linux-sound.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/27] ALSA: Reorganize HD-audio driver code
@ 2025-07-09 16:04 Takashi Iwai
  2025-07-09 16:04 ` [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h Takashi Iwai
                   ` (27 more replies)
  0 siblings, 28 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

HD-audio driver is known to be quite messy in both file structures and
its design, but until now I haven't touched its files paths so much
because I set a higher priority for the easiness of backport to stable
kernels.  But, you can't leave garbages forever, it's been already
high time for a large clean up -- so here it is.

The basic idea is to move the code from sound/pci/hda/* into different
subdirectories in sound/hda/ per functionality, as most of the stuff
are independent from PCI, but rather HD-audio bus specific.

So, now the all HD-audio driver code are moved under sound/hda:

  % ls sound/hda 
  codecs/  common/  controllers/  core/  Kconfig  Makefile

* The former hda core code is found in sound/hda/core.
* The former snd-hda-codec code is found in sound/hda/common.
* The former snd-hda-intel, tegra and acpi are put in
  sound/hda/controllers.
* The former patch_* and co are put to sound/hda/codecs.
* Realtek codec driver is split to several modules as
  sound/hda/codecs/realtek/alc*.
* Cirrus codec driver is split to cs420x and cs421x, put under
  sound/hda/codecs/cirrus together with cs8409.
* HDMI codec driver is split to several modules under
  sound/hda/codecs/hdmi
* Cirrus and TI sub-codecs are put under sound/hda/codecs/side-codecs

Also, the probe of the HD-audio codec driver is moved into the
driver's ops instead of the ugly patch_ops embedded in hda_codec
object. (As of now, hda_codec_driver.ops is a pointer, but it can be
embedded later, too.)

This change required some code to be modified without the dynamic
override of callbacks.

In future, we may convert the runtime PM handling to use the standard
pm_ops, too.  This was raised some time ago during the discussion with
Realtek devs.

The tree applying those patches is found in topic/hda-reorg branch of
sound git tree:
  https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/log/?h=topic/hda-reorg


Takashi

===

Takashi Iwai (27):
  ALSA: hda: Move widget capability macros into hdaudio.h
  ALSA: hda: Move HD-audio core stuff into sound/hda/core
  ALSA: hda: Move common codec driver into sound/hda/common directory
  ALSA: hda: Move CONFIG_SND_HDA_PREALLOC_SIZE into sound/hda/common
  ALSA: hda: Move controller drivers into sound/hda/controllers
    directory
  ALSA: hda: Move codec drivers into sound/hda/codecs directory
  ALSA: hda: Split Realtek HD-audio codec driver
  ALSA: hda/hdmi: Split vendor codec drivers
  ALSA: hda: Introduce hda_codec_driver ops
  ALSA: hda/generic: Rewrite to new probe method
  ALSA: hda/realtek: Rewrite to new probe method
  ALSA: hda/cmedia: Rewrite to new probe method
  ALSA: hda/analog: Rewrite to new probe method
  ALSA: hda/ca0110: Rewrite to new probe method
  ALSA: hda/cirrus: Split to cs420x and cs421x drivers
  ALSA: hda/cs8409: Rewrite to new probe method
  ALSA: hda/conexant: Rewrite to new probe method
  ALSA: hda/senary: Rewrite to new probe method
  ALSA: hda/si3054: Rewrite to new probe method
  ALSA: hda/via: Rewrite to new probe method
  ALSA: hda/sigmatel: Rewrite to new probe method
  ALSA: hda/ca0132: Rewrite to new probe method
  ALSA: hda/hdmi: Rewrite to new probe method
  ALSA: hda: Drop old codec binding method
  ALSA: hda: Drop superfluous driver->ops NULL checks
  MAINTAINERS: Adjust to the new HD-audio driver paths
  ALSA: hda: Return the codec init error properly at
    snd_hda_codec_build_controls()

 MAINTAINERS                                   |   10 +-
 include/sound/hda_codec.h                     |   40 +-
 include/sound/hdaudio.h                       |   24 +
 sound/hda/Kconfig                             |   70 +-
 sound/hda/Makefile                            |   28 +-
 sound/hda/codecs/Kconfig                      |  137 +
 sound/hda/codecs/Makefile                     |   34 +
 .../patch_analog.c => hda/codecs/analog.c}    |  223 +-
 .../patch_ca0110.c => hda/codecs/ca0110.c}    |   37 +-
 .../patch_ca0132.c => hda/codecs/ca0132.c}    |  105 +-
 sound/{pci/hda => hda/codecs}/ca0132_regs.h   |    2 +-
 sound/hda/codecs/cirrus/Kconfig               |   31 +
 sound/hda/codecs/cirrus/Makefile              |   10 +
 .../codecs/cirrus/cs420x.c}                   |  528 +-
 sound/hda/codecs/cirrus/cs421x.c              |  590 ++
 .../codecs/cirrus/cs8409-tables.c}            |    4 +-
 .../codecs/cirrus/cs8409.c}                   |   57 +-
 .../codecs/cirrus/cs8409.h}                   |    6 +-
 .../patch_cmedia.c => hda/codecs/cm9825.c}    |  140 +-
 sound/hda/codecs/cmedia.c                     |  106 +
 .../codecs/conexant.c}                        |  110 +-
 .../hda_generic.c => hda/codecs/generic.c}    |   57 +-
 .../hda_generic.h => hda/codecs/generic.h}    |    2 +-
 sound/hda/codecs/hdmi/Kconfig                 |   68 +
 sound/hda/codecs/hdmi/Makefile                |   18 +
 sound/hda/codecs/hdmi/atihdmi.c               |  615 ++
 .../hda/hda_eld.c => hda/codecs/hdmi/eld.c}   |  172 -
 sound/hda/codecs/hdmi/hdmi.c                  | 2416 +++++++
 sound/hda/codecs/hdmi/hdmi_local.h            |  302 +
 sound/hda/codecs/hdmi/intelhdmi.c             |  811 +++
 sound/hda/codecs/hdmi/nvhdmi-mcp.c            |  384 ++
 sound/hda/codecs/hdmi/nvhdmi.c                |  223 +
 sound/hda/codecs/hdmi/simplehdmi.c            |  251 +
 sound/hda/codecs/hdmi/tegrahdmi.c             |  316 +
 .../codecs/helpers/hp_x360.c}                 |    0
 .../codecs/helpers/ideapad_hotkey_led.c}      |    0
 .../codecs/helpers/ideapad_s740.c}            |    0
 .../codecs/helpers/thinkpad.c}                |    0
 sound/hda/codecs/realtek/Kconfig              |   90 +
 sound/hda/codecs/realtek/Makefile             |   26 +
 sound/hda/codecs/realtek/alc260.c             |  290 +
 sound/hda/codecs/realtek/alc262.c             |  213 +
 sound/hda/codecs/realtek/alc268.c             |  190 +
 .../codecs/realtek/alc269.c}                  | 5828 +----------------
 sound/hda/codecs/realtek/alc662.c             | 1116 ++++
 sound/hda/codecs/realtek/alc680.c             |   67 +
 sound/hda/codecs/realtek/alc861.c             |  163 +
 sound/hda/codecs/realtek/alc861vd.c           |  137 +
 sound/hda/codecs/realtek/alc880.c             |  509 ++
 sound/hda/codecs/realtek/alc882.c             |  861 +++
 sound/hda/codecs/realtek/realtek.c            | 2299 +++++++
 sound/hda/codecs/realtek/realtek.h            |  298 +
 .../codecs/senarytech.c}                      |   50 +-
 .../patch_si3054.c => hda/codecs/si3054.c}    |   53 +-
 sound/hda/codecs/side-codecs/Kconfig          |  128 +
 sound/hda/codecs/side-codecs/Makefile         |   28 +
 .../codecs/side-codecs}/cirrus_scodec.c       |    0
 .../codecs/side-codecs}/cirrus_scodec.h       |    0
 .../codecs/side-codecs}/cirrus_scodec_test.c  |    0
 .../codecs/side-codecs}/cs35l41_hda.c         |    2 +-
 .../codecs/side-codecs}/cs35l41_hda.h         |    0
 .../codecs/side-codecs}/cs35l41_hda_i2c.c     |    0
 .../side-codecs}/cs35l41_hda_property.c       |    0
 .../side-codecs}/cs35l41_hda_property.h       |    0
 .../codecs/side-codecs}/cs35l41_hda_spi.c     |    0
 .../codecs/side-codecs}/cs35l56_hda.c         |    2 +-
 .../codecs/side-codecs}/cs35l56_hda.h         |    0
 .../codecs/side-codecs}/cs35l56_hda_i2c.c     |    0
 .../codecs/side-codecs}/cs35l56_hda_spi.c     |    0
 .../codecs/side-codecs}/hda_component.c       |    0
 .../codecs/side-codecs}/hda_component.h       |    0
 .../codecs/side-codecs}/tas2781_hda.c         |    0
 .../codecs/side-codecs}/tas2781_hda.h         |    0
 .../codecs/side-codecs}/tas2781_hda_i2c.c     |    2 +-
 .../codecs/side-codecs}/tas2781_hda_spi.c     |    2 +-
 .../codecs/sigmatel.c}                        |  402 +-
 .../{pci/hda/patch_via.c => hda/codecs/via.c} |  447 +-
 sound/hda/common/Kconfig                      |   97 +
 sound/hda/common/Makefile                     |   13 +
 .../common/auto_parser.c}                     |    0
 .../{pci/hda/hda_beep.c => hda/common/beep.c} |    0
 .../{pci/hda/hda_bind.c => hda/common/bind.c} |   29 +-
 .../hda/hda_codec.c => hda/common/codec.c}    |   57 +-
 .../common/controller.c}                      |    2 +-
 .../common/controller_trace.h}                |    2 +-
 .../{pci/hda => hda/common}/hda_auto_parser.h |    0
 sound/{pci/hda => hda/common}/hda_beep.h      |    0
 .../{pci/hda => hda/common}/hda_controller.h  |    0
 sound/{pci/hda => hda/common}/hda_jack.h      |    0
 sound/{pci/hda => hda/common}/hda_local.h     |   13 +-
 .../hda/hda_hwdep.c => hda/common/hwdep.c}    |    0
 .../{pci/hda/hda_jack.c => hda/common/jack.c} |    0
 .../{pci/hda/hda_proc.c => hda/common/proc.c} |    0
 .../hda/hda_sysfs.c => hda/common/sysfs.c}    |    0
 sound/hda/controllers/Kconfig                 |   42 +
 sound/hda/controllers/Makefile                |   13 +
 .../hda/hda_acpi.c => hda/controllers/acpi.c} |    0
 .../hda_intel.c => hda/controllers/intel.c}   |    5 +-
 .../hda_intel.h => hda/controllers/intel.h}   |    0
 .../controllers/intel_trace.h}                |    2 +-
 .../hda_tegra.c => hda/controllers/tegra.c}   |    0
 sound/hda/core/Kconfig                        |   51 +
 sound/hda/core/Makefile                       |   22 +
 sound/hda/{ => core}/array.c                  |    0
 sound/hda/{hdac_bus.c => core/bus.c}          |    0
 .../{hdac_component.c => core/component.c}    |    0
 .../{hdac_controller.c => core/controller.c}  |    0
 sound/hda/{hdac_device.c => core/device.c}    |    8 +-
 sound/hda/{ => core}/ext/Makefile             |    2 +-
 .../{ext/hdac_ext_bus.c => core/ext/bus.c}    |    0
 .../ext/controller.c}                         |    0
 .../hdac_ext_stream.c => core/ext/stream.c}   |    0
 sound/hda/{ => core}/hda_bus_type.c           |    0
 sound/hda/{ => core}/hdmi_chmap.c             |    0
 sound/hda/{hdac_i915.c => core/i915.c}        |    0
 sound/hda/{ => core}/intel-dsp-config.c       |    0
 sound/hda/{ => core}/intel-nhlt.c             |    0
 sound/hda/{ => core}/intel-sdw-acpi.c         |    0
 sound/hda/{ => core}/local.h                  |   21 -
 sound/hda/{hdac_regmap.c => core/regmap.c}    |    0
 sound/hda/{hdac_stream.c => core/stream.c}    |    0
 sound/hda/{hdac_sysfs.c => core/sysfs.c}      |   14 +-
 sound/hda/{ => core}/trace.c                  |    0
 sound/hda/{ => core}/trace.h                  |    0
 sound/pci/Kconfig                             |    2 -
 sound/pci/Makefile                            |    1 -
 sound/pci/hda/Kconfig                         |  436 --
 sound/pci/hda/Makefile                        |   84 -
 sound/pci/hda/patch_hdmi.c                    | 4695 -------------
 sound/soc/codecs/hda.c                        |   17 +-
 sound/soc/codecs/hdac_hda.c                   |   29 +-
 sound/soc/codecs/hdac_hdmi.c                  |   21 +-
 132 files changed, 14057 insertions(+), 12751 deletions(-)
 create mode 100644 sound/hda/codecs/Kconfig
 create mode 100644 sound/hda/codecs/Makefile
 rename sound/{pci/hda/patch_analog.c => hda/codecs/analog.c} (90%)
 rename sound/{pci/hda/patch_ca0110.c => hda/codecs/ca0110.c} (75%)
 rename sound/{pci/hda/patch_ca0132.c => hda/codecs/ca0132.c} (99%)
 rename sound/{pci/hda => hda/codecs}/ca0132_regs.h (99%)
 create mode 100644 sound/hda/codecs/cirrus/Kconfig
 create mode 100644 sound/hda/codecs/cirrus/Makefile
 rename sound/{pci/hda/patch_cirrus.c => hda/codecs/cirrus/cs420x.c} (61%)
 create mode 100644 sound/hda/codecs/cirrus/cs421x.c
 rename sound/{pci/hda/patch_cs8409-tables.c => hda/codecs/cirrus/cs8409-tables.c} (99%)
 rename sound/{pci/hda/patch_cs8409.c => hda/codecs/cirrus/cs8409.c} (98%)
 rename sound/{pci/hda/patch_cs8409.h => hda/codecs/cirrus/cs8409.h} (98%)
 rename sound/{pci/hda/patch_cmedia.c => hda/codecs/cm9825.c} (73%)
 create mode 100644 sound/hda/codecs/cmedia.c
 rename sound/{pci/hda/patch_conexant.c => hda/codecs/conexant.c} (93%)
 rename sound/{pci/hda/hda_generic.c => hda/codecs/generic.c} (99%)
 rename sound/{pci/hda/hda_generic.h => hda/codecs/generic.h} (99%)
 create mode 100644 sound/hda/codecs/hdmi/Kconfig
 create mode 100644 sound/hda/codecs/hdmi/Makefile
 create mode 100644 sound/hda/codecs/hdmi/atihdmi.c
 rename sound/{pci/hda/hda_eld.c => hda/codecs/hdmi/eld.c} (51%)
 create mode 100644 sound/hda/codecs/hdmi/hdmi.c
 create mode 100644 sound/hda/codecs/hdmi/hdmi_local.h
 create mode 100644 sound/hda/codecs/hdmi/intelhdmi.c
 create mode 100644 sound/hda/codecs/hdmi/nvhdmi-mcp.c
 create mode 100644 sound/hda/codecs/hdmi/nvhdmi.c
 create mode 100644 sound/hda/codecs/hdmi/simplehdmi.c
 create mode 100644 sound/hda/codecs/hdmi/tegrahdmi.c
 rename sound/{pci/hda/hp_x360_helper.c => hda/codecs/helpers/hp_x360.c} (100%)
 rename sound/{pci/hda/ideapad_hotkey_led_helper.c => hda/codecs/helpers/ideapad_hotkey_led.c} (100%)
 rename sound/{pci/hda/ideapad_s740_helper.c => hda/codecs/helpers/ideapad_s740.c} (100%)
 rename sound/{pci/hda/thinkpad_helper.c => hda/codecs/helpers/thinkpad.c} (100%)
 create mode 100644 sound/hda/codecs/realtek/Kconfig
 create mode 100644 sound/hda/codecs/realtek/Makefile
 create mode 100644 sound/hda/codecs/realtek/alc260.c
 create mode 100644 sound/hda/codecs/realtek/alc262.c
 create mode 100644 sound/hda/codecs/realtek/alc268.c
 rename sound/{pci/hda/patch_realtek.c => hda/codecs/realtek/alc269.c} (63%)
 create mode 100644 sound/hda/codecs/realtek/alc662.c
 create mode 100644 sound/hda/codecs/realtek/alc680.c
 create mode 100644 sound/hda/codecs/realtek/alc861.c
 create mode 100644 sound/hda/codecs/realtek/alc861vd.c
 create mode 100644 sound/hda/codecs/realtek/alc880.c
 create mode 100644 sound/hda/codecs/realtek/alc882.c
 create mode 100644 sound/hda/codecs/realtek/realtek.c
 create mode 100644 sound/hda/codecs/realtek/realtek.h
 rename sound/{pci/hda/patch_senarytech.c => hda/codecs/senarytech.c} (87%)
 rename sound/{pci/hda/patch_si3054.c => hda/codecs/si3054.c} (88%)
 create mode 100644 sound/hda/codecs/side-codecs/Kconfig
 create mode 100644 sound/hda/codecs/side-codecs/Makefile
 rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec_test.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.c (99%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_i2c.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_spi.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.c (99%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_i2c.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_spi.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_i2c.c (99%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_spi.c (99%)
 rename sound/{pci/hda/patch_sigmatel.c => hda/codecs/sigmatel.c} (94%)
 rename sound/{pci/hda/patch_via.c => hda/codecs/via.c} (78%)
 create mode 100644 sound/hda/common/Kconfig
 create mode 100644 sound/hda/common/Makefile
 rename sound/{pci/hda/hda_auto_parser.c => hda/common/auto_parser.c} (100%)
 rename sound/{pci/hda/hda_beep.c => hda/common/beep.c} (100%)
 rename sound/{pci/hda/hda_bind.c => hda/common/bind.c} (93%)
 rename sound/{pci/hda/hda_codec.c => hda/common/codec.c} (98%)
 rename sound/{pci/hda/hda_controller.c => hda/common/controller.c} (99%)
 rename sound/{pci/hda/hda_controller_trace.h => hda/common/controller_trace.h} (97%)
 rename sound/{pci/hda => hda/common}/hda_auto_parser.h (100%)
 rename sound/{pci/hda => hda/common}/hda_beep.h (100%)
 rename sound/{pci/hda => hda/common}/hda_controller.h (100%)
 rename sound/{pci/hda => hda/common}/hda_jack.h (100%)
 rename sound/{pci/hda => hda/common}/hda_local.h (99%)
 rename sound/{pci/hda/hda_hwdep.c => hda/common/hwdep.c} (100%)
 rename sound/{pci/hda/hda_jack.c => hda/common/jack.c} (100%)
 rename sound/{pci/hda/hda_proc.c => hda/common/proc.c} (100%)
 rename sound/{pci/hda/hda_sysfs.c => hda/common/sysfs.c} (100%)
 create mode 100644 sound/hda/controllers/Kconfig
 create mode 100644 sound/hda/controllers/Makefile
 rename sound/{pci/hda/hda_acpi.c => hda/controllers/acpi.c} (100%)
 rename sound/{pci/hda/hda_intel.c => hda/controllers/intel.c} (99%)
 rename sound/{pci/hda/hda_intel.h => hda/controllers/intel.h} (100%)
 rename sound/{pci/hda/hda_intel_trace.h => hda/controllers/intel_trace.h} (95%)
 rename sound/{pci/hda/hda_tegra.c => hda/controllers/tegra.c} (100%)
 create mode 100644 sound/hda/core/Kconfig
 create mode 100644 sound/hda/core/Makefile
 rename sound/hda/{ => core}/array.c (100%)
 rename sound/hda/{hdac_bus.c => core/bus.c} (100%)
 rename sound/hda/{hdac_component.c => core/component.c} (100%)
 rename sound/hda/{hdac_controller.c => core/controller.c} (100%)
 rename sound/hda/{hdac_device.c => core/device.c} (99%)
 rename sound/hda/{ => core}/ext/Makefile (54%)
 rename sound/hda/{ext/hdac_ext_bus.c => core/ext/bus.c} (100%)
 rename sound/hda/{ext/hdac_ext_controller.c => core/ext/controller.c} (100%)
 rename sound/hda/{ext/hdac_ext_stream.c => core/ext/stream.c} (100%)
 rename sound/hda/{ => core}/hda_bus_type.c (100%)
 rename sound/hda/{ => core}/hdmi_chmap.c (100%)
 rename sound/hda/{hdac_i915.c => core/i915.c} (100%)
 rename sound/hda/{ => core}/intel-dsp-config.c (100%)
 rename sound/hda/{ => core}/intel-nhlt.c (100%)
 rename sound/hda/{ => core}/intel-sdw-acpi.c (100%)
 rename sound/hda/{ => core}/local.h (66%)
 rename sound/hda/{hdac_regmap.c => core/regmap.c} (100%)
 rename sound/hda/{hdac_stream.c => core/stream.c} (100%)
 rename sound/hda/{hdac_sysfs.c => core/sysfs.c} (95%)
 rename sound/hda/{ => core}/trace.c (100%)
 rename sound/hda/{ => core}/trace.h (100%)
 delete mode 100644 sound/pci/hda/Kconfig
 delete mode 100644 sound/pci/hda/Makefile
 delete mode 100644 sound/pci/hda/patch_hdmi.c

-- 
2.50.0


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-14  8:40   ` Cezary Rojewski
  2025-07-09 16:04 ` [PATCH 02/27] ALSA: hda: Move HD-audio core stuff into sound/hda/core Takashi Iwai
                   ` (26 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

The get_wcaps() and co are used not only by HD-audio core but also
other driver code, hence it'd be better to put into the common header
instead of local.h.

OTOH, there are macros of the same name like get_wcaps() that are
still used in sound/pci/hda/* locally, and those conflict with each
other.  So we need to rename get_wcaps() (to be moved from hda-core)
with the proper snd_hdac prefix for avoiding name conflicts, and
define in the common hdaudio.h.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/hdaudio.h      | 24 ++++++++++++++++++++++++
 sound/hda/hdac_device.c      |  8 ++++----
 sound/hda/hdac_sysfs.c       | 14 +++++++-------
 sound/hda/local.h            | 21 ---------------------
 sound/soc/codecs/hdac_hdmi.c | 21 ++++++++++-----------
 5 files changed, 45 insertions(+), 43 deletions(-)

diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 25668eee65cf..d38234f8fe44 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -680,6 +680,30 @@ static inline void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
 }
 #endif /* CONFIG_SND_HDA_DSP_LOADER */
 
+/*
+ * Easy macros for widget capabilities
+ */
+#define snd_hdac_get_wcaps(codec, nid) \
+	snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
+
+/* get the widget type from widget capability bits */
+static inline int snd_hdac_get_wcaps_type(unsigned int wcaps)
+{
+	if (!wcaps)
+		return -1; /* invalid type */
+	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+}
+
+/* get the number of supported channels */
+static inline unsigned int snd_hdac_get_wcaps_channels(u32 wcaps)
+{
+	unsigned int chans;
+
+	chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
+	chans = (chans + 1) * 2;
+
+	return chans;
+}
 
 /*
  * generic array helpers
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index a02dce5f6a88..018f9e176b1b 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -436,11 +436,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
 /* return CONNLIST_LEN parameter of the given widget */
 static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid)
 {
-	unsigned int wcaps = get_wcaps(codec, nid);
+	unsigned int wcaps = snd_hdac_get_wcaps(codec, nid);
 	unsigned int parm;
 
 	if (!(wcaps & AC_WCAP_CONN_LIST) &&
-	    get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+	    snd_hdac_get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
 		return 0;
 
 	parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN);
@@ -854,7 +854,7 @@ static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid)
 	unsigned int val = 0;
 
 	if (nid != codec->afg &&
-	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+	    (snd_hdac_get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
 		val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM);
 	if (!val || val == -1)
 		val = snd_hdac_read_parm(codec, codec->afg, AC_PAR_PCM);
@@ -894,7 +894,7 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
 {
 	unsigned int i, val, wcaps;
 
-	wcaps = get_wcaps(codec, nid);
+	wcaps = snd_hdac_get_wcaps(codec, nid);
 	val = query_pcm_param(codec, nid);
 
 	if (ratesp) {
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c
index 60b0a70428d5..bffe52859dba 100644
--- a/sound/hda/hdac_sysfs.c
+++ b/sound/hda/hdac_sysfs.c
@@ -161,13 +161,13 @@ static const struct kobj_type widget_ktype = {
 static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid,
 			struct widget_attribute *attr, char *buf)
 {
-	return sysfs_emit(buf, "0x%08x\n", get_wcaps(codec, nid));
+	return sysfs_emit(buf, "0x%08x\n", snd_hdac_get_wcaps(codec, nid));
 }
 
 static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
 			     struct widget_attribute *attr, char *buf)
 {
-	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+	if (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid)) != AC_WID_PIN)
 		return 0;
 	return sysfs_emit(buf, "0x%08x\n",
 			  snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
@@ -178,7 +178,7 @@ static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
 {
 	unsigned int val;
 
-	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+	if (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid)) != AC_WID_PIN)
 		return 0;
 	if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
 		return 0;
@@ -189,7 +189,7 @@ static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid)
 {
 	if (nid == codec->afg || nid == codec->mfg)
 		return true;
-	switch (get_wcaps_type(get_wcaps(codec, nid))) {
+	switch (snd_hdac_get_wcaps_type(snd_hdac_get_wcaps(codec, nid))) {
 	case AC_WID_AUD_OUT:
 	case AC_WID_AUD_IN:
 		return true;
@@ -219,7 +219,7 @@ static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
 static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
 				struct widget_attribute *attr, char *buf)
 {
-	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+	if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
 		return 0;
 	return sysfs_emit(buf, "0x%08x\n",
 			  snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
@@ -228,7 +228,7 @@ static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
 static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
 				 struct widget_attribute *attr, char *buf)
 {
-	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+	if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
 		return 0;
 	return sysfs_emit(buf, "0x%08x\n",
 			  snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
@@ -237,7 +237,7 @@ static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
 static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
 			       struct widget_attribute *attr, char *buf)
 {
-	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER))
+	if (nid != codec->afg && !(snd_hdac_get_wcaps(codec, nid) & AC_WCAP_POWER))
 		return 0;
 	return sysfs_emit(buf, "0x%08x\n",
 			  snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
diff --git a/sound/hda/local.h b/sound/hda/local.h
index 896ba142e8bc..5f03b203c416 100644
--- a/sound/hda/local.h
+++ b/sound/hda/local.h
@@ -6,27 +6,6 @@
 #ifndef __HDAC_LOCAL_H
 #define __HDAC_LOCAL_H
 
-#define get_wcaps(codec, nid) \
-	snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
-
-/* get the widget type from widget capability bits */
-static inline int get_wcaps_type(unsigned int wcaps)
-{
-	if (!wcaps)
-		return -1; /* invalid type */
-	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-}
-
-static inline unsigned int get_wcaps_channels(u32 wcaps)
-{
-	unsigned int chans;
-
-	chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
-	chans = (chans + 1) * 2;
-
-	return chans;
-}
-
 extern const struct attribute_group *hdac_dev_attr_groups[];
 int hda_widget_sysfs_init(struct hdac_device *codec);
 int hda_widget_sysfs_reinit(struct hdac_device *codec, hda_nid_t start_nid,
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 1139a2754ca3..b33cd5178008 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -24,7 +24,6 @@
 #include <sound/hda_i915.h>
 #include <sound/pcm_drm_eld.h>
 #include <sound/hda_chmap.h>
-#include "../../hda/local.h"
 #include "hdac_hdmi.h"
 
 #define NAME_SIZE	32
@@ -221,8 +220,8 @@ static int hdac_hdmi_get_port_len(struct hdac_device *hdev, hda_nid_t nid)
 	unsigned int caps;
 	unsigned int type, param;
 
-	caps = get_wcaps(hdev, nid);
-	type = get_wcaps_type(caps);
+	caps = snd_hdac_get_wcaps(hdev, nid);
+	type = snd_hdac_get_wcaps_type(caps);
 
 	if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
 		return 0;
@@ -492,10 +491,10 @@ static int hdac_hdmi_query_port_connlist(struct hdac_device *hdev,
 					struct hdac_hdmi_pin *pin,
 					struct hdac_hdmi_port *port)
 {
-	if (!(get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
+	if (!(snd_hdac_get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
 		dev_warn(&hdev->dev,
 			"HDMI: pin %d wcaps %#x does not support connection list\n",
-			pin->nid, get_wcaps(hdev, pin->nid));
+			pin->nid, snd_hdac_get_wcaps(hdev, pin->nid));
 		return -EINVAL;
 	}
 
@@ -660,8 +659,8 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
 	int err;
 
-	chans = get_wcaps(hdev, cvt->nid);
-	chans = get_wcaps_channels(chans);
+	chans = snd_hdac_get_wcaps(hdev, cvt->nid);
+	chans = snd_hdac_get_wcaps_channels(chans);
 
 	cvt->params.channels_min = 2;
 
@@ -743,7 +742,7 @@ static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
 	int count;
 	unsigned int state;
 
-	if (get_wcaps(hdev, nid) & AC_WCAP_POWER) {
+	if (snd_hdac_get_wcaps(hdev, nid) & AC_WCAP_POWER) {
 		if (!snd_hdac_check_power_state(hdev, nid, pwr_state)) {
 			for (count = 0; count < 10; count++) {
 				snd_hdac_codec_read(hdev, nid, 0,
@@ -761,7 +760,7 @@ static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
 static void hdac_hdmi_set_amp(struct hdac_device *hdev,
 				   hda_nid_t nid, int val)
 {
-	if (get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
+	if (snd_hdac_get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
 		snd_hdac_codec_write(hdev, nid, 0,
 					AC_VERB_SET_AMP_GAIN_MUTE, val);
 }
@@ -1648,8 +1647,8 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
 		unsigned int caps;
 		unsigned int type;
 
-		caps = get_wcaps(hdev, nid);
-		type = get_wcaps_type(caps);
+		caps = snd_hdac_get_wcaps(hdev, nid);
+		type = snd_hdac_get_wcaps_type(caps);
 
 		if (!(caps & AC_WCAP_DIGITAL))
 			continue;
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 02/27] ALSA: hda: Move HD-audio core stuff into sound/hda/core
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
  2025-07-09 16:04 ` [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-14  8:41   ` Cezary Rojewski
  2025-07-09 16:04 ` [PATCH 03/27] ALSA: hda: Move common codec driver into sound/hda/common directory Takashi Iwai
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

This is a part of HD-audio code restructuring.
Simply move the current code of sound/hda/* into the subdirectory
sound/hda/core, so that more stuff can be moved into sound/hda cleanly
later.

Most of file names with hdac_ and hdac_ext_ prefix are renamed without
the prefix, since they can be identified well in the directory name
and superfluous.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/Kconfig                             | 67 +------------------
 sound/hda/Makefile                            | 22 +-----
 sound/hda/core/Kconfig                        | 67 +++++++++++++++++++
 sound/hda/core/Makefile                       | 22 ++++++
 sound/hda/{ => core}/array.c                  |  0
 sound/hda/{hdac_bus.c => core/bus.c}          |  0
 .../{hdac_component.c => core/component.c}    |  0
 .../{hdac_controller.c => core/controller.c}  |  0
 sound/hda/{hdac_device.c => core/device.c}    |  0
 sound/hda/{ => core}/ext/Makefile             |  2 +-
 .../{ext/hdac_ext_bus.c => core/ext/bus.c}    |  0
 .../ext/controller.c}                         |  0
 .../hdac_ext_stream.c => core/ext/stream.c}   |  0
 sound/hda/{ => core}/hda_bus_type.c           |  0
 sound/hda/{ => core}/hdmi_chmap.c             |  0
 sound/hda/{hdac_i915.c => core/i915.c}        |  0
 sound/hda/{ => core}/intel-dsp-config.c       |  0
 sound/hda/{ => core}/intel-nhlt.c             |  0
 sound/hda/{ => core}/intel-sdw-acpi.c         |  0
 sound/hda/{ => core}/local.h                  |  0
 sound/hda/{hdac_regmap.c => core/regmap.c}    |  0
 sound/hda/{hdac_stream.c => core/stream.c}    |  0
 sound/hda/{hdac_sysfs.c => core/sysfs.c}      |  0
 sound/hda/{ => core}/trace.c                  |  0
 sound/hda/{ => core}/trace.h                  |  0
 25 files changed, 92 insertions(+), 88 deletions(-)
 create mode 100644 sound/hda/core/Kconfig
 create mode 100644 sound/hda/core/Makefile
 rename sound/hda/{ => core}/array.c (100%)
 rename sound/hda/{hdac_bus.c => core/bus.c} (100%)
 rename sound/hda/{hdac_component.c => core/component.c} (100%)
 rename sound/hda/{hdac_controller.c => core/controller.c} (100%)
 rename sound/hda/{hdac_device.c => core/device.c} (100%)
 rename sound/hda/{ => core}/ext/Makefile (54%)
 rename sound/hda/{ext/hdac_ext_bus.c => core/ext/bus.c} (100%)
 rename sound/hda/{ext/hdac_ext_controller.c => core/ext/controller.c} (100%)
 rename sound/hda/{ext/hdac_ext_stream.c => core/ext/stream.c} (100%)
 rename sound/hda/{ => core}/hda_bus_type.c (100%)
 rename sound/hda/{ => core}/hdmi_chmap.c (100%)
 rename sound/hda/{hdac_i915.c => core/i915.c} (100%)
 rename sound/hda/{ => core}/intel-dsp-config.c (100%)
 rename sound/hda/{ => core}/intel-nhlt.c (100%)
 rename sound/hda/{ => core}/intel-sdw-acpi.c (100%)
 rename sound/hda/{ => core}/local.h (100%)
 rename sound/hda/{hdac_regmap.c => core/regmap.c} (100%)
 rename sound/hda/{hdac_stream.c => core/stream.c} (100%)
 rename sound/hda/{hdac_sysfs.c => core/sysfs.c} (100%)
 rename sound/hda/{ => core}/trace.c (100%)
 rename sound/hda/{ => core}/trace.h (100%)

diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index eb488a522572..e38014656077 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -1,67 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0-only
-config SND_HDA_CORE
-	tristate
-	select REGMAP
-
-config SND_HDA_DSP_LOADER
-	bool
-
-config SND_HDA_ALIGNED_MMIO
-	bool
-
-config SND_HDA_COMPONENT
-	bool
-
-config SND_HDA_I915
-	bool
-	select SND_HDA_COMPONENT
-
-config SND_HDA_EXT_CORE
-       tristate
-       select SND_HDA_CORE
-
-config SND_HDA_PREALLOC_SIZE
-	int "Pre-allocated buffer size for HD-audio driver"
-	range 0 32768
-	default 0 if SND_DMA_SGBUF
-	default 64 if !SND_DMA_SGBUF
-	help
-	  Specifies the default pre-allocated buffer-size in kB for the
-	  HD-audio driver.  A larger buffer (e.g. 2048) is preferred
-	  for systems using PulseAudio.  The default 64 is chosen just
-	  for compatibility reasons.
-	  On x86 systems, the default is zero as S/G allocation works
-	  and no preallocation is needed in most cases.
-
-	  Note that the pre-allocation size can be changed dynamically
-	  via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
-
-config SND_INTEL_NHLT
-	bool
-	# this config should be selected only for Intel ACPI platforms.
-	# A fallback is provided so that the code compiles in all cases.
-
-config SND_INTEL_DSP_CONFIG
-	tristate
-	select ACPI_NHLT if ACPI
-	select SND_INTEL_NHLT if ACPI
-	select SND_INTEL_SOUNDWIRE_ACPI if ACPI
-	# this config should be selected only for Intel DSP platforms.
-	# A fallback is provided so that the code compiles in all cases.
-
-config SND_INTEL_SOUNDWIRE_ACPI
-	tristate
-
-config SND_INTEL_BYT_PREFER_SOF
-	bool "Prefer SOF driver over SST on BY/CHT platforms"
-	depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL
-	default n
-	help
-	  The kernel has 2 drivers for the Low Power Engine audio-block on
-	  Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF
-	  driver. If both drivers are enabled then the kernel will default
-	  to using the old SST driver, unless told otherwise through the
-	  snd_intel_dspcfg.dsp_driver module-parameter.
-
-	  Set this option to Y to make the kernel default to the new SOF
-	  driver instead.
+source "sound/hda/core/Kconfig"
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index 83cceafe0d4c..3fdbc22b1530 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,22 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0
-snd-hda-core-y := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
-	hdac_regmap.o hdac_controller.o hdac_stream.o array.o hdmi_chmap.o
-
-snd-hda-core-y += trace.o
-CFLAGS_trace.o := -I$(src)
-
-# for sync with i915 gfx driver
-snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o
-snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o
-
-obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
-
-#extended hda
-obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
-
-snd-intel-dspcfg-y := intel-dsp-config.o
-snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o
-obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o
-
-snd-intel-sdw-acpi-y := intel-sdw-acpi.o
-obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o
+obj-y += core/
diff --git a/sound/hda/core/Kconfig b/sound/hda/core/Kconfig
new file mode 100644
index 000000000000..eb488a522572
--- /dev/null
+++ b/sound/hda/core/Kconfig
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_HDA_CORE
+	tristate
+	select REGMAP
+
+config SND_HDA_DSP_LOADER
+	bool
+
+config SND_HDA_ALIGNED_MMIO
+	bool
+
+config SND_HDA_COMPONENT
+	bool
+
+config SND_HDA_I915
+	bool
+	select SND_HDA_COMPONENT
+
+config SND_HDA_EXT_CORE
+       tristate
+       select SND_HDA_CORE
+
+config SND_HDA_PREALLOC_SIZE
+	int "Pre-allocated buffer size for HD-audio driver"
+	range 0 32768
+	default 0 if SND_DMA_SGBUF
+	default 64 if !SND_DMA_SGBUF
+	help
+	  Specifies the default pre-allocated buffer-size in kB for the
+	  HD-audio driver.  A larger buffer (e.g. 2048) is preferred
+	  for systems using PulseAudio.  The default 64 is chosen just
+	  for compatibility reasons.
+	  On x86 systems, the default is zero as S/G allocation works
+	  and no preallocation is needed in most cases.
+
+	  Note that the pre-allocation size can be changed dynamically
+	  via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
+
+config SND_INTEL_NHLT
+	bool
+	# this config should be selected only for Intel ACPI platforms.
+	# A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_DSP_CONFIG
+	tristate
+	select ACPI_NHLT if ACPI
+	select SND_INTEL_NHLT if ACPI
+	select SND_INTEL_SOUNDWIRE_ACPI if ACPI
+	# this config should be selected only for Intel DSP platforms.
+	# A fallback is provided so that the code compiles in all cases.
+
+config SND_INTEL_SOUNDWIRE_ACPI
+	tristate
+
+config SND_INTEL_BYT_PREFER_SOF
+	bool "Prefer SOF driver over SST on BY/CHT platforms"
+	depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL
+	default n
+	help
+	  The kernel has 2 drivers for the Low Power Engine audio-block on
+	  Bay- and Cherry-Trail SoCs. The old SST driver and the new SOF
+	  driver. If both drivers are enabled then the kernel will default
+	  to using the old SST driver, unless told otherwise through the
+	  snd_intel_dspcfg.dsp_driver module-parameter.
+
+	  Set this option to Y to make the kernel default to the new SOF
+	  driver instead.
diff --git a/sound/hda/core/Makefile b/sound/hda/core/Makefile
new file mode 100644
index 000000000000..89cb46143050
--- /dev/null
+++ b/sound/hda/core/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-hda-core-y := hda_bus_type.o bus.o device.o sysfs.o \
+	regmap.o controller.o stream.o array.o hdmi_chmap.o
+
+snd-hda-core-y += trace.o
+CFLAGS_trace.o := -I$(src)
+
+# for sync with i915 gfx driver
+snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += component.o
+snd-hda-core-$(CONFIG_SND_HDA_I915) += i915.o
+
+obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
+
+#extended hda
+obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/
+
+snd-intel-dspcfg-y := intel-dsp-config.o
+snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o
+obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o
+
+snd-intel-sdw-acpi-y := intel-sdw-acpi.o
+obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o
diff --git a/sound/hda/array.c b/sound/hda/core/array.c
similarity index 100%
rename from sound/hda/array.c
rename to sound/hda/core/array.c
diff --git a/sound/hda/hdac_bus.c b/sound/hda/core/bus.c
similarity index 100%
rename from sound/hda/hdac_bus.c
rename to sound/hda/core/bus.c
diff --git a/sound/hda/hdac_component.c b/sound/hda/core/component.c
similarity index 100%
rename from sound/hda/hdac_component.c
rename to sound/hda/core/component.c
diff --git a/sound/hda/hdac_controller.c b/sound/hda/core/controller.c
similarity index 100%
rename from sound/hda/hdac_controller.c
rename to sound/hda/core/controller.c
diff --git a/sound/hda/hdac_device.c b/sound/hda/core/device.c
similarity index 100%
rename from sound/hda/hdac_device.c
rename to sound/hda/core/device.c
diff --git a/sound/hda/ext/Makefile b/sound/hda/core/ext/Makefile
similarity index 54%
rename from sound/hda/ext/Makefile
rename to sound/hda/core/ext/Makefile
index 05883fb28d28..85190a7eb5de 100644
--- a/sound/hda/ext/Makefile
+++ b/sound/hda/core/ext/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-snd-hda-ext-core-y := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o
+snd-hda-ext-core-y := bus.o controller.o stream.o
 
 obj-$(CONFIG_SND_HDA_EXT_CORE) += snd-hda-ext-core.o
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/core/ext/bus.c
similarity index 100%
rename from sound/hda/ext/hdac_ext_bus.c
rename to sound/hda/core/ext/bus.c
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/core/ext/controller.c
similarity index 100%
rename from sound/hda/ext/hdac_ext_controller.c
rename to sound/hda/core/ext/controller.c
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/core/ext/stream.c
similarity index 100%
rename from sound/hda/ext/hdac_ext_stream.c
rename to sound/hda/core/ext/stream.c
diff --git a/sound/hda/hda_bus_type.c b/sound/hda/core/hda_bus_type.c
similarity index 100%
rename from sound/hda/hda_bus_type.c
rename to sound/hda/core/hda_bus_type.c
diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/core/hdmi_chmap.c
similarity index 100%
rename from sound/hda/hdmi_chmap.c
rename to sound/hda/core/hdmi_chmap.c
diff --git a/sound/hda/hdac_i915.c b/sound/hda/core/i915.c
similarity index 100%
rename from sound/hda/hdac_i915.c
rename to sound/hda/core/i915.c
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/core/intel-dsp-config.c
similarity index 100%
rename from sound/hda/intel-dsp-config.c
rename to sound/hda/core/intel-dsp-config.c
diff --git a/sound/hda/intel-nhlt.c b/sound/hda/core/intel-nhlt.c
similarity index 100%
rename from sound/hda/intel-nhlt.c
rename to sound/hda/core/intel-nhlt.c
diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/core/intel-sdw-acpi.c
similarity index 100%
rename from sound/hda/intel-sdw-acpi.c
rename to sound/hda/core/intel-sdw-acpi.c
diff --git a/sound/hda/local.h b/sound/hda/core/local.h
similarity index 100%
rename from sound/hda/local.h
rename to sound/hda/core/local.h
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/core/regmap.c
similarity index 100%
rename from sound/hda/hdac_regmap.c
rename to sound/hda/core/regmap.c
diff --git a/sound/hda/hdac_stream.c b/sound/hda/core/stream.c
similarity index 100%
rename from sound/hda/hdac_stream.c
rename to sound/hda/core/stream.c
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/core/sysfs.c
similarity index 100%
rename from sound/hda/hdac_sysfs.c
rename to sound/hda/core/sysfs.c
diff --git a/sound/hda/trace.c b/sound/hda/core/trace.c
similarity index 100%
rename from sound/hda/trace.c
rename to sound/hda/core/trace.c
diff --git a/sound/hda/trace.h b/sound/hda/core/trace.h
similarity index 100%
rename from sound/hda/trace.h
rename to sound/hda/core/trace.h
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 03/27] ALSA: hda: Move common codec driver into sound/hda/common directory
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
  2025-07-09 16:04 ` [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h Takashi Iwai
  2025-07-09 16:04 ` [PATCH 02/27] ALSA: hda: Move HD-audio core stuff into sound/hda/core Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 04/27] ALSA: hda: Move CONFIG_SND_HDA_PREALLOC_SIZE into sound/hda/common Takashi Iwai
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

The snd-hda-codec module contains the most of common code used by both
HD-audio controller and codec drivers, and it's basically independent
from PCI.  Let's move the code to sound/hda/common directory as a part
of code reorganization.

The hda_ prefix is dropped from the most of file names as it's rather
superfluous.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/Kconfig                             |  5 ++
 sound/hda/Makefile                            |  1 +
 sound/hda/common/Kconfig                      | 80 +++++++++++++++++++
 sound/hda/common/Makefile                     | 13 +++
 .../common/auto_parser.c}                     |  0
 .../{pci/hda/hda_beep.c => hda/common/beep.c} |  0
 .../{pci/hda/hda_bind.c => hda/common/bind.c} |  0
 .../hda/hda_codec.c => hda/common/codec.c}    |  0
 .../common/controller.c}                      |  2 +-
 .../common/controller_trace.h}                |  2 +-
 .../{pci/hda => hda/common}/hda_auto_parser.h |  0
 sound/{pci/hda => hda/common}/hda_beep.h      |  0
 .../{pci/hda => hda/common}/hda_controller.h  |  0
 sound/{pci/hda => hda/common}/hda_jack.h      |  0
 sound/{pci/hda => hda/common}/hda_local.h     |  0
 .../hda/hda_hwdep.c => hda/common/hwdep.c}    |  0
 .../{pci/hda/hda_jack.c => hda/common/jack.c} |  0
 .../{pci/hda/hda_proc.c => hda/common/proc.c} |  0
 .../hda/hda_sysfs.c => hda/common/sysfs.c}    |  0
 sound/pci/hda/Kconfig                         | 76 ------------------
 sound/pci/hda/Makefile                        | 13 +--
 21 files changed, 103 insertions(+), 89 deletions(-)
 create mode 100644 sound/hda/common/Kconfig
 create mode 100644 sound/hda/common/Makefile
 rename sound/{pci/hda/hda_auto_parser.c => hda/common/auto_parser.c} (100%)
 rename sound/{pci/hda/hda_beep.c => hda/common/beep.c} (100%)
 rename sound/{pci/hda/hda_bind.c => hda/common/bind.c} (100%)
 rename sound/{pci/hda/hda_codec.c => hda/common/codec.c} (100%)
 rename sound/{pci/hda/hda_controller.c => hda/common/controller.c} (99%)
 rename sound/{pci/hda/hda_controller_trace.h => hda/common/controller_trace.h} (97%)
 rename sound/{pci/hda => hda/common}/hda_auto_parser.h (100%)
 rename sound/{pci/hda => hda/common}/hda_beep.h (100%)
 rename sound/{pci/hda => hda/common}/hda_controller.h (100%)
 rename sound/{pci/hda => hda/common}/hda_jack.h (100%)
 rename sound/{pci/hda => hda/common}/hda_local.h (100%)
 rename sound/{pci/hda/hda_hwdep.c => hda/common/hwdep.c} (100%)
 rename sound/{pci/hda/hda_jack.c => hda/common/jack.c} (100%)
 rename sound/{pci/hda/hda_proc.c => hda/common/proc.c} (100%)
 rename sound/{pci/hda/hda_sysfs.c => hda/common/sysfs.c} (100%)

diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index e38014656077..2928cb570ec6 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -1,2 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
+menu "HD-Audio"
+
+source "sound/hda/common/Kconfig"
 source "sound/hda/core/Kconfig"
+
+endmenu
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index 3fdbc22b1530..e7596bf736a4 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y += core/
+obj-$(CONFIG_SND_HDA) += common/
diff --git a/sound/hda/common/Kconfig b/sound/hda/common/Kconfig
new file mode 100644
index 000000000000..d1e2bfd24c11
--- /dev/null
+++ b/sound/hda/common/Kconfig
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SND_HDA
+	tristate
+	select SND_PCM
+	select SND_VMASTER
+	select SND_JACK
+	select SND_HDA_CORE
+
+if SND_HDA
+
+config SND_HDA_HWDEP
+	bool "Build hwdep interface for HD-audio driver"
+	select SND_HWDEP
+	help
+	  Say Y here to build a hwdep interface for HD-audio driver.
+	  This interface can be used for out-of-band communication
+	  with codecs for debugging purposes.
+
+config SND_HDA_RECONFIG
+	bool "Allow dynamic codec reconfiguration"
+	help
+	  Say Y here to enable the HD-audio codec re-configuration feature.
+	  It allows user to clear the whole codec configuration, change the
+	  codec setup, add extra verbs, and re-configure the codec dynamically.
+
+	  Note that this item alone doesn't provide the sysfs interface, but
+	  enables the feature just for the patch loader below.
+	  If you need the traditional sysfs entries for the manual interaction,
+	  turn on CONFIG_SND_HDA_HWDEP as well.
+
+config SND_HDA_INPUT_BEEP
+	bool "Support digital beep via input layer"
+	depends on INPUT=y || INPUT=SND_HDA
+	help
+	  Say Y here to build a digital beep interface for HD-audio
+	  driver. This interface is used to generate digital beeps.
+
+config SND_HDA_INPUT_BEEP_MODE
+	int "Digital beep registration mode (0=off, 1=on)"
+	depends on SND_HDA_INPUT_BEEP=y
+	default "1"
+	range 0 1
+	help
+	  Set 0 to disable the digital beep interface for HD-audio by default.
+	  Set 1 to always enable the digital beep interface for HD-audio by
+	  default.
+
+config SND_HDA_PATCH_LOADER
+	bool "Support initialization patch loading for HD-audio"
+	select FW_LOADER
+	select SND_HDA_RECONFIG
+	help
+	  Say Y here to allow the HD-audio driver to load a pseudo
+	  firmware file ("patch") for overriding the BIOS setup at
+	  start up.  The "patch" file can be specified via patch module
+	  option, such as patch=hda-init.
+
+config SND_HDA_POWER_SAVE_DEFAULT
+	int "Default time-out for HD-audio power-save mode"
+	depends on PM
+	default 0
+	help
+	  The default time-out value in seconds for HD-audio automatic
+	  power-save mode.  0 means to disable the power-save mode.
+
+config SND_HDA_CTL_DEV_ID
+	bool "Use the device identifier field for controls"
+	depends on SND_HDA_INTEL
+	help
+	  Say Y to use the device identifier field for (mixer)
+	  controls (old behaviour until this option is available).
+
+	  When enabled, the multiple HDA codecs may set the device
+	  field in control (mixer) element identifiers. The use
+	  of this field is not recommended and defined for mixer controls.
+
+	  The old behaviour (Y) is obsolete and will be removed. Consider
+	  to not enable this option.
+endif
diff --git a/sound/hda/common/Makefile b/sound/hda/common/Makefile
new file mode 100644
index 000000000000..3344fa0efe75
--- /dev/null
+++ b/sound/hda/common/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-hda-codec-y := bind.o codec.o jack.o auto_parser.o sysfs.o
+snd-hda-codec-y += controller.o
+snd-hda-codec-$(CONFIG_SND_PROC_FS) += proc.o
+
+snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hwdep.o
+snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += beep.o
+
+# for trace-points
+CFLAGS_controller.o := -I$(src)
+
+# common driver
+obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/hda/common/auto_parser.c
similarity index 100%
rename from sound/pci/hda/hda_auto_parser.c
rename to sound/hda/common/auto_parser.c
diff --git a/sound/pci/hda/hda_beep.c b/sound/hda/common/beep.c
similarity index 100%
rename from sound/pci/hda/hda_beep.c
rename to sound/hda/common/beep.c
diff --git a/sound/pci/hda/hda_bind.c b/sound/hda/common/bind.c
similarity index 100%
rename from sound/pci/hda/hda_bind.c
rename to sound/hda/common/bind.c
diff --git a/sound/pci/hda/hda_codec.c b/sound/hda/common/codec.c
similarity index 100%
rename from sound/pci/hda/hda_codec.c
rename to sound/hda/common/codec.c
diff --git a/sound/pci/hda/hda_controller.c b/sound/hda/common/controller.c
similarity index 99%
rename from sound/pci/hda/hda_controller.c
rename to sound/hda/common/controller.c
index f3330b7e0fcf..84387ed761be 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/hda/common/controller.c
@@ -29,7 +29,7 @@
 #include "hda_local.h"
 
 #define CREATE_TRACE_POINTS
-#include "hda_controller_trace.h"
+#include "controller_trace.h"
 
 /* DSP lock helpers */
 #define dsp_lock(dev)		snd_hdac_dsp_lock(azx_stream(dev))
diff --git a/sound/pci/hda/hda_controller_trace.h b/sound/hda/common/controller_trace.h
similarity index 97%
rename from sound/pci/hda/hda_controller_trace.h
rename to sound/hda/common/controller_trace.h
index bf48304e230a..7f5841f8919e 100644
--- a/sound/pci/hda/hda_controller_trace.h
+++ b/sound/hda/common/controller_trace.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM hda_controller
-#define TRACE_INCLUDE_FILE hda_controller_trace
+#define TRACE_INCLUDE_FILE controller_trace
 
 #if !defined(_TRACE_HDA_CONTROLLER_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_HDA_CONTROLLER_H
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/hda/common/hda_auto_parser.h
similarity index 100%
rename from sound/pci/hda/hda_auto_parser.h
rename to sound/hda/common/hda_auto_parser.h
diff --git a/sound/pci/hda/hda_beep.h b/sound/hda/common/hda_beep.h
similarity index 100%
rename from sound/pci/hda/hda_beep.h
rename to sound/hda/common/hda_beep.h
diff --git a/sound/pci/hda/hda_controller.h b/sound/hda/common/hda_controller.h
similarity index 100%
rename from sound/pci/hda/hda_controller.h
rename to sound/hda/common/hda_controller.h
diff --git a/sound/pci/hda/hda_jack.h b/sound/hda/common/hda_jack.h
similarity index 100%
rename from sound/pci/hda/hda_jack.h
rename to sound/hda/common/hda_jack.h
diff --git a/sound/pci/hda/hda_local.h b/sound/hda/common/hda_local.h
similarity index 100%
rename from sound/pci/hda/hda_local.h
rename to sound/hda/common/hda_local.h
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/hda/common/hwdep.c
similarity index 100%
rename from sound/pci/hda/hda_hwdep.c
rename to sound/hda/common/hwdep.c
diff --git a/sound/pci/hda/hda_jack.c b/sound/hda/common/jack.c
similarity index 100%
rename from sound/pci/hda/hda_jack.c
rename to sound/hda/common/jack.c
diff --git a/sound/pci/hda/hda_proc.c b/sound/hda/common/proc.c
similarity index 100%
rename from sound/pci/hda/hda_proc.c
rename to sound/hda/common/proc.c
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/hda/common/sysfs.c
similarity index 100%
rename from sound/pci/hda/hda_sysfs.c
rename to sound/hda/common/sysfs.c
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 745f120a5cee..1dfd56493d39 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -1,13 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "HD-Audio"
 
-config SND_HDA
-	tristate
-	select SND_PCM
-	select SND_VMASTER
-	select SND_JACK
-	select SND_HDA_CORE
-
 config SND_HDA_GENERIC_LEDS
        bool
 
@@ -55,53 +48,6 @@ config SND_HDA_ACPI
 
 if SND_HDA
 
-config SND_HDA_HWDEP
-	bool "Build hwdep interface for HD-audio driver"
-	select SND_HWDEP
-	help
-	  Say Y here to build a hwdep interface for HD-audio driver.
-	  This interface can be used for out-of-band communication
-	  with codecs for debugging purposes.
-
-config SND_HDA_RECONFIG
-	bool "Allow dynamic codec reconfiguration"
-	help
-	  Say Y here to enable the HD-audio codec re-configuration feature.
-	  It allows user to clear the whole codec configuration, change the
-	  codec setup, add extra verbs, and re-configure the codec dynamically.
-
-	  Note that this item alone doesn't provide the sysfs interface, but
-	  enables the feature just for the patch loader below.
-	  If you need the traditional sysfs entries for the manual interaction,
-	  turn on CONFIG_SND_HDA_HWDEP as well.
-
-config SND_HDA_INPUT_BEEP
-	bool "Support digital beep via input layer"
-	depends on INPUT=y || INPUT=SND_HDA
-	help
-	  Say Y here to build a digital beep interface for HD-audio
-	  driver. This interface is used to generate digital beeps.
-
-config SND_HDA_INPUT_BEEP_MODE
-	int "Digital beep registration mode (0=off, 1=on)"
-	depends on SND_HDA_INPUT_BEEP=y
-	default "1"
-	range 0 1
-	help
-	  Set 0 to disable the digital beep interface for HD-audio by default.
-	  Set 1 to always enable the digital beep interface for HD-audio by
-	  default.
-
-config SND_HDA_PATCH_LOADER
-	bool "Support initialization patch loading for HD-audio"
-	select FW_LOADER
-	select SND_HDA_RECONFIG
-	help
-	  Say Y here to allow the HD-audio driver to load a pseudo
-	  firmware file ("patch") for overriding the BIOS setup at
-	  start up.  The "patch" file can be specified via patch module
-	  option, such as patch=hda-init.
-
 config SND_HDA_CIRRUS_SCODEC
 	tristate
 
@@ -394,14 +340,6 @@ config SND_HDA_GENERIC
 comment "Set to Y if you want auto-loading the codec driver"
 	depends on SND_HDA=y && SND_HDA_GENERIC=m
 
-config SND_HDA_POWER_SAVE_DEFAULT
-	int "Default time-out for HD-audio power-save mode"
-	depends on PM
-	default 0
-	help
-	  The default time-out value in seconds for HD-audio automatic
-	  power-save mode.  0 means to disable the power-save mode.
-
 config SND_HDA_INTEL_HDMI_SILENT_STREAM
 	bool "Enable Silent Stream always for HDMI"
 	depends on SND_HDA_INTEL
@@ -417,20 +355,6 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
 	  This feature can impact power consumption as resources
 	  are kept reserved both at transmitter and receiver.
 
-config SND_HDA_CTL_DEV_ID
-	bool "Use the device identifier field for controls"
-	depends on SND_HDA_INTEL
-	help
-	  Say Y to use the device identifier field for (mixer)
-	  controls (old behaviour until this option is available).
-
-	  When enabled, the multiple HDA codecs may set the device
-	  field in control (mixer) element identifiers. The use
-	  of this field is not recommended and defined for mixer controls.
-
-	  The old behaviour (Y) is obsolete and will be removed. Consider
-	  to not enable this option.
-
 endif
 
 endmenu
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index a5ab8ee2d7f9..920011bb1b06 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -3,17 +3,11 @@ snd-hda-intel-y := hda_intel.o
 snd-hda-tegra-y := hda_tegra.o
 snd-hda-acpi-y := hda_acpi.o
 
-snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
-snd-hda-codec-y += hda_controller.o
-snd-hda-codec-$(CONFIG_SND_PROC_FS) += hda_proc.o
-
-snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
-snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
-
 # for trace-points
-CFLAGS_hda_controller.o := -I$(src)
 CFLAGS_hda_intel.o := -I$(src)
 
+subdir-ccflags-y += -I$(src)/../../hda/common
+
 snd-hda-codec-generic-y :=	hda_generic.o
 snd-hda-codec-realtek-y :=	patch_realtek.o
 snd-hda-codec-cmedia-y :=	patch_cmedia.o
@@ -43,9 +37,6 @@ snd-hda-scodec-tas2781-y :=	tas2781_hda.o
 snd-hda-scodec-tas2781-i2c-y :=	tas2781_hda_i2c.o
 snd-hda-scodec-tas2781-spi-y :=	tas2781_hda_spi.o
 
-# common driver
-obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
-
 # codec drivers
 obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
 obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 04/27] ALSA: hda: Move CONFIG_SND_HDA_PREALLOC_SIZE into sound/hda/common
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (2 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 03/27] ALSA: hda: Move common codec driver into sound/hda/common directory Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 05/27] ALSA: hda: Move controller drivers into sound/hda/controllers directory Takashi Iwai
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

CONFIG_SND_HDA_PREALLOC_SIZE is used only by controller.c in
sound/hda/common, hence it depends on CONFIG_SND_HDA.

Move the definition to the right place inside SND_HDA if/endif block
in sound/hda/common/Kconfig.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/common/Kconfig | 17 +++++++++++++++++
 sound/hda/core/Kconfig   | 16 ----------------
 2 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/sound/hda/common/Kconfig b/sound/hda/common/Kconfig
index d1e2bfd24c11..f38e1947fb3e 100644
--- a/sound/hda/common/Kconfig
+++ b/sound/hda/common/Kconfig
@@ -77,4 +77,21 @@ config SND_HDA_CTL_DEV_ID
 
 	  The old behaviour (Y) is obsolete and will be removed. Consider
 	  to not enable this option.
+
+config SND_HDA_PREALLOC_SIZE
+	int "Pre-allocated buffer size for HD-audio driver"
+	range 0 32768
+	default 0 if SND_DMA_SGBUF
+	default 64 if !SND_DMA_SGBUF
+	help
+	  Specifies the default pre-allocated buffer-size in kB for the
+	  HD-audio driver.  A larger buffer (e.g. 2048) is preferred
+	  for systems using PulseAudio.  The default 64 is chosen just
+	  for compatibility reasons.
+	  On x86 systems, the default is zero as S/G allocation works
+	  and no preallocation is needed in most cases.
+
+	  Note that the pre-allocation size can be changed dynamically
+	  via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
+
 endif
diff --git a/sound/hda/core/Kconfig b/sound/hda/core/Kconfig
index eb488a522572..bfdcf6384c52 100644
--- a/sound/hda/core/Kconfig
+++ b/sound/hda/core/Kconfig
@@ -20,22 +20,6 @@ config SND_HDA_EXT_CORE
        tristate
        select SND_HDA_CORE
 
-config SND_HDA_PREALLOC_SIZE
-	int "Pre-allocated buffer size for HD-audio driver"
-	range 0 32768
-	default 0 if SND_DMA_SGBUF
-	default 64 if !SND_DMA_SGBUF
-	help
-	  Specifies the default pre-allocated buffer-size in kB for the
-	  HD-audio driver.  A larger buffer (e.g. 2048) is preferred
-	  for systems using PulseAudio.  The default 64 is chosen just
-	  for compatibility reasons.
-	  On x86 systems, the default is zero as S/G allocation works
-	  and no preallocation is needed in most cases.
-
-	  Note that the pre-allocation size can be changed dynamically
-	  via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
-
 config SND_INTEL_NHLT
 	bool
 	# this config should be selected only for Intel ACPI platforms.
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 05/27] ALSA: hda: Move controller drivers into sound/hda/controllers directory
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (3 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 04/27] ALSA: hda: Move CONFIG_SND_HDA_PREALLOC_SIZE into sound/hda/common Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory Takashi Iwai
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Now HD-audio controller drivers are moved into sound/hda/controllers
directory as a part of HD-audio code reorganization.  Most of drivers
are independent from PCI bus, hence it makes more sense to put under
sound/hda.

The hda_ prefix is dropped from most of files at moving, as it's
more or less superfluous.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/Kconfig                             |  1 +
 sound/hda/Makefile                            |  4 ++
 sound/hda/controllers/Kconfig                 | 42 +++++++++++++++++++
 sound/hda/controllers/Makefile                | 13 ++++++
 .../hda/hda_acpi.c => hda/controllers/acpi.c} |  0
 .../hda_intel.c => hda/controllers/intel.c}   |  5 +--
 .../hda_intel.h => hda/controllers/intel.h}   |  0
 .../controllers/intel_trace.h}                |  2 +-
 .../hda_tegra.c => hda/controllers/tegra.c}   |  0
 sound/pci/hda/Kconfig                         | 42 -------------------
 sound/pci/hda/Makefile                        | 14 -------
 11 files changed, 63 insertions(+), 60 deletions(-)
 create mode 100644 sound/hda/controllers/Kconfig
 create mode 100644 sound/hda/controllers/Makefile
 rename sound/{pci/hda/hda_acpi.c => hda/controllers/acpi.c} (100%)
 rename sound/{pci/hda/hda_intel.c => hda/controllers/intel.c} (99%)
 rename sound/{pci/hda/hda_intel.h => hda/controllers/intel.h} (100%)
 rename sound/{pci/hda/hda_intel_trace.h => hda/controllers/intel_trace.h} (95%)
 rename sound/{pci/hda/hda_tegra.c => hda/controllers/tegra.c} (100%)

diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index 2928cb570ec6..d360c884bd6d 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -2,6 +2,7 @@
 menu "HD-Audio"
 
 source "sound/hda/common/Kconfig"
+source "sound/hda/controllers/Kconfig"
 source "sound/hda/core/Kconfig"
 
 endmenu
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index e7596bf736a4..fc76086a1f5e 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,3 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y += core/
 obj-$(CONFIG_SND_HDA) += common/
+# this must be the last entry after codec drivers;
+# otherwise the codec patches won't be hooked before the PCI probe
+# when built in kernel
+obj-$(CONFIG_SND_HDA) += controllers/
diff --git a/sound/hda/controllers/Kconfig b/sound/hda/controllers/Kconfig
new file mode 100644
index 000000000000..34721f50b055
--- /dev/null
+++ b/sound/hda/controllers/Kconfig
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_HDA_INTEL
+	tristate "HD Audio PCI"
+	depends on SND_PCI
+	select SND_HDA
+	select SND_INTEL_DSP_CONFIG
+	help
+	  Say Y here to include support for Intel "High Definition
+	  Audio" (Azalia) and its compatible devices.
+
+	  This option enables the HD-audio controller.  Don't forget
+	  to choose the appropriate HD-audio codec options.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-intel.
+
+config SND_HDA_TEGRA
+	tristate "NVIDIA Tegra HD Audio"
+	depends on ARCH_TEGRA
+	select SND_HDA
+	select SND_HDA_ALIGNED_MMIO
+	help
+	  Say Y here to support the HDA controller present in NVIDIA
+	  Tegra SoCs
+
+	  This options enables support for the HD Audio controller
+	  present in some NVIDIA Tegra SoCs, used to communicate audio
+	  to the HDMI output.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-tegra.
+
+config SND_HDA_ACPI
+	tristate "HD Audio ACPI"
+	depends on ACPI
+	select SND_HDA
+	help
+	  Say Y here to include support for Azalia-compatible HDA controllers
+	  which are advertised via ACPI objects.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-hda-acpi.
diff --git a/sound/hda/controllers/Makefile b/sound/hda/controllers/Makefile
new file mode 100644
index 000000000000..a4bcd055e9ae
--- /dev/null
+++ b/sound/hda/controllers/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-hda-intel-y := intel.o
+snd-hda-tegra-y := tegra.o
+snd-hda-acpi-y := acpi.o
+
+subdir-ccflags-y += -I$(src)/../common
+
+# for trace-points
+CFLAGS_intel.o := -I$(src)
+
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
+obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
+obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o
diff --git a/sound/pci/hda/hda_acpi.c b/sound/hda/controllers/acpi.c
similarity index 100%
rename from sound/pci/hda/hda_acpi.c
rename to sound/hda/controllers/acpi.c
diff --git a/sound/pci/hda/hda_intel.c b/sound/hda/controllers/intel.c
similarity index 99%
rename from sound/pci/hda/hda_intel.c
rename to sound/hda/controllers/intel.c
index 439cf1bda6e6..ebfc999156f4 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/hda/controllers/intel.c
@@ -54,11 +54,10 @@
 #include <linux/apple-gmux.h>
 #include <linux/firmware.h>
 #include <sound/hda_codec.h>
-#include "hda_controller.h"
-#include "hda_intel.h"
+#include "intel.h"
 
 #define CREATE_TRACE_POINTS
-#include "hda_intel_trace.h"
+#include "intel_trace.h"
 
 /* position fix mode */
 enum {
diff --git a/sound/pci/hda/hda_intel.h b/sound/hda/controllers/intel.h
similarity index 100%
rename from sound/pci/hda/hda_intel.h
rename to sound/hda/controllers/intel.h
diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/hda/controllers/intel_trace.h
similarity index 95%
rename from sound/pci/hda/hda_intel_trace.h
rename to sound/hda/controllers/intel_trace.h
index 2775fa81a500..fb10ab9e7e55 100644
--- a/sound/pci/hda/hda_intel_trace.h
+++ b/sound/hda/controllers/intel_trace.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM hda_intel
-#define TRACE_INCLUDE_FILE hda_intel_trace
+#define TRACE_INCLUDE_FILE intel_trace
 
 #if !defined(_TRACE_HDA_INTEL_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_HDA_INTEL_H
diff --git a/sound/pci/hda/hda_tegra.c b/sound/hda/controllers/tegra.c
similarity index 100%
rename from sound/pci/hda/hda_tegra.c
rename to sound/hda/controllers/tegra.c
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 1dfd56493d39..a5d345514cf3 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -4,48 +4,6 @@ menu "HD-Audio"
 config SND_HDA_GENERIC_LEDS
        bool
 
-config SND_HDA_INTEL
-	tristate "HD Audio PCI"
-	depends on SND_PCI
-	select SND_HDA
-	select SND_INTEL_DSP_CONFIG
-	help
-	  Say Y here to include support for Intel "High Definition
-	  Audio" (Azalia) and its compatible devices.
-
-	  This option enables the HD-audio controller.  Don't forget
-	  to choose the appropriate codec options below.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-hda-intel.
-
-config SND_HDA_TEGRA
-	tristate "NVIDIA Tegra HD Audio"
-	depends on ARCH_TEGRA
-	select SND_HDA
-	select SND_HDA_ALIGNED_MMIO
-	help
-	  Say Y here to support the HDA controller present in NVIDIA
-	  Tegra SoCs
-
-	  This options enables support for the HD Audio controller
-	  present in some NVIDIA Tegra SoCs, used to communicate audio
-	  to the HDMI output.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-hda-tegra.
-
-config SND_HDA_ACPI
-	tristate "HD Audio ACPI"
-	depends on ACPI
-	select SND_HDA
-	help
-	  Say Y here to include support for Azalia-compatible HDA controllers
-	  which are advertised via ACPI objects.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-hda-acpi.
-
 if SND_HDA
 
 config SND_HDA_CIRRUS_SCODEC
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 920011bb1b06..79de0af71ad4 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,11 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-snd-hda-intel-y := hda_intel.o
-snd-hda-tegra-y := hda_tegra.o
-snd-hda-acpi-y := hda_acpi.o
-
-# for trace-points
-CFLAGS_hda_intel.o := -I$(src)
-
 subdir-ccflags-y += -I$(src)/../../hda/common
 
 snd-hda-codec-generic-y :=	hda_generic.o
@@ -66,10 +59,3 @@ obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
 obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
 obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
-
-# this must be the last entry after codec drivers;
-# otherwise the codec patches won't be hooked before the PCI probe
-# when built in kernel
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
-obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
-obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (4 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 05/27] ALSA: hda: Move controller drivers into sound/hda/controllers directory Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-10 10:05   ` Richard Fitzgerald
  2025-07-14  8:57   ` Cezary Rojewski
  2025-07-09 16:04 ` [PATCH 07/27] ALSA: hda: Split Realtek HD-audio codec driver Takashi Iwai
                   ` (21 subsequent siblings)
  27 siblings, 2 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Now move the all remaining codec drivers from sound/pci/hda to
sound/hda/codecs subdirectory.  Some drivers are put under the further
vendor subdirectory, and the vendor helper code (*_helper.c) are put
under helpers subdirectory.  Also the sub-codec drivers are moved under
a different subdirectory, sound/hda/codecs/sub-codecs, for
distinguishing from the main HD-audio codec drivers.

The prefix patch_ and hda_ as well as the suffix _helper are dropped
from file names as they are mostly superfluous.

No functional changes but just file path shuffling.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/Kconfig                             |   1 +
 sound/hda/Makefile                            |   1 +
 sound/{pci/hda => hda/codecs}/Kconfig         | 158 +-----------------
 sound/hda/codecs/Makefile                     |  31 ++++
 .../patch_analog.c => hda/codecs/analog.c}    |   2 +-
 .../patch_ca0110.c => hda/codecs/ca0110.c}    |   2 +-
 .../patch_ca0132.c => hda/codecs/ca0132.c}    |   2 +-
 sound/{pci/hda => hda/codecs}/ca0132_regs.h   |   0
 sound/hda/codecs/cirrus/Kconfig               |  21 +++
 sound/hda/codecs/cirrus/Makefile              |   8 +
 .../codecs/cirrus/cirrus.c}                   |   2 +-
 .../codecs/cirrus/cs8409-tables.c}            |   4 +-
 .../codecs/cirrus/cs8409.c}                   |   2 +-
 .../codecs/cirrus/cs8409.h}                   |   2 +-
 .../patch_cmedia.c => hda/codecs/cmedia.c}    |   2 +-
 .../codecs/conexant.c}                        |   6 +-
 .../hda_generic.c => hda/codecs/generic.c}    |   2 +-
 .../hda_generic.h => hda/codecs/generic.h}    |   0
 sound/hda/codecs/hdmi/Makefile                |   6 +
 .../hda/hda_eld.c => hda/codecs/hdmi/eld.c}   |   0
 .../patch_hdmi.c => hda/codecs/hdmi/hdmi.c}   |   2 +-
 .../codecs/helpers/hp_x360.c}                 |   0
 .../codecs/helpers/ideapad_hotkey_led.c}      |   0
 .../codecs/helpers/ideapad_s740.c}            |   0
 .../codecs/helpers/thinkpad.c}                |   0
 .../patch_realtek.c => hda/codecs/realtek.c}  |  12 +-
 .../codecs/senarytech.c}                      |   4 +-
 .../patch_si3054.c => hda/codecs/si3054.c}    |   0
 sound/hda/codecs/side-codecs/Kconfig          | 128 ++++++++++++++
 sound/hda/codecs/side-codecs/Makefile         |  28 ++++
 .../codecs/side-codecs}/cirrus_scodec.c       |   0
 .../codecs/side-codecs}/cirrus_scodec.h       |   0
 .../codecs/side-codecs}/cirrus_scodec_test.c  |   0
 .../codecs/side-codecs}/cs35l41_hda.c         |   2 +-
 .../codecs/side-codecs}/cs35l41_hda.h         |   0
 .../codecs/side-codecs}/cs35l41_hda_i2c.c     |   0
 .../side-codecs}/cs35l41_hda_property.c       |   0
 .../side-codecs}/cs35l41_hda_property.h       |   0
 .../codecs/side-codecs}/cs35l41_hda_spi.c     |   0
 .../codecs/side-codecs}/cs35l56_hda.c         |   2 +-
 .../codecs/side-codecs}/cs35l56_hda.h         |   0
 .../codecs/side-codecs}/cs35l56_hda_i2c.c     |   0
 .../codecs/side-codecs}/cs35l56_hda_spi.c     |   0
 .../codecs/side-codecs}/hda_component.c       |   0
 .../codecs/side-codecs}/hda_component.h       |   0
 .../codecs/side-codecs}/tas2781_hda.c         |   0
 .../codecs/side-codecs}/tas2781_hda.h         |   0
 .../codecs/side-codecs}/tas2781_hda_i2c.c     |   2 +-
 .../codecs/side-codecs}/tas2781_hda_spi.c     |   2 +-
 .../codecs/sigmatel.c}                        |   4 +-
 .../{pci/hda/patch_via.c => hda/codecs/via.c} |   2 +-
 sound/pci/Kconfig                             |   2 -
 sound/pci/Makefile                            |   1 -
 sound/pci/hda/Makefile                        |  61 -------
 54 files changed, 257 insertions(+), 247 deletions(-)
 rename sound/{pci/hda => hda/codecs}/Kconfig (55%)
 create mode 100644 sound/hda/codecs/Makefile
 rename sound/{pci/hda/patch_analog.c => hda/codecs/analog.c} (99%)
 rename sound/{pci/hda/patch_ca0110.c => hda/codecs/ca0110.c} (98%)
 rename sound/{pci/hda/patch_ca0132.c => hda/codecs/ca0132.c} (99%)
 rename sound/{pci/hda => hda/codecs}/ca0132_regs.h (100%)
 create mode 100644 sound/hda/codecs/cirrus/Kconfig
 create mode 100644 sound/hda/codecs/cirrus/Makefile
 rename sound/{pci/hda/patch_cirrus.c => hda/codecs/cirrus/cirrus.c} (99%)
 rename sound/{pci/hda/patch_cs8409-tables.c => hda/codecs/cirrus/cs8409-tables.c} (99%)
 rename sound/{pci/hda/patch_cs8409.c => hda/codecs/cirrus/cs8409.c} (99%)
 rename sound/{pci/hda/patch_cs8409.h => hda/codecs/cirrus/cs8409.h} (99%)
 rename sound/{pci/hda/patch_cmedia.c => hda/codecs/cmedia.c} (99%)
 rename sound/{pci/hda/patch_conexant.c => hda/codecs/conexant.c} (99%)
 rename sound/{pci/hda/hda_generic.c => hda/codecs/generic.c} (99%)
 rename sound/{pci/hda/hda_generic.h => hda/codecs/generic.h} (100%)
 create mode 100644 sound/hda/codecs/hdmi/Makefile
 rename sound/{pci/hda/hda_eld.c => hda/codecs/hdmi/eld.c} (100%)
 rename sound/{pci/hda/patch_hdmi.c => hda/codecs/hdmi/hdmi.c} (99%)
 rename sound/{pci/hda/hp_x360_helper.c => hda/codecs/helpers/hp_x360.c} (100%)
 rename sound/{pci/hda/ideapad_hotkey_led_helper.c => hda/codecs/helpers/ideapad_hotkey_led.c} (100%)
 rename sound/{pci/hda/ideapad_s740_helper.c => hda/codecs/helpers/ideapad_s740.c} (100%)
 rename sound/{pci/hda/thinkpad_helper.c => hda/codecs/helpers/thinkpad.c} (100%)
 rename sound/{pci/hda/patch_realtek.c => hda/codecs/realtek.c} (99%)
 rename sound/{pci/hda/patch_senarytech.c => hda/codecs/senarytech.c} (98%)
 rename sound/{pci/hda/patch_si3054.c => hda/codecs/si3054.c} (100%)
 create mode 100644 sound/hda/codecs/side-codecs/Kconfig
 create mode 100644 sound/hda/codecs/side-codecs/Makefile
 rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec_test.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.c (99%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_i2c.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_spi.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.c (99%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_i2c.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_spi.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.c (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.h (100%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_i2c.c (99%)
 rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_spi.c (99%)
 rename sound/{pci/hda/patch_sigmatel.c => hda/codecs/sigmatel.c} (99%)
 rename sound/{pci/hda/patch_via.c => hda/codecs/via.c} (99%)
 delete mode 100644 sound/pci/hda/Makefile

diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index d360c884bd6d..7797f44b3d0c 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -3,6 +3,7 @@ menu "HD-Audio"
 
 source "sound/hda/common/Kconfig"
 source "sound/hda/controllers/Kconfig"
+source "sound/hda/codecs/Kconfig"
 source "sound/hda/core/Kconfig"
 
 endmenu
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index fc76086a1f5e..31b9fbedaa77 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y += core/
 obj-$(CONFIG_SND_HDA) += common/
+obj-$(CONFIG_SND_HDA) += codecs/
 # this must be the last entry after codec drivers;
 # otherwise the codec patches won't be hooked before the PCI probe
 # when built in kernel
diff --git a/sound/pci/hda/Kconfig b/sound/hda/codecs/Kconfig
similarity index 55%
rename from sound/pci/hda/Kconfig
rename to sound/hda/codecs/Kconfig
index a5d345514cf3..bac19a664be0 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/hda/codecs/Kconfig
@@ -1,140 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
-menu "HD-Audio"
+if SND_HDA
 
 config SND_HDA_GENERIC_LEDS
        bool
 
-if SND_HDA
-
-config SND_HDA_CIRRUS_SCODEC
-	tristate
-
-config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
-	tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
-	depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT
-	default KUNIT_ALL_TESTS
-	help
-	  This builds KUnit tests for the cirrus side-codec library.
-	  For more information on KUnit and unit tests in general,
-	  please refer to the KUnit documentation in
-	  Documentation/dev-tools/kunit/.
-	  If in doubt, say "N".
-
-config SND_HDA_SCODEC_CS35L41
-	tristate
-	select SND_HDA_GENERIC
-	select REGMAP_IRQ
-	select FW_CS_DSP
-
-config SND_HDA_SCODEC_COMPONENT
-	tristate
-
-config SND_HDA_SCODEC_CS35L41_I2C
-	tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
-	depends on I2C
-	depends on ACPI
-	depends on EFI
-	depends on SND_SOC
-	select SND_SOC_CS35L41_LIB
-	select SND_HDA_SCODEC_CS35L41
-	select SND_SOC_CS_AMP_LIB
-	help
-	  Say Y or M here to include CS35L41 I2C HD-audio side codec support
-	  in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-	depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m
-
-config SND_HDA_SCODEC_CS35L41_SPI
-	tristate "Build CS35L41 HD-audio codec support for SPI Bus"
-	depends on SPI_MASTER
-	depends on ACPI
-	depends on EFI
-	depends on SND_SOC
-	select SND_SOC_CS35L41_LIB
-	select SND_HDA_SCODEC_CS35L41
-	select SND_SOC_CS_AMP_LIB
-	help
-	  Say Y or M here to include CS35L41 SPI HD-audio side codec support
-	  in snd-hda-intel driver, such as ALC287.
-
-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
-	depends on SND_SOC
-	select FW_CS_DSP
-	imply SERIAL_MULTI_INSTANTIATE
-	select SND_HDA_GENERIC
-	select SND_SOC_CS35L56_SHARED
-	select SND_HDA_SCODEC_CS35L56
-	select SND_HDA_CIRRUS_SCODEC
-	select SND_SOC_CS_AMP_LIB
-	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
-	depends on SND_SOC
-	select FW_CS_DSP
-	imply SERIAL_MULTI_INSTANTIATE
-	select SND_HDA_GENERIC
-	select SND_SOC_CS35L56_SHARED
-	select SND_HDA_SCODEC_CS35L56
-	select SND_HDA_CIRRUS_SCODEC
-	select SND_SOC_CS_AMP_LIB
-	help
-	  Say Y or M here to include CS35L56 amplifier support with
-	  SPI control.
-
-config SND_HDA_SCODEC_TAS2781
-	tristate
-	select SND_HDA_GENERIC
-
-config SND_HDA_SCODEC_TAS2781_I2C
-	tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
-	depends on I2C
-	depends on ACPI
-	depends on EFI
-	depends on SND_SOC
-	select SND_HDA_SCODEC_TAS2781
-	select SND_SOC_TAS2781_COMLIB_I2C
-	select SND_SOC_TAS2781_FMWLIB
-	select CRC32
-	help
-	  Say Y or M here to include TAS2781 I2C HD-audio side codec support
-	  in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-	depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
-
-config SND_HDA_SCODEC_TAS2781_SPI
-	tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
-	depends on SPI_MASTER
-	depends on ACPI
-	depends on EFI
-	depends on SND_SOC
-	select SND_HDA_SCODEC_TAS2781
-	select SND_SOC_TAS2781_COMLIB
-	select SND_SOC_TAS2781_FMWLIB
-	select CRC8
-	select CRC32
-	help
-	  Say Y or M here to include TAS2781 SPI HD-audio side codec support
-	  in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-	depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m
-
 config SND_HDA_CODEC_REALTEK
 	tristate "Build Realtek HD-audio codec support"
 	depends on INPUT
@@ -194,26 +63,6 @@ config SND_HDA_CODEC_HDMI
 comment "Set to Y if you want auto-loading the codec driver"
 	depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
 
-config SND_HDA_CODEC_CIRRUS
-	tristate "Build Cirrus Logic codec support"
-	select SND_HDA_GENERIC
-	help
-	  Say Y or M here to include Cirrus Logic codec support in
-	  snd-hda-intel driver, such as CS4206.
-
-comment "Set to Y if you want auto-loading the codec driver"
-	depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
-
-config SND_HDA_CODEC_CS8409
-	tristate "Build Cirrus Logic HDA bridge support"
-	select SND_HDA_GENERIC
-	help
-	  Say Y or M here to include Cirrus Logic HDA bridge support in
-	  snd-hda-intel driver, such as CS8409.
-
-comment "Set to Y if you want auto-loading the codec driver"
-	depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m
-
 config SND_HDA_CODEC_CONEXANT
 	tristate "Build Conexant HD-audio codec support"
 	select SND_HDA_GENERIC
@@ -313,6 +162,7 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
 	  This feature can impact power consumption as resources
 	  are kept reserved both at transmitter and receiver.
 
-endif
+source "sound/hda/codecs/cirrus/Kconfig"
+source "sound/hda/codecs/side-codecs/Kconfig"
 
-endmenu
+endif # SND_HDA
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
new file mode 100644
index 000000000000..205cd1373b42
--- /dev/null
+++ b/sound/hda/codecs/Makefile
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../common
+
+snd-hda-codec-generic-y :=	generic.o
+snd-hda-codec-analog-y :=	analog.o
+snd-hda-codec-ca0110-y :=	ca0110.o
+snd-hda-codec-ca0132-y :=	ca0132.o
+snd-hda-codec-cmedia-y :=	cmedia.o
+snd-hda-codec-conexant-y :=	conexant.o
+snd-hda-codec-idt-y :=		sigmatel.o
+snd-hda-codec-realtek-y :=	realtek.o
+snd-hda-codec-senarytech-y :=	senarytech.o
+snd-hda-codec-si3054-y :=	si3054.o
+snd-hda-codec-via-y :=		via.o
+
+obj-y += cirrus/
+obj-y += hdmi/
+obj-y += side-codecs/
+
+# codec drivers
+obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
+obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
+obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
+obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
+obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
+obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
+obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
+obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
+obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
diff --git a/sound/pci/hda/patch_analog.c b/sound/hda/codecs/analog.c
similarity index 99%
rename from sound/pci/hda/patch_analog.c
rename to sound/hda/codecs/analog.c
index 56354fe060a1..3557e06c6d2b 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/hda/codecs/analog.c
@@ -16,7 +16,7 @@
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 
 struct ad198x_spec {
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/hda/codecs/ca0110.c
similarity index 98%
rename from sound/pci/hda/patch_ca0110.c
rename to sound/hda/codecs/ca0110.c
index 1818ce67f761..0353544435b9 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/hda/codecs/ca0110.c
@@ -13,7 +13,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 
 static const struct hda_codec_ops ca0110_patch_ops = {
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/hda/codecs/ca0132.c
similarity index 99%
rename from sound/pci/hda/patch_ca0132.c
rename to sound/hda/codecs/ca0132.c
index 686ce0947131..35a979465c75 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2011, Creative Technology Ltd.
  *
- * Based on patch_ca0110.c
+ * Based on ca0110.c
  * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
  */
 
diff --git a/sound/pci/hda/ca0132_regs.h b/sound/hda/codecs/ca0132_regs.h
similarity index 100%
rename from sound/pci/hda/ca0132_regs.h
rename to sound/hda/codecs/ca0132_regs.h
diff --git a/sound/hda/codecs/cirrus/Kconfig b/sound/hda/codecs/cirrus/Kconfig
new file mode 100644
index 000000000000..f6cefb65c5f8
--- /dev/null
+++ b/sound/hda/codecs/cirrus/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SND_HDA_CODEC_CIRRUS
+	tristate "Build Cirrus Logic codec support"
+	select SND_HDA_GENERIC
+	help
+	  Say Y or M here to include Cirrus Logic codec support in
+	  snd-hda-intel driver, such as CS4206.
+
+comment "Set to Y if you want auto-loading the codec driver"
+	depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
+
+config SND_HDA_CODEC_CS8409
+	tristate "Build Cirrus Logic HDA bridge support"
+	select SND_HDA_GENERIC
+	help
+	  Say Y or M here to include Cirrus Logic HDA bridge support in
+	  snd-hda-intel driver, such as CS8409.
+
+comment "Set to Y if you want auto-loading the codec driver"
+	depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m
diff --git a/sound/hda/codecs/cirrus/Makefile b/sound/hda/codecs/cirrus/Makefile
new file mode 100644
index 000000000000..fa40c893fb09
--- /dev/null
+++ b/sound/hda/codecs/cirrus/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-cirrus-y :=	cirrus.o
+snd-hda-codec-cs8409-y :=	cs8409.o cs8409-tables.o
+
+obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
+obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/hda/codecs/cirrus/cirrus.c
similarity index 99%
rename from sound/pci/hda/patch_cirrus.c
rename to sound/hda/codecs/cirrus/cirrus.c
index 06e046214a41..81ea66c4e9d3 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/hda/codecs/cirrus/cirrus.c
@@ -15,7 +15,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
 
 /*
  */
diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/hda/codecs/cirrus/cs8409-tables.c
similarity index 99%
rename from sound/pci/hda/patch_cs8409-tables.c
rename to sound/hda/codecs/cirrus/cs8409-tables.c
index 09240138e087..5fe49f13c0da 100644
--- a/sound/pci/hda/patch_cs8409-tables.c
+++ b/sound/hda/codecs/cirrus/cs8409-tables.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * patch_cs8409-tables.c  --  HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * cs8409-tables.c  --  HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
  *
  * Copyright (C) 2021 Cirrus Logic, Inc. and
  *                    Cirrus Logic International Semiconductor Ltd.
@@ -8,7 +8,7 @@
  * Author: Lucas Tanure <tanureal@opensource.cirrus.com>
  */
 
-#include "patch_cs8409.h"
+#include "cs8409.h"
 
 /******************************************************************************
  *                          CS42L42 Specific Data
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/hda/codecs/cirrus/cs8409.c
similarity index 99%
rename from sound/pci/hda/patch_cs8409.c
rename to sound/hda/codecs/cirrus/cs8409.c
index e50006757a2c..5ec1126b2a55 100644
--- a/sound/pci/hda/patch_cs8409.c
+++ b/sound/hda/codecs/cirrus/cs8409.c
@@ -13,7 +13,7 @@
 #include <linux/mutex.h>
 #include <linux/iopoll.h>
 
-#include "patch_cs8409.h"
+#include "cs8409.h"
 
 /******************************************************************************
  *                        CS8409 Specific Functions
diff --git a/sound/pci/hda/patch_cs8409.h b/sound/hda/codecs/cirrus/cs8409.h
similarity index 99%
rename from sound/pci/hda/patch_cs8409.h
rename to sound/hda/codecs/cirrus/cs8409.h
index e4bd2e12110b..35072cd009dc 100644
--- a/sound/pci/hda/patch_cs8409.h
+++ b/sound/hda/codecs/cirrus/cs8409.h
@@ -17,7 +17,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
 
 /* CS8409 Specific Definitions */
 
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/hda/codecs/cmedia.c
similarity index 99%
rename from sound/pci/hda/patch_cmedia.c
rename to sound/hda/codecs/cmedia.c
index fe946d407830..c88da2f8233e 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/hda/codecs/cmedia.c
@@ -15,7 +15,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 /* CM9825 Offset Definitions */
 
diff --git a/sound/pci/hda/patch_conexant.c b/sound/hda/codecs/conexant.c
similarity index 99%
rename from sound/pci/hda/patch_conexant.c
rename to sound/hda/codecs/conexant.c
index e584a7b2877d..b7710a81fd87 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -19,7 +19,7 @@
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 struct conexant_spec {
 	struct hda_gen_spec gen;
@@ -312,10 +312,10 @@ enum {
 };
 
 /* for hda_fixup_thinkpad_acpi() */
-#include "thinkpad_helper.c"
+#include "helpers/thinkpad.c"
 
 /* for hda_fixup_ideapad_acpi() */
-#include "ideapad_hotkey_led_helper.c"
+#include "helpers/ideapad_hotkey_led.c"
 
 static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
 				  const struct hda_fixup *fix, int action)
diff --git a/sound/pci/hda/hda_generic.c b/sound/hda/codecs/generic.c
similarity index 99%
rename from sound/pci/hda/hda_generic.c
rename to sound/hda/codecs/generic.c
index 2a28c8b6ba55..873fd4b7f451 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/hda/codecs/generic.c
@@ -25,7 +25,7 @@
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_beep.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 
 /**
diff --git a/sound/pci/hda/hda_generic.h b/sound/hda/codecs/generic.h
similarity index 100%
rename from sound/pci/hda/hda_generic.h
rename to sound/hda/codecs/generic.h
diff --git a/sound/hda/codecs/hdmi/Makefile b/sound/hda/codecs/hdmi/Makefile
new file mode 100644
index 000000000000..371818d4e9b2
--- /dev/null
+++ b/sound/hda/codecs/hdmi/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-hdmi-y :=		hdmi.o eld.o
+
+obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
diff --git a/sound/pci/hda/hda_eld.c b/sound/hda/codecs/hdmi/eld.c
similarity index 100%
rename from sound/pci/hda/hda_eld.c
rename to sound/hda/codecs/hdmi/eld.c
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
similarity index 99%
rename from sound/pci/hda/patch_hdmi.c
rename to sound/hda/codecs/hdmi/hdmi.c
index 9a7793eb16e9..3811eb1dc998 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  *
- *  patch_hdmi.c - routines for HDMI/DisplayPort codecs
+ *  hdmi.c - routines for HDMI/DisplayPort codecs
  *
  *  Copyright(c) 2008-2010 Intel Corporation
  *  Copyright (c) 2006 ATI Technologies Inc.
diff --git a/sound/pci/hda/hp_x360_helper.c b/sound/hda/codecs/helpers/hp_x360.c
similarity index 100%
rename from sound/pci/hda/hp_x360_helper.c
rename to sound/hda/codecs/helpers/hp_x360.c
diff --git a/sound/pci/hda/ideapad_hotkey_led_helper.c b/sound/hda/codecs/helpers/ideapad_hotkey_led.c
similarity index 100%
rename from sound/pci/hda/ideapad_hotkey_led_helper.c
rename to sound/hda/codecs/helpers/ideapad_hotkey_led.c
diff --git a/sound/pci/hda/ideapad_s740_helper.c b/sound/hda/codecs/helpers/ideapad_s740.c
similarity index 100%
rename from sound/pci/hda/ideapad_s740_helper.c
rename to sound/hda/codecs/helpers/ideapad_s740.c
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/hda/codecs/helpers/thinkpad.c
similarity index 100%
rename from sound/pci/hda/thinkpad_helper.c
rename to sound/hda/codecs/helpers/thinkpad.c
diff --git a/sound/pci/hda/patch_realtek.c b/sound/hda/codecs/realtek.c
similarity index 99%
rename from sound/pci/hda/patch_realtek.c
rename to sound/hda/codecs/realtek.c
index c2592e5cf70a..9c86c7bd1a90 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/hda/codecs/realtek.c
@@ -30,8 +30,8 @@
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
-#include "hda_component.h"
+#include "generic.h"
+#include "side-codecs/hda_component.h"
 
 /* keep halting ALC5505 DSP, for power saving */
 #define HALT_REALTEK_ALC5505
@@ -7120,7 +7120,7 @@ static void alc285_fixup_hp_beep(struct hda_codec *codec,
 }
 
 /* for hda_fixup_thinkpad_acpi() */
-#include "thinkpad_helper.c"
+#include "helpers/thinkpad.c"
 
 static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 				    const struct hda_fixup *fix, int action)
@@ -7130,7 +7130,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 }
 
 /* for hda_fixup_ideapad_acpi() */
-#include "ideapad_hotkey_led_helper.c"
+#include "helpers/ideapad_hotkey_led.c"
 
 static void alc_fixup_ideapad_acpi(struct hda_codec *codec,
 				   const struct hda_fixup *fix, int action)
@@ -7362,10 +7362,10 @@ static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
 
 
 /* for alc295_fixup_hp_top_speakers */
-#include "hp_x360_helper.c"
+#include "helpers/hp_x360.c"
 
 /* for alc285_fixup_ideapad_s740_coef() */
-#include "ideapad_s740_helper.c"
+#include "helpers/ideapad_s740.c"
 
 static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
 	WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
diff --git a/sound/pci/hda/patch_senarytech.c b/sound/hda/codecs/senarytech.c
similarity index 98%
rename from sound/pci/hda/patch_senarytech.c
rename to sound/hda/codecs/senarytech.c
index 0691996fa971..9a253ad19f4d 100644
--- a/sound/pci/hda/patch_senarytech.c
+++ b/sound/hda/codecs/senarytech.c
@@ -2,7 +2,7 @@
 /*
  * HD audio interface patch for Senary HDA audio codec
  *
- * Initially based on sound/pci/hda/patch_conexant.c
+ * Initially based on conexant.c
  */
 
 #include <linux/init.h>
@@ -17,7 +17,7 @@
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 struct senary_spec {
 	struct hda_gen_spec gen;
diff --git a/sound/pci/hda/patch_si3054.c b/sound/hda/codecs/si3054.c
similarity index 100%
rename from sound/pci/hda/patch_si3054.c
rename to sound/hda/codecs/si3054.c
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
new file mode 100644
index 000000000000..cbf1847896bc
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -0,0 +1,128 @@
+config SND_HDA_CIRRUS_SCODEC
+	tristate
+
+config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
+	tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
+	depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  This builds KUnit tests for the cirrus side-codec library.
+	  For more information on KUnit and unit tests in general,
+	  please refer to the KUnit documentation in
+	  Documentation/dev-tools/kunit/.
+	  If in doubt, say "N".
+
+config SND_HDA_SCODEC_CS35L41
+	tristate
+	select SND_HDA_GENERIC
+	select REGMAP_IRQ
+	select FW_CS_DSP
+
+config SND_HDA_SCODEC_COMPONENT
+	tristate
+
+config SND_HDA_SCODEC_CS35L41_I2C
+	tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
+	depends on I2C
+	depends on ACPI
+	depends on EFI
+	depends on SND_SOC
+	select SND_SOC_CS35L41_LIB
+	select SND_HDA_SCODEC_CS35L41
+	select SND_SOC_CS_AMP_LIB
+	help
+	  Say Y or M here to include CS35L41 I2C HD-audio side codec support
+	  in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+	depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m
+
+config SND_HDA_SCODEC_CS35L41_SPI
+	tristate "Build CS35L41 HD-audio codec support for SPI Bus"
+	depends on SPI_MASTER
+	depends on ACPI
+	depends on EFI
+	depends on SND_SOC
+	select SND_SOC_CS35L41_LIB
+	select SND_HDA_SCODEC_CS35L41
+	select SND_SOC_CS_AMP_LIB
+	help
+	  Say Y or M here to include CS35L41 SPI HD-audio side codec support
+	  in snd-hda-intel driver, such as ALC287.
+
+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
+	depends on SND_SOC
+	select FW_CS_DSP
+	imply SERIAL_MULTI_INSTANTIATE
+	select SND_HDA_GENERIC
+	select SND_SOC_CS35L56_SHARED
+	select SND_HDA_SCODEC_CS35L56
+	select SND_HDA_CIRRUS_SCODEC
+	select SND_SOC_CS_AMP_LIB
+	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
+	depends on SND_SOC
+	select FW_CS_DSP
+	imply SERIAL_MULTI_INSTANTIATE
+	select SND_HDA_GENERIC
+	select SND_SOC_CS35L56_SHARED
+	select SND_HDA_SCODEC_CS35L56
+	select SND_HDA_CIRRUS_SCODEC
+	select SND_SOC_CS_AMP_LIB
+	help
+	  Say Y or M here to include CS35L56 amplifier support with
+	  SPI control.
+
+config SND_HDA_SCODEC_TAS2781
+	tristate
+	select SND_HDA_GENERIC
+
+config SND_HDA_SCODEC_TAS2781_I2C
+	tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
+	depends on I2C
+	depends on ACPI
+	depends on EFI
+	depends on SND_SOC
+	select SND_HDA_SCODEC_TAS2781
+	select SND_SOC_TAS2781_COMLIB_I2C
+	select SND_SOC_TAS2781_FMWLIB
+	select CRC32
+	help
+	  Say Y or M here to include TAS2781 I2C HD-audio side codec support
+	  in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+	depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
+
+config SND_HDA_SCODEC_TAS2781_SPI
+	tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
+	depends on SPI_MASTER
+	depends on ACPI
+	depends on EFI
+	depends on SND_SOC
+	select SND_HDA_SCODEC_TAS2781
+	select SND_SOC_TAS2781_COMLIB
+	select SND_SOC_TAS2781_FMWLIB
+	select CRC8
+	select CRC32
+	help
+	  Say Y or M here to include TAS2781 SPI HD-audio side codec support
+	  in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+	depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m
diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile
new file mode 100644
index 000000000000..245e84f6a121
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/Makefile
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-cirrus-scodec-y :=	cirrus_scodec.o
+snd-hda-cirrus-scodec-test-y :=	cirrus_scodec_test.o
+snd-hda-scodec-cs35l41-y :=	cs35l41_hda.o cs35l41_hda_property.o
+snd-hda-scodec-cs35l41-i2c-y :=	cs35l41_hda_i2c.o
+snd-hda-scodec-cs35l41-spi-y :=	cs35l41_hda_spi.o
+snd-hda-scodec-cs35l56-y :=	cs35l56_hda.o
+snd-hda-scodec-cs35l56-i2c-y :=	cs35l56_hda_i2c.o
+snd-hda-scodec-cs35l56-spi-y :=	cs35l56_hda_spi.o
+snd-hda-scodec-component-y :=	hda_component.o
+snd-hda-scodec-tas2781-y :=	tas2781_hda.o
+snd-hda-scodec-tas2781-i2c-y :=	tas2781_hda_i2c.o
+snd-hda-scodec-tas2781-spi-y :=	tas2781_hda_spi.o
+
+obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
+obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.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_SCODEC_COMPONENT) += snd-hda-scodec-component.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
diff --git a/sound/pci/hda/cirrus_scodec.c b/sound/hda/codecs/side-codecs/cirrus_scodec.c
similarity index 100%
rename from sound/pci/hda/cirrus_scodec.c
rename to sound/hda/codecs/side-codecs/cirrus_scodec.c
diff --git a/sound/pci/hda/cirrus_scodec.h b/sound/hda/codecs/side-codecs/cirrus_scodec.h
similarity index 100%
rename from sound/pci/hda/cirrus_scodec.h
rename to sound/hda/codecs/side-codecs/cirrus_scodec.h
diff --git a/sound/pci/hda/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c
similarity index 100%
rename from sound/pci/hda/cirrus_scodec_test.c
rename to sound/hda/codecs/side-codecs/cirrus_scodec_test.c
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
similarity index 99%
rename from sound/pci/hda/cs35l41_hda.c
rename to sound/hda/codecs/side-codecs/cs35l41_hda.c
index 2d7ee121a7fd..37f2cdc8ce82 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -17,7 +17,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
 #include "hda_component.h"
 #include "cs35l41_hda.h"
 #include "cs35l41_hda_property.h"
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/hda/codecs/side-codecs/cs35l41_hda.h
similarity index 100%
rename from sound/pci/hda/cs35l41_hda.h
rename to sound/hda/codecs/side-codecs/cs35l41_hda.h
diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c
similarity index 100%
rename from sound/pci/hda/cs35l41_hda_i2c.c
rename to sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
similarity index 100%
rename from sound/pci/hda/cs35l41_hda_property.c
rename to sound/hda/codecs/side-codecs/cs35l41_hda_property.c
diff --git a/sound/pci/hda/cs35l41_hda_property.h b/sound/hda/codecs/side-codecs/cs35l41_hda_property.h
similarity index 100%
rename from sound/pci/hda/cs35l41_hda_property.h
rename to sound/hda/codecs/side-codecs/cs35l41_hda_property.h
diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c
similarity index 100%
rename from sound/pci/hda/cs35l41_hda_spi.c
rename to sound/hda/codecs/side-codecs/cs35l41_hda_spi.c
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
similarity index 99%
rename from sound/pci/hda/cs35l56_hda.c
rename to sound/hda/codecs/side-codecs/cs35l56_hda.c
index e8b4995118bb..8d43119b3dd2 100644
--- a/sound/pci/hda/cs35l56_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -20,7 +20,7 @@
 #include "cirrus_scodec.h"
 #include "cs35l56_hda.h"
 #include "hda_component.h"
-#include "hda_generic.h"
+#include "../generic.h"
 
  /*
   * The cs35l56_hda_dai_config[] reg sequence configures the device as
diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h
similarity index 100%
rename from sound/pci/hda/cs35l56_hda.h
rename to sound/hda/codecs/side-codecs/cs35l56_hda.h
diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c
similarity index 100%
rename from sound/pci/hda/cs35l56_hda_i2c.c
rename to sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c
diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c
similarity index 100%
rename from sound/pci/hda/cs35l56_hda_spi.c
rename to sound/hda/codecs/side-codecs/cs35l56_hda_spi.c
diff --git a/sound/pci/hda/hda_component.c b/sound/hda/codecs/side-codecs/hda_component.c
similarity index 100%
rename from sound/pci/hda/hda_component.c
rename to sound/hda/codecs/side-codecs/hda_component.c
diff --git a/sound/pci/hda/hda_component.h b/sound/hda/codecs/side-codecs/hda_component.h
similarity index 100%
rename from sound/pci/hda/hda_component.h
rename to sound/hda/codecs/side-codecs/hda_component.h
diff --git a/sound/pci/hda/tas2781_hda.c b/sound/hda/codecs/side-codecs/tas2781_hda.c
similarity index 100%
rename from sound/pci/hda/tas2781_hda.c
rename to sound/hda/codecs/side-codecs/tas2781_hda.c
diff --git a/sound/pci/hda/tas2781_hda.h b/sound/hda/codecs/side-codecs/tas2781_hda.h
similarity index 100%
rename from sound/pci/hda/tas2781_hda.h
rename to sound/hda/codecs/side-codecs/tas2781_hda.h
diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
similarity index 99%
rename from sound/pci/hda/tas2781_hda_i2c.c
rename to sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
index b7ee22840d78..bacc3f6ed4bd 100644
--- a/sound/pci/hda/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -30,7 +30,7 @@
 #include "hda_auto_parser.h"
 #include "hda_component.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
 #include "tas2781_hda.h"
 
 #define TAS2563_CAL_VAR_NAME_MAX	16
diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
similarity index 99%
rename from sound/pci/hda/tas2781_hda_spi.c
rename to sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index c4b9a3c1a7f0..09a5d0f131b2 100644
--- a/sound/pci/hda/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -35,7 +35,7 @@
 #include "hda_auto_parser.h"
 #include "hda_component.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "../generic.h"
 #include "tas2781_hda.h"
 
 #define TASDEVICE_RANGE_MAX_SIZE	(256 * 128)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/hda/codecs/sigmatel.c
similarity index 99%
rename from sound/pci/hda/patch_sigmatel.c
rename to sound/hda/codecs/sigmatel.c
index bde6b7373858..56274ff49b0b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/hda/codecs/sigmatel.c
@@ -7,7 +7,7 @@
  * Copyright (c) 2005 Embedded Alley Solutions, Inc.
  * Matt Porter <mporter@embeddedalley.com>
  *
- * Based on patch_cmedia.c and patch_realtek.c
+ * Based on cmedia.c and realtek.c
  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
  */
 
@@ -24,7 +24,7 @@
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 enum {
 	STAC_REF,
diff --git a/sound/pci/hda/patch_via.c b/sound/hda/codecs/via.c
similarity index 99%
rename from sound/pci/hda/patch_via.c
rename to sound/hda/codecs/via.c
index d0893059b1b9..e3ce563f866b 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/hda/codecs/via.c
@@ -43,7 +43,7 @@
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
-#include "hda_generic.h"
+#include "generic.h"
 
 /* Pin Widget NID */
 #define VT1708_HP_PIN_NID	0x20
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 787868c9e91b..e0996a9d90b0 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -933,5 +933,3 @@ config SND_YMFPCI
 	  will be called snd-ymfpci.
 
 endif	# SND_PCI
-
-source "sound/pci/hda/Kconfig"
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index 18b673018dfd..9d5e8e12ae73 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -69,7 +69,6 @@ obj-$(CONFIG_SND) += \
 	lx6464es/ \
 	echoaudio/ \
 	emu10k1/ \
-	hda/ \
 	ice1712/ \
 	korg1212/ \
 	mixart/ \
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
deleted file mode 100644
index 79de0af71ad4..000000000000
--- a/sound/pci/hda/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-subdir-ccflags-y += -I$(src)/../../hda/common
-
-snd-hda-codec-generic-y :=	hda_generic.o
-snd-hda-codec-realtek-y :=	patch_realtek.o
-snd-hda-codec-cmedia-y :=	patch_cmedia.o
-snd-hda-codec-analog-y :=	patch_analog.o
-snd-hda-codec-idt-y :=		patch_sigmatel.o
-snd-hda-codec-si3054-y :=	patch_si3054.o
-snd-hda-codec-cirrus-y :=	patch_cirrus.o
-snd-hda-codec-cs8409-y :=	patch_cs8409.o patch_cs8409-tables.o
-snd-hda-codec-ca0110-y :=	patch_ca0110.o
-snd-hda-codec-ca0132-y :=	patch_ca0132.o
-snd-hda-codec-conexant-y :=	patch_conexant.o
-snd-hda-codec-senarytech-y :=patch_senarytech.o
-snd-hda-codec-via-y :=		patch_via.o
-snd-hda-codec-hdmi-y :=		patch_hdmi.o hda_eld.o
-
-# side codecs
-snd-hda-cirrus-scodec-y :=	cirrus_scodec.o
-snd-hda-cirrus-scodec-test-y :=	cirrus_scodec_test.o
-snd-hda-scodec-cs35l41-y :=	cs35l41_hda.o cs35l41_hda_property.o
-snd-hda-scodec-cs35l41-i2c-y :=	cs35l41_hda_i2c.o
-snd-hda-scodec-cs35l41-spi-y :=	cs35l41_hda_spi.o
-snd-hda-scodec-cs35l56-y :=	cs35l56_hda.o
-snd-hda-scodec-cs35l56-i2c-y :=	cs35l56_hda_i2c.o
-snd-hda-scodec-cs35l56-spi-y :=	cs35l56_hda_spi.o
-snd-hda-scodec-component-y :=	hda_component.o
-snd-hda-scodec-tas2781-y :=	tas2781_hda.o
-snd-hda-scodec-tas2781-i2c-y :=	tas2781_hda_i2c.o
-snd-hda-scodec-tas2781-spi-y :=	tas2781_hda_spi.o
-
-# codec drivers
-obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
-obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
-obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
-obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
-obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
-obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
-obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
-obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
-obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
-obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
-obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
-obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
-obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
-obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
-
-# side codecs
-obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
-obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.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_SCODEC_COMPONENT) += snd-hda-scodec-component.o
-obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
-obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
-obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 07/27] ALSA: hda: Split Realtek HD-audio codec driver
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (5 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-14  9:02   ` Cezary Rojewski
  2025-07-09 16:04 ` [PATCH 08/27] ALSA: hda/hdmi: Split vendor codec drivers Takashi Iwai
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

The snd-hda-codec-realtek driver supports many different codec models
and accumulated lots of quirks.  Now let's split it to multiple
modules per probe function, i.e. for ALC260, ALC262, ALC269, etc.

The common code and quirks are provided by the common library module,
snd-hda-codec-realtek-lib now.  One drawback of this action is that
many symbols have to be exported.  But they are limited with
SND_HDA_CODEC_REALTEK namespace, at least.

This patch tries to be idiomatic and doesn't try to rewrite the
existing code.  We can move the codec model-specific code into each
codec driver later.

The HD-audio sub-codec component binding is currently specific to
ALC269, hence the management is moved into alc269.c.
After that, alc_free() became identical with snd_hda_gen_free(), and
it's replaced as a macro just to call snd_hda_gen_free().

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/Kconfig                      |   14 +-
 sound/hda/codecs/Makefile                     |    5 +-
 sound/hda/codecs/realtek/Kconfig              |   90 +
 sound/hda/codecs/realtek/Makefile             |   26 +
 sound/hda/codecs/realtek/alc260.c             |  276 +
 sound/hda/codecs/realtek/alc262.c             |  199 +
 sound/hda/codecs/realtek/alc268.c             |  176 +
 .../codecs/{realtek.c => realtek/alc269.c}    | 5727 +----------------
 sound/hda/codecs/realtek/alc662.c             | 1102 ++++
 sound/hda/codecs/realtek/alc680.c             |   53 +
 sound/hda/codecs/realtek/alc861.c             |  149 +
 sound/hda/codecs/realtek/alc861vd.c           |  123 +
 sound/hda/codecs/realtek/alc880.c             |  497 ++
 sound/hda/codecs/realtek/alc882.c             |  847 +++
 sound/hda/codecs/realtek/realtek.c            | 2314 +++++++
 sound/hda/codecs/realtek/realtek.h            |  302 +
 16 files changed, 6191 insertions(+), 5709 deletions(-)
 create mode 100644 sound/hda/codecs/realtek/Kconfig
 create mode 100644 sound/hda/codecs/realtek/Makefile
 create mode 100644 sound/hda/codecs/realtek/alc260.c
 create mode 100644 sound/hda/codecs/realtek/alc262.c
 create mode 100644 sound/hda/codecs/realtek/alc268.c
 rename sound/hda/codecs/{realtek.c => realtek/alc269.c} (64%)
 create mode 100644 sound/hda/codecs/realtek/alc662.c
 create mode 100644 sound/hda/codecs/realtek/alc680.c
 create mode 100644 sound/hda/codecs/realtek/alc861.c
 create mode 100644 sound/hda/codecs/realtek/alc861vd.c
 create mode 100644 sound/hda/codecs/realtek/alc880.c
 create mode 100644 sound/hda/codecs/realtek/alc882.c
 create mode 100644 sound/hda/codecs/realtek/realtek.c
 create mode 100644 sound/hda/codecs/realtek/realtek.h

diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
index bac19a664be0..0bb675ab84fe 100644
--- a/sound/hda/codecs/Kconfig
+++ b/sound/hda/codecs/Kconfig
@@ -4,19 +4,6 @@ if SND_HDA
 config SND_HDA_GENERIC_LEDS
        bool
 
-config SND_HDA_CODEC_REALTEK
-	tristate "Build Realtek HD-audio codec support"
-	depends on INPUT
-	select SND_HDA_GENERIC
-	select SND_HDA_GENERIC_LEDS
-	select SND_HDA_SCODEC_COMPONENT
-	help
-	  Say Y or M here to include Realtek HD-audio codec support in
-	  snd-hda-intel driver, such as ALC880.
-
-comment "Set to Y if you want auto-loading the codec driver"
-	depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
-
 config SND_HDA_CODEC_ANALOG
 	tristate "Build Analog Devices HD-audio codec support"
 	select SND_HDA_GENERIC
@@ -162,6 +149,7 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
 	  This feature can impact power consumption as resources
 	  are kept reserved both at transmitter and receiver.
 
+source "sound/hda/codecs/realtek/Kconfig"
 source "sound/hda/codecs/cirrus/Kconfig"
 source "sound/hda/codecs/side-codecs/Kconfig"
 
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
index 205cd1373b42..14e5041aa4f0 100644
--- a/sound/hda/codecs/Makefile
+++ b/sound/hda/codecs/Makefile
@@ -2,30 +2,31 @@
 subdir-ccflags-y += -I$(src)/../common
 
 snd-hda-codec-generic-y :=	generic.o
+snd-hda-codec-cmedia-y :=	cmedia.o
 snd-hda-codec-analog-y :=	analog.o
 snd-hda-codec-ca0110-y :=	ca0110.o
 snd-hda-codec-ca0132-y :=	ca0132.o
 snd-hda-codec-cmedia-y :=	cmedia.o
 snd-hda-codec-conexant-y :=	conexant.o
 snd-hda-codec-idt-y :=		sigmatel.o
-snd-hda-codec-realtek-y :=	realtek.o
 snd-hda-codec-senarytech-y :=	senarytech.o
 snd-hda-codec-si3054-y :=	si3054.o
 snd-hda-codec-via-y :=		via.o
 
 obj-y += cirrus/
 obj-y += hdmi/
+obj-y += realtek/
 obj-y += side-codecs/
 
 # codec drivers
 obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
+obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
 obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
 obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
 obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
 obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
 obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
 obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
-obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
 obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
 obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
 obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
diff --git a/sound/hda/codecs/realtek/Kconfig b/sound/hda/codecs/realtek/Kconfig
new file mode 100644
index 000000000000..4b3ab28203b4
--- /dev/null
+++ b/sound/hda/codecs/realtek/Kconfig
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig SND_HDA_CODEC_REALTEK
+	bool "Realtek HD-audio codec support"
+
+if SND_HDA_CODEC_REALTEK
+
+config SND_HDA_CODEC_REALTEK_LIB
+	tristate
+	select SND_HDA_GENERIC
+	select SND_HDA_GENERIC_LEDS
+	select SND_HDA_SCODEC_COMPONENT
+
+config SND_HDA_CODEC_ALC260
+	tristate "Build Realtek ALC260 HD-audio codec support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC260 HD-audio codec support
+
+config SND_HDA_CODEC_ALC262
+	tristate "Build Realtek ALC262 HD-audio codec support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC262 HD-audio codec support
+
+config SND_HDA_CODEC_ALC268
+	tristate "Build Realtek ALC268 HD-audio codec support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC268 and compatible HD-audio
+	  codec support
+
+config SND_HDA_CODEC_ALC269
+	tristate "Build Realtek ALC269 HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC269 and compatible HD-audio
+	  codec support
+
+config SND_HDA_CODEC_ALC662
+	tristate "Build Realtek ALC662 HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC662 and compatible HD-audio
+	  codec support
+
+config SND_HDA_CODEC_ALC680
+	tristate "Build Realtek ALC680 HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC680 HD-audio codec support
+
+config SND_HDA_CODEC_ALC861
+	tristate "Build Realtek ALC861 HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC861 HD-audio codec support
+
+config SND_HDA_CODEC_ALC861VD
+	tristate "Build Realtek ALC861-VD HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC861-VD HD-audio codec support
+
+config SND_HDA_CODEC_ALC880
+	tristate "Build Realtek ALC880 HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC880 HD-audio codec support
+
+config SND_HDA_CODEC_ALC882
+	tristate "Build Realtek ALC882 HD-audio codecs support"
+	depends on INPUT
+	select SND_HDA_CODEC_REALTEK_LIB
+	help
+	  Say Y or M here to include Realtek ALC882 and compatible HD-audio
+	  codec support
+
+endif
+
+
diff --git a/sound/hda/codecs/realtek/Makefile b/sound/hda/codecs/realtek/Makefile
new file mode 100644
index 000000000000..c6ee4e526a40
--- /dev/null
+++ b/sound/hda/codecs/realtek/Makefile
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-realtek-lib-y :=	realtek.o
+snd-hda-codec-alc260-y :=	alc260.o
+snd-hda-codec-alc262-y :=	alc262.o
+snd-hda-codec-alc268-y :=	alc268.o
+snd-hda-codec-alc269-y :=	alc269.o
+snd-hda-codec-alc662-y :=	alc662.o
+snd-hda-codec-alc680-y :=	alc680.o
+snd-hda-codec-alc861-y :=	alc861.o
+snd-hda-codec-alc861vd-y :=	alc861vd.o
+snd-hda-codec-alc880-y :=	alc880.o
+snd-hda-codec-alc882-y :=	alc882.o
+
+obj-$(CONFIG_SND_HDA_CODEC_REALTEK_LIB) += snd-hda-codec-realtek-lib.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC260) += snd-hda-codec-alc260.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC262) += snd-hda-codec-alc262.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC268) += snd-hda-codec-alc268.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC269) += snd-hda-codec-alc269.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC662) += snd-hda-codec-alc662.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC680) += snd-hda-codec-alc680.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC861) += snd-hda-codec-alc861.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC861VD) += snd-hda-codec-alc861vd.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC880) += snd-hda-codec-alc880.o
+obj-$(CONFIG_SND_HDA_CODEC_ALC882) += snd-hda-codec-alc882.o
diff --git a/sound/hda/codecs/realtek/alc260.c b/sound/hda/codecs/realtek/alc260.c
new file mode 100644
index 000000000000..ebe20eaec58a
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc260.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC260 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc260_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
+	static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
+	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
+}
+
+/*
+ * Pin config fixes
+ */
+enum {
+	ALC260_FIXUP_HP_DC5750,
+	ALC260_FIXUP_HP_PIN_0F,
+	ALC260_FIXUP_COEF,
+	ALC260_FIXUP_GPIO1,
+	ALC260_FIXUP_GPIO1_TOGGLE,
+	ALC260_FIXUP_REPLACER,
+	ALC260_FIXUP_HP_B1900,
+	ALC260_FIXUP_KN1,
+	ALC260_FIXUP_FSC_S7020,
+	ALC260_FIXUP_FSC_S7020_JWSE,
+	ALC260_FIXUP_VAIO_PINS,
+};
+
+static void alc260_gpio1_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
+}
+
+static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
+				      const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		/* although the machine has only one output pin, we need to
+		 * toggle GPIO1 according to the jack state
+		 */
+		spec->gen.automute_hook = alc260_gpio1_automute;
+		spec->gen.detect_hp = 1;
+		spec->gen.automute_speaker = 1;
+		spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
+		snd_hda_jack_detect_enable_callback(codec, 0x0f,
+						    snd_hda_gen_hp_automute);
+		alc_setup_gpio(codec, 0x01);
+	}
+}
+
+static void alc260_fixup_kn1(struct hda_codec *codec,
+			     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	static const struct hda_pintbl pincfgs[] = {
+		{ 0x0f, 0x02214000 }, /* HP/speaker */
+		{ 0x12, 0x90a60160 }, /* int mic */
+		{ 0x13, 0x02a19000 }, /* ext mic */
+		{ 0x18, 0x01446000 }, /* SPDIF out */
+		/* disable bogus I/O pins */
+		{ 0x10, 0x411111f0 },
+		{ 0x11, 0x411111f0 },
+		{ 0x14, 0x411111f0 },
+		{ 0x15, 0x411111f0 },
+		{ 0x16, 0x411111f0 },
+		{ 0x17, 0x411111f0 },
+		{ 0x19, 0x411111f0 },
+		{ }
+	};
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		snd_hda_apply_pincfgs(codec, pincfgs);
+		spec->init_amp = ALC_INIT_NONE;
+		break;
+	}
+}
+
+static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		spec->init_amp = ALC_INIT_NONE;
+}
+
+static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.add_jack_modes = 1;
+		spec->gen.hp_mic = 1;
+	}
+}
+
+static const struct hda_fixup alc260_fixups[] = {
+	[ALC260_FIXUP_HP_DC5750] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x11, 0x90130110 }, /* speaker */
+			{ }
+		}
+	},
+	[ALC260_FIXUP_HP_PIN_0F] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x0f, 0x01214000 }, /* HP */
+			{ }
+		}
+	},
+	[ALC260_FIXUP_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
+			{ }
+		},
+	},
+	[ALC260_FIXUP_GPIO1] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio1,
+	},
+	[ALC260_FIXUP_GPIO1_TOGGLE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc260_fixup_gpio1_toggle,
+		.chained = true,
+		.chain_id = ALC260_FIXUP_HP_PIN_0F,
+	},
+	[ALC260_FIXUP_REPLACER] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
+	},
+	[ALC260_FIXUP_HP_B1900] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc260_fixup_gpio1_toggle,
+		.chained = true,
+		.chain_id = ALC260_FIXUP_COEF,
+	},
+	[ALC260_FIXUP_KN1] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc260_fixup_kn1,
+	},
+	[ALC260_FIXUP_FSC_S7020] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc260_fixup_fsc_s7020,
+	},
+	[ALC260_FIXUP_FSC_S7020_JWSE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc260_fixup_fsc_s7020_jwse,
+		.chained = true,
+		.chain_id = ALC260_FIXUP_FSC_S7020,
+	},
+	[ALC260_FIXUP_VAIO_PINS] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* Pin configs are missing completely on some VAIOs */
+			{ 0x0f, 0x01211020 },
+			{ 0x10, 0x0001003f },
+			{ 0x11, 0x411111f0 },
+			{ 0x12, 0x01a15930 },
+			{ 0x13, 0x411111f0 },
+			{ 0x14, 0x411111f0 },
+			{ 0x15, 0x411111f0 },
+			{ 0x16, 0x411111f0 },
+			{ 0x17, 0x411111f0 },
+			{ 0x18, 0x411111f0 },
+			{ 0x19, 0x411111f0 },
+			{ }
+		}
+	},
+};
+
+static const struct hda_quirk alc260_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
+	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
+	SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
+	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
+	SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
+	SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
+	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
+	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
+	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
+	{}
+};
+
+static const struct hda_model_fixup alc260_fixup_models[] = {
+	{.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
+	{.id = ALC260_FIXUP_COEF, .name = "coef"},
+	{.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
+	{.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
+	{}
+};
+
+/*
+ */
+static int patch_alc260(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x07);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+	/* as quite a few machines require HP amp for speaker outputs,
+	 * it's easier to enable it unconditionally; even if it's unneeded,
+	 * it's almost harmless.
+	 */
+	spec->gen.prefer_hp_amp = 1;
+	spec->gen.beep_nid = 0x01;
+
+	spec->shutup = alc_eapd_shutup;
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
+			   alc260_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	/* automatic parse from the BIOS config */
+	err = alc260_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog) {
+		err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc260[] = {
+	HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC260 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc260_driver = {
+	.id = snd_hda_id_alc260,
+};
+
+module_hda_codec_driver(alc260_driver);
diff --git a/sound/hda/codecs/realtek/alc262.c b/sound/hda/codecs/realtek/alc262.c
new file mode 100644
index 000000000000..ffe61f447667
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc262.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC262 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc262_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+	return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
+}
+
+/*
+ * Pin config fixes
+ */
+enum {
+	ALC262_FIXUP_FSC_H270,
+	ALC262_FIXUP_FSC_S7110,
+	ALC262_FIXUP_HP_Z200,
+	ALC262_FIXUP_TYAN,
+	ALC262_FIXUP_LENOVO_3000,
+	ALC262_FIXUP_BENQ,
+	ALC262_FIXUP_BENQ_T31,
+	ALC262_FIXUP_INV_DMIC,
+	ALC262_FIXUP_INTEL_BAYLEYBAY,
+};
+
+static const struct hda_fixup alc262_fixups[] = {
+	[ALC262_FIXUP_FSC_H270] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x15, 0x0221142f }, /* front HP */
+			{ 0x1b, 0x0121141f }, /* rear HP */
+			{ }
+		}
+	},
+	[ALC262_FIXUP_FSC_S7110] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x90170110 }, /* speaker */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC262_FIXUP_BENQ,
+	},
+	[ALC262_FIXUP_HP_Z200] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x99130120 }, /* internal speaker */
+			{ }
+		}
+	},
+	[ALC262_FIXUP_TYAN] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x1993e1f0 }, /* int AUX */
+			{ }
+		}
+	},
+	[ALC262_FIXUP_LENOVO_3000] = {
+		.type = HDA_FIXUP_PINCTLS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, PIN_VREF50 },
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC262_FIXUP_BENQ,
+	},
+	[ALC262_FIXUP_BENQ] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+			{}
+		}
+	},
+	[ALC262_FIXUP_BENQ_T31] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+			{}
+		}
+	},
+	[ALC262_FIXUP_INV_DMIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic,
+	},
+	[ALC262_FIXUP_INTEL_BAYLEYBAY] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_no_depop_delay,
+	},
+};
+
+static const struct hda_quirk alc262_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
+	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
+	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
+	SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
+	SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
+	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
+	SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
+	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
+	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
+	SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
+	{}
+};
+
+static const struct hda_model_fixup alc262_fixup_models[] = {
+	{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
+	{.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
+	{.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
+	{.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
+	{.id = ALC262_FIXUP_TYAN, .name = "tyan"},
+	{.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
+	{.id = ALC262_FIXUP_BENQ, .name = "benq"},
+	{.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
+	{.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
+	{}
+};
+
+/*
+ */
+static int patch_alc262(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+	spec->gen.shared_mic_vref_pin = 0x18;
+
+	spec->shutup = alc_eapd_shutup;
+
+#if 0
+	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
+	 * under-run
+	 */
+	alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
+#endif
+	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
+		       alc262_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	alc_auto_parse_customize_define(codec);
+
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
+	/* automatic parse from the BIOS config */
+	err = alc262_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog && spec->gen.beep_nid) {
+		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc262[] = {
+	HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC262 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc262_driver = {
+	.id = snd_hda_id_alc262,
+};
+
+module_hda_codec_driver(alc262_driver);
diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c
new file mode 100644
index 000000000000..d018f9982feb
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc268.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/* bind Beep switches of both NID 0x0f and 0x10 */
+static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned long pval;
+	int err;
+
+	mutex_lock(&codec->control_mutex);
+	pval = kcontrol->private_value;
+	kcontrol->private_value = (pval & ~0xff) | 0x0f;
+	err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+	if (err >= 0) {
+		kcontrol->private_value = (pval & ~0xff) | 0x10;
+		err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+	}
+	kcontrol->private_value = pval;
+	mutex_unlock(&codec->control_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new alc268_beep_mixer[] = {
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Beep Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc268_beep_switch_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
+	},
+};
+
+/* set PCBEEP vol = 0, mute connections */
+static const struct hda_verb alc268_beep_init_verbs[] = {
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{ }
+};
+
+enum {
+	ALC268_FIXUP_INV_DMIC,
+	ALC268_FIXUP_HP_EAPD,
+	ALC268_FIXUP_SPDIF,
+};
+
+static const struct hda_fixup alc268_fixups[] = {
+	[ALC268_FIXUP_INV_DMIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic,
+	},
+	[ALC268_FIXUP_HP_EAPD] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
+			{}
+		}
+	},
+	[ALC268_FIXUP_SPDIF] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x014b1180 }, /* enable SPDIF out */
+			{}
+		}
+	},
+};
+
+static const struct hda_model_fixup alc268_fixup_models[] = {
+	{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
+	{.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
+	{.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
+	{}
+};
+
+static const struct hda_quirk alc268_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
+	SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
+	/* below is codec SSID since multiple Toshiba laptops have the
+	 * same PCI SSID 1179:ff00
+	 */
+	SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
+	{}
+};
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+	return alc_parse_auto_config(codec, NULL, alc268_ssids);
+}
+
+/*
+ */
+static int patch_alc268(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int i, err;
+
+	/* ALC268 has no aa-loopback mixer */
+	err = alc_alloc_spec(codec, 0);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
+	spec->shutup = alc_eapd_shutup;
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	/* automatic parse from the BIOS config */
+	err = alc268_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (err > 0 && !spec->gen.no_analog &&
+	    spec->gen.autocfg.speaker_pins[0] != 0x1d) {
+		for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
+			if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+						  &alc268_beep_mixer[i])) {
+				err = -ENOMEM;
+				goto error;
+			}
+		}
+		snd_hda_add_verbs(codec, alc268_beep_init_verbs);
+		if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+			/* override the amp caps for beep generator */
+			snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+					  (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
+					  (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
+					  (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+					  (0 << AC_AMPCAP_MUTE_SHIFT));
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc268[] = {
+	HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
+	HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc268);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC267/268 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc268_driver = {
+	.id = snd_hda_id_alc268,
+};
+
+module_hda_codec_driver(alc268_driver);
diff --git a/sound/hda/codecs/realtek.c b/sound/hda/codecs/realtek/alc269.c
similarity index 64%
rename from sound/hda/codecs/realtek.c
rename to sound/hda/codecs/realtek/alc269.c
index 9c86c7bd1a90..325ba08e2981 100644
--- a/sound/hda/codecs/realtek.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -1,3160 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for Realtek ALC codecs
- *
- * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
- *                    PeiSen Hou <pshou@realtek.com.tw>
- *                    Takashi Iwai <tiwai@suse.de>
- *                    Jonathan Woithe <jwoithe@just42.net>
- */
+//
+// Realtek ALC269 and compatible codecs
+//
 
-#include <linux/acpi.h>
-#include <linux/cleanup.h>
 #include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/dmi.h>
 #include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/leds.h>
-#include <linux/ctype.h>
-#include <linux/spi/spi.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_beep.h"
-#include "hda_jack.h"
-#include "generic.h"
-#include "side-codecs/hda_component.h"
+#include "realtek.h"
 
 /* keep halting ALC5505 DSP, for power saving */
 #define HALT_REALTEK_ALC5505
 
-/* extra amp-initialization sequence types */
-enum {
-	ALC_INIT_UNDEFINED,
-	ALC_INIT_NONE,
-	ALC_INIT_DEFAULT,
-};
-
-enum {
-	ALC_HEADSET_MODE_UNKNOWN,
-	ALC_HEADSET_MODE_UNPLUGGED,
-	ALC_HEADSET_MODE_HEADSET,
-	ALC_HEADSET_MODE_MIC,
-	ALC_HEADSET_MODE_HEADPHONE,
-};
-
-enum {
-	ALC_HEADSET_TYPE_UNKNOWN,
-	ALC_HEADSET_TYPE_CTIA,
-	ALC_HEADSET_TYPE_OMTP,
-};
-
-enum {
-	ALC_KEY_MICMUTE_INDEX,
-};
-
-struct alc_customize_define {
-	unsigned int  sku_cfg;
-	unsigned char port_connectivity;
-	unsigned char check_sum;
-	unsigned char customization;
-	unsigned char external_amp;
-	unsigned int  enable_pcbeep:1;
-	unsigned int  platform_type:1;
-	unsigned int  swap:1;
-	unsigned int  override:1;
-	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
-};
-
-struct alc_coef_led {
-	unsigned int idx;
-	unsigned int mask;
-	unsigned int on;
-	unsigned int off;
-};
-
-struct alc_spec {
-	struct hda_gen_spec gen; /* must be at head */
-
-	/* codec parameterization */
-	struct alc_customize_define cdefine;
-	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
-
-	/* GPIO bits */
-	unsigned int gpio_mask;
-	unsigned int gpio_dir;
-	unsigned int gpio_data;
-	bool gpio_write_delay;	/* add a delay before writing gpio_data */
-
-	/* mute LED for HP laptops, see vref_mute_led_set() */
-	int mute_led_polarity;
-	int micmute_led_polarity;
-	hda_nid_t mute_led_nid;
-	hda_nid_t cap_mute_led_nid;
-
-	unsigned int gpio_mute_led_mask;
-	unsigned int gpio_mic_led_mask;
-	struct alc_coef_led mute_led_coef;
-	struct alc_coef_led mic_led_coef;
-	struct mutex coef_mutex;
-
-	hda_nid_t headset_mic_pin;
-	hda_nid_t headphone_mic_pin;
-	int current_headset_mode;
-	int current_headset_type;
-
-	/* hooks */
-	void (*init_hook)(struct hda_codec *codec);
-	void (*power_hook)(struct hda_codec *codec);
-	void (*shutup)(struct hda_codec *codec);
-
-	int init_amp;
-	int codec_variant;	/* flag for other variants */
-	unsigned int has_alc5505_dsp:1;
-	unsigned int no_depop_delay:1;
-	unsigned int done_hp_init:1;
-	unsigned int no_shutup_pins:1;
-	unsigned int ultra_low_power:1;
-	unsigned int has_hs_key:1;
-	unsigned int no_internal_mic_pin:1;
-	unsigned int en_3kpull_low:1;
-	int num_speaker_amps;
-
-	/* for PLL fix */
-	hda_nid_t pll_nid;
-	unsigned int pll_coef_idx, pll_coef_bit;
-	unsigned int coef0;
-	struct input_dev *kb_dev;
-	u8 alc_mute_keycode_map[1];
-
-	/* component binding */
-	struct hda_component_parent comps;
-};
-
-/*
- * COEF access helper functions
- */
-
-static void coef_mutex_lock(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	snd_hda_power_up_pm(codec);
-	mutex_lock(&spec->coef_mutex);
-}
-
-static void coef_mutex_unlock(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	mutex_unlock(&spec->coef_mutex);
-	snd_hda_power_down_pm(codec);
-}
-
-static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-				 unsigned int coef_idx)
-{
-	unsigned int val;
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
-	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
-	return val;
-}
-
-static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-			       unsigned int coef_idx)
-{
-	unsigned int val;
-
-	coef_mutex_lock(codec);
-	val = __alc_read_coefex_idx(codec, nid, coef_idx);
-	coef_mutex_unlock(codec);
-	return val;
-}
-
-#define alc_read_coef_idx(codec, coef_idx) \
-	alc_read_coefex_idx(codec, 0x20, coef_idx)
-
-static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-				   unsigned int coef_idx, unsigned int coef_val)
-{
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
-}
-
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-				 unsigned int coef_idx, unsigned int coef_val)
-{
-	coef_mutex_lock(codec);
-	__alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
-	coef_mutex_unlock(codec);
-}
-
-#define alc_write_coef_idx(codec, coef_idx, coef_val) \
-	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
-
-static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-				    unsigned int coef_idx, unsigned int mask,
-				    unsigned int bits_set)
-{
-	unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
-
-	if (val != -1)
-		__alc_write_coefex_idx(codec, nid, coef_idx,
-				       (val & ~mask) | bits_set);
-}
-
-static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-				  unsigned int coef_idx, unsigned int mask,
-				  unsigned int bits_set)
-{
-	coef_mutex_lock(codec);
-	__alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
-	coef_mutex_unlock(codec);
-}
-
-#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)	\
-	alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
-
-/* a special bypass for COEF 0; read the cached value at the second time */
-static unsigned int alc_get_coef0(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (!spec->coef0)
-		spec->coef0 = alc_read_coef_idx(codec, 0);
-	return spec->coef0;
-}
-
-/* coef writes/updates batch */
-struct coef_fw {
-	unsigned char nid;
-	unsigned char idx;
-	unsigned short mask;
-	unsigned short val;
-};
-
-#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
-	{ .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
-#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
-#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
-#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
-
-static void alc_process_coef_fw(struct hda_codec *codec,
-				const struct coef_fw *fw)
-{
-	coef_mutex_lock(codec);
-	for (; fw->nid; fw++) {
-		if (fw->mask == (unsigned short)-1)
-			__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
-		else
-			__alc_update_coefex_idx(codec, fw->nid, fw->idx,
-						fw->mask, fw->val);
-	}
-	coef_mutex_unlock(codec);
-}
-
-/*
- * GPIO setup tables, used in initialization
- */
-
-/* Enable GPIO mask and set output */
-static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->gpio_mask |= mask;
-	spec->gpio_dir |= mask;
-	spec->gpio_data |= mask;
-}
-
-static void alc_write_gpio_data(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-			    spec->gpio_data);
-}
-
-static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
-				 bool on)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int oldval = spec->gpio_data;
-
-	if (on)
-		spec->gpio_data |= mask;
-	else
-		spec->gpio_data &= ~mask;
-	if (oldval != spec->gpio_data)
-		alc_write_gpio_data(codec);
-}
-
-static void alc_write_gpio(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (!spec->gpio_mask)
-		return;
-
-	snd_hda_codec_write(codec, codec->core.afg, 0,
-			    AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
-	snd_hda_codec_write(codec, codec->core.afg, 0,
-			    AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
-	if (spec->gpio_write_delay)
-		msleep(1);
-	alc_write_gpio_data(codec);
-}
-
-static void alc_fixup_gpio(struct hda_codec *codec, int action,
-			   unsigned int mask)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		alc_setup_gpio(codec, mask);
-}
-
-static void alc_fixup_gpio1(struct hda_codec *codec,
-			    const struct hda_fixup *fix, int action)
-{
-	alc_fixup_gpio(codec, action, 0x01);
-}
-
-static void alc_fixup_gpio2(struct hda_codec *codec,
-			    const struct hda_fixup *fix, int action)
-{
-	alc_fixup_gpio(codec, action, 0x02);
-}
-
-static void alc_fixup_gpio3(struct hda_codec *codec,
-			    const struct hda_fixup *fix, int action)
-{
-	alc_fixup_gpio(codec, action, 0x03);
-}
-
-static void alc_fixup_gpio4(struct hda_codec *codec,
-			    const struct hda_fixup *fix, int action)
-{
-	alc_fixup_gpio(codec, action, 0x04);
-}
-
-static void alc_fixup_micmute_led(struct hda_codec *codec,
-				  const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		snd_hda_gen_add_micmute_led_cdev(codec, NULL);
-}
-
-/*
- * Fix hardware PLL issue
- * On some codecs, the analog PLL gating control must be off while
- * the default value is 1.
- */
-static void alc_fix_pll(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (spec->pll_nid)
-		alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
-				      1 << spec->pll_coef_bit, 0);
-}
-
-static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
-			     unsigned int coef_idx, unsigned int coef_bit)
-{
-	struct alc_spec *spec = codec->spec;
-	spec->pll_nid = nid;
-	spec->pll_coef_idx = coef_idx;
-	spec->pll_coef_bit = coef_bit;
-	alc_fix_pll(codec);
-}
-
-/* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec,
-				   struct hda_jack_callback *jack)
-{
-	unsigned int val;
-	struct snd_kcontrol *kctl;
-	struct snd_ctl_elem_value *uctl;
-
-	kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
-	if (!kctl)
-		return;
-	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
-	if (!uctl)
-		return;
-	val = snd_hda_codec_read(codec, jack->nid, 0,
-				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
-	val &= HDA_AMP_VOLMASK;
-	uctl->value.integer.value[0] = val;
-	uctl->value.integer.value[1] = val;
-	kctl->put(kctl, uctl);
-	kfree(uctl);
-}
-
-static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	/* For some reason, the res given from ALC880 is broken.
-	   Here we adjust it properly. */
-	snd_hda_jack_unsol_event(codec, res >> 2);
-}
-
-/* Change EAPD to verb control */
-static void alc_fill_eapd_coef(struct hda_codec *codec)
-{
-	int coef;
-
-	coef = alc_get_coef0(codec);
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0262:
-		alc_update_coef_idx(codec, 0x7, 0, 1<<5);
-		break;
-	case 0x10ec0267:
-	case 0x10ec0268:
-		alc_update_coef_idx(codec, 0x7, 0, 1<<13);
-		break;
-	case 0x10ec0269:
-		if ((coef & 0x00f0) == 0x0010)
-			alc_update_coef_idx(codec, 0xd, 0, 1<<14);
-		if ((coef & 0x00f0) == 0x0020)
-			alc_update_coef_idx(codec, 0x4, 1<<15, 0);
-		if ((coef & 0x00f0) == 0x0030)
-			alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-		break;
-	case 0x10ec0280:
-	case 0x10ec0284:
-	case 0x10ec0290:
-	case 0x10ec0292:
-		alc_update_coef_idx(codec, 0x4, 1<<15, 0);
-		break;
-	case 0x10ec0225:
-	case 0x10ec0295:
-	case 0x10ec0299:
-		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
-		fallthrough;
-	case 0x10ec0215:
-	case 0x10ec0236:
-	case 0x10ec0245:
-	case 0x10ec0256:
-	case 0x10ec0257:
-	case 0x10ec0285:
-	case 0x10ec0289:
-		alc_update_coef_idx(codec, 0x36, 1<<13, 0);
-		fallthrough;
-	case 0x10ec0230:
-	case 0x10ec0233:
-	case 0x10ec0235:
-	case 0x10ec0255:
-	case 0x19e58326:
-	case 0x10ec0282:
-	case 0x10ec0283:
-	case 0x10ec0286:
-	case 0x10ec0288:
-	case 0x10ec0298:
-	case 0x10ec0300:
-		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-		break;
-	case 0x10ec0275:
-		alc_update_coef_idx(codec, 0xe, 0, 1<<0);
-		break;
-	case 0x10ec0287:
-		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-		alc_write_coef_idx(codec, 0x8, 0x4ab7);
-		break;
-	case 0x10ec0293:
-		alc_update_coef_idx(codec, 0xa, 1<<13, 0);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-		alc_write_coef_idx(codec, 0x6e, 0x0c25);
-		fallthrough;
-	case 0x10ec0294:
-	case 0x10ec0700:
-	case 0x10ec0701:
-	case 0x10ec0703:
-	case 0x10ec0711:
-		alc_update_coef_idx(codec, 0x10, 1<<15, 0);
-		break;
-	case 0x10ec0662:
-		if ((coef & 0x00f0) == 0x0030)
-			alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
-		break;
-	case 0x10ec0272:
-	case 0x10ec0273:
-	case 0x10ec0663:
-	case 0x10ec0665:
-	case 0x10ec0670:
-	case 0x10ec0671:
-	case 0x10ec0672:
-		alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
-		break;
-	case 0x10ec0222:
-	case 0x10ec0623:
-		alc_update_coef_idx(codec, 0x19, 1<<13, 0);
-		break;
-	case 0x10ec0668:
-		alc_update_coef_idx(codec, 0x7, 3<<13, 0);
-		break;
-	case 0x10ec0867:
-		alc_update_coef_idx(codec, 0x4, 1<<10, 0);
-		break;
-	case 0x10ec0888:
-		if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
-			alc_update_coef_idx(codec, 0x7, 1<<5, 0);
-		break;
-	case 0x10ec0892:
-	case 0x10ec0897:
-		alc_update_coef_idx(codec, 0x7, 1<<5, 0);
-		break;
-	case 0x10ec0899:
-	case 0x10ec0900:
-	case 0x10ec0b00:
-	case 0x10ec1168:
-	case 0x10ec1220:
-		alc_update_coef_idx(codec, 0x7, 1<<1, 0);
-		break;
-	}
-}
-
-/* additional initialization for ALC888 variants */
-static void alc888_coef_init(struct hda_codec *codec)
-{
-	switch (alc_get_coef0(codec) & 0x00f0) {
-	/* alc888-VA */
-	case 0x00:
-	/* alc888-VB */
-	case 0x10:
-		alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
-		break;
-	}
-}
-
-/* turn on/off EAPD control (only if available) */
-static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
-{
-	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
-		return;
-	if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
-				    on ? 2 : 0);
-}
-
-/* turn on/off EAPD controls of the codec */
-static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
-{
-	/* We currently only handle front, HP */
-	static const hda_nid_t pins[] = {
-		0x0f, 0x10, 0x14, 0x15, 0x17, 0
-	};
-	const hda_nid_t *p;
-	for (p = pins; *p; p++)
-		set_eapd(codec, *p, on);
-}
-
-static int find_ext_mic_pin(struct hda_codec *codec);
-
-static void alc_headset_mic_no_shutup(struct hda_codec *codec)
-{
-	const struct hda_pincfg *pin;
-	int mic_pin = find_ext_mic_pin(codec);
-	int i;
-
-	/* don't shut up pins when unloading the driver; otherwise it breaks
-	 * the default pin setup at the next load of the driver
-	 */
-	if (codec->bus->shutdown)
-		return;
-
-	snd_array_for_each(&codec->init_pins, i, pin) {
-		/* use read here for syncing after issuing each verb */
-		if (pin->nid != mic_pin)
-			snd_hda_codec_read(codec, pin->nid, 0,
-					AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-	}
-
-	codec->pins_shutup = 1;
-}
-
-static void alc_shutup_pins(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (spec->no_shutup_pins)
-		return;
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x10ec0257:
-	case 0x19e58326:
-	case 0x10ec0283:
-	case 0x10ec0285:
-	case 0x10ec0286:
-	case 0x10ec0287:
-	case 0x10ec0288:
-	case 0x10ec0295:
-	case 0x10ec0298:
-		alc_headset_mic_no_shutup(codec);
-		break;
-	default:
-		snd_hda_shutup_pins(codec);
-		break;
-	}
-}
-
-/* generic shutup callback;
- * just turning off EAPD and a little pause for avoiding pop-noise
- */
-static void alc_eapd_shutup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	alc_auto_setup_eapd(codec, false);
-	if (!spec->no_depop_delay)
-		msleep(200);
-	alc_shutup_pins(codec);
-}
-
-/* generic EAPD initialization */
-static void alc_auto_init_amp(struct hda_codec *codec, int type)
-{
-	alc_auto_setup_eapd(codec, true);
-	alc_write_gpio(codec);
-	switch (type) {
-	case ALC_INIT_DEFAULT:
-		switch (codec->core.vendor_id) {
-		case 0x10ec0260:
-			alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
-			break;
-		case 0x10ec0880:
-		case 0x10ec0882:
-		case 0x10ec0883:
-		case 0x10ec0885:
-			alc_update_coef_idx(codec, 7, 0, 0x2030);
-			break;
-		case 0x10ec0888:
-			alc888_coef_init(codec);
-			break;
-		}
-		break;
-	}
-}
-
-/* get a primary headphone pin if available */
-static hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
-{
-	if (spec->gen.autocfg.hp_pins[0])
-		return spec->gen.autocfg.hp_pins[0];
-	if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
-		return spec->gen.autocfg.line_out_pins[0];
-	return 0;
-}
-
-/*
- * Realtek SSID verification
- */
-
-/* Could be any non-zero and even value. When used as fixup, tells
- * the driver to ignore any present sku defines.
- */
-#define ALC_FIXUP_SKU_IGNORE (2)
-
-static void alc_fixup_sku_ignore(struct hda_codec *codec,
-				 const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->cdefine.fixup = 1;
-		spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
-	}
-}
-
-static void alc_fixup_no_depop_delay(struct hda_codec *codec,
-				    const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (action == HDA_FIXUP_ACT_PROBE) {
-		spec->no_depop_delay = 1;
-		codec->depop_delay = 0;
-	}
-}
-
-static int alc_auto_parse_customize_define(struct hda_codec *codec)
-{
-	unsigned int ass, tmp, i;
-	unsigned nid = 0;
-	struct alc_spec *spec = codec->spec;
-
-	spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
-
-	if (spec->cdefine.fixup) {
-		ass = spec->cdefine.sku_cfg;
-		if (ass == ALC_FIXUP_SKU_IGNORE)
-			return -1;
-		goto do_sku;
-	}
-
-	if (!codec->bus->pci)
-		return -1;
-	ass = codec->core.subsystem_id & 0xffff;
-	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
-		goto do_sku;
-
-	nid = 0x1d;
-	if (codec->core.vendor_id == 0x10ec0260)
-		nid = 0x17;
-	ass = snd_hda_codec_get_pincfg(codec, nid);
-
-	if (!(ass & 1)) {
-		codec_info(codec, "%s: SKU not ready 0x%08x\n",
-			   codec->core.chip_name, ass);
-		return -1;
-	}
-
-	/* check sum */
-	tmp = 0;
-	for (i = 1; i < 16; i++) {
-		if ((ass >> i) & 1)
-			tmp++;
-	}
-	if (((ass >> 16) & 0xf) != tmp)
-		return -1;
-
-	spec->cdefine.port_connectivity = ass >> 30;
-	spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
-	spec->cdefine.check_sum = (ass >> 16) & 0xf;
-	spec->cdefine.customization = ass >> 8;
-do_sku:
-	spec->cdefine.sku_cfg = ass;
-	spec->cdefine.external_amp = (ass & 0x38) >> 3;
-	spec->cdefine.platform_type = (ass & 0x4) >> 2;
-	spec->cdefine.swap = (ass & 0x2) >> 1;
-	spec->cdefine.override = ass & 0x1;
-
-	codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
-		   nid, spec->cdefine.sku_cfg);
-	codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
-		   spec->cdefine.port_connectivity);
-	codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
-	codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
-	codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
-	codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
-	codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
-	codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
-	codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
-
-	return 0;
-}
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-	int i;
-	for (i = 0; i < nums; i++)
-		if (list[i] == nid)
-			return i;
-	return -1;
-}
-/* return true if the given NID is found in the list */
-static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-	return find_idx_in_nid_list(nid, list, nums) >= 0;
-}
-
-/* check subsystem ID and set up device-specific initialization;
- * return 1 if initialized, 0 if invalid SSID
- */
-/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
- *	31 ~ 16 :	Manufacture ID
- *	15 ~ 8	:	SKU ID
- *	7  ~ 0	:	Assembly ID
- *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
- */
-static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
-{
-	unsigned int ass, tmp, i;
-	unsigned nid;
-	struct alc_spec *spec = codec->spec;
-
-	if (spec->cdefine.fixup) {
-		ass = spec->cdefine.sku_cfg;
-		if (ass == ALC_FIXUP_SKU_IGNORE)
-			return 0;
-		goto do_sku;
-	}
-
-	ass = codec->core.subsystem_id & 0xffff;
-	if (codec->bus->pci &&
-	    ass != codec->bus->pci->subsystem_device && (ass & 1))
-		goto do_sku;
-
-	/* invalid SSID, check the special NID pin defcfg instead */
-	/*
-	 * 31~30	: port connectivity
-	 * 29~21	: reserve
-	 * 20		: PCBEEP input
-	 * 19~16	: Check sum (15:1)
-	 * 15~1		: Custom
-	 * 0		: override
-	*/
-	nid = 0x1d;
-	if (codec->core.vendor_id == 0x10ec0260)
-		nid = 0x17;
-	ass = snd_hda_codec_get_pincfg(codec, nid);
-	codec_dbg(codec,
-		  "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
-		   ass, nid);
-	if (!(ass & 1))
-		return 0;
-	if ((ass >> 30) != 1)	/* no physical connection */
-		return 0;
-
-	/* check sum */
-	tmp = 0;
-	for (i = 1; i < 16; i++) {
-		if ((ass >> i) & 1)
-			tmp++;
-	}
-	if (((ass >> 16) & 0xf) != tmp)
-		return 0;
-do_sku:
-	codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
-		   ass & 0xffff, codec->core.vendor_id);
-	/*
-	 * 0 : override
-	 * 1 :	Swap Jack
-	 * 2 : 0 --> Desktop, 1 --> Laptop
-	 * 3~5 : External Amplifier control
-	 * 7~6 : Reserved
-	*/
-	tmp = (ass & 0x38) >> 3;	/* external Amp control */
-	if (spec->init_amp == ALC_INIT_UNDEFINED) {
-		switch (tmp) {
-		case 1:
-			alc_setup_gpio(codec, 0x01);
-			break;
-		case 3:
-			alc_setup_gpio(codec, 0x02);
-			break;
-		case 7:
-			alc_setup_gpio(codec, 0x04);
-			break;
-		case 5:
-		default:
-			spec->init_amp = ALC_INIT_DEFAULT;
-			break;
-		}
-	}
-
-	/* is laptop or Desktop and enable the function "Mute internal speaker
-	 * when the external headphone out jack is plugged"
-	 */
-	if (!(ass & 0x8000))
-		return 1;
-	/*
-	 * 10~8 : Jack location
-	 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
-	 * 14~13: Resvered
-	 * 15   : 1 --> enable the function "Mute internal speaker
-	 *	        when the external headphone out jack is plugged"
-	 */
-	if (!alc_get_hp_pin(spec)) {
-		hda_nid_t nid;
-		tmp = (ass >> 11) & 0x3;	/* HP to chassis */
-		nid = ports[tmp];
-		if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
-				      spec->gen.autocfg.line_outs))
-			return 1;
-		spec->gen.autocfg.hp_pins[0] = nid;
-	}
-	return 1;
-}
-
-/* Check the validity of ALC subsystem-id
- * ports contains an array of 4 pin NIDs for port-A, E, D and I */
-static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
-{
-	if (!alc_subsystem_id(codec, ports)) {
-		struct alc_spec *spec = codec->spec;
-		if (spec->init_amp == ALC_INIT_UNDEFINED) {
-			codec_dbg(codec,
-				  "realtek: Enable default setup for auto mode as fallback\n");
-			spec->init_amp = ALC_INIT_DEFAULT;
-		}
-	}
-}
-
-/* inverted digital-mic */
-static void alc_fixup_inv_dmic(struct hda_codec *codec,
-			       const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->gen.inv_dmic_split = 1;
-}
-
-
-static int alc_build_controls(struct hda_codec *codec)
-{
-	int err;
-
-	err = snd_hda_gen_build_controls(codec);
-	if (err < 0)
-		return err;
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
-	return 0;
-}
-
-
-/*
- * Common callbacks
- */
-
-static void alc_pre_init(struct hda_codec *codec)
-{
-	alc_fill_eapd_coef(codec);
-}
-
-#define is_s3_resume(codec) \
-	((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
-#define is_s4_resume(codec) \
-	((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
-#define is_s4_suspend(codec) \
-	((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
-
-static int alc_init(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	/* hibernation resume needs the full chip initialization */
-	if (is_s4_resume(codec))
-		alc_pre_init(codec);
-
-	if (spec->init_hook)
-		spec->init_hook(codec);
-
-	spec->gen.skip_verbs = 1; /* applied in below */
-	snd_hda_gen_init(codec);
-	alc_fix_pll(codec);
-	alc_auto_init_amp(codec, spec->init_amp);
-	snd_hda_apply_verbs(codec); /* apply verbs here after own init */
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-	return 0;
-}
-
-/* forward declaration */
-static const struct component_master_ops comp_master_ops;
-
-static void alc_free(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (spec)
-		hda_component_manager_free(&spec->comps, &comp_master_ops);
-
-	snd_hda_gen_free(codec);
-}
-
-static inline void alc_shutup(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (!snd_hda_get_bool_hint(codec, "shutup"))
-		return; /* disabled explicitly by hints */
-
-	if (spec && spec->shutup)
-		spec->shutup(codec);
-	else
-		alc_shutup_pins(codec);
-}
-
-static void alc_power_eapd(struct hda_codec *codec)
-{
-	alc_auto_setup_eapd(codec, false);
-}
-
-static int alc_suspend(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	alc_shutup(codec);
-	if (spec && spec->power_hook)
-		spec->power_hook(codec);
-	return 0;
-}
-
-static int alc_resume(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (!spec->no_depop_delay)
-		msleep(150); /* to avoid pop noise */
-	codec->patch_ops.init(codec);
-	snd_hda_regmap_sync(codec);
-	hda_call_check_power_status(codec, 0x01);
-	return 0;
-}
-
-/*
- */
-static const struct hda_codec_ops alc_patch_ops = {
-	.build_controls = alc_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = alc_init,
-	.free = alc_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.resume = alc_resume,
-	.suspend = alc_suspend,
-	.check_power_status = snd_hda_gen_check_power_status,
-};
-
-
-#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
-
-/*
- * Rename codecs appropriately from COEF value or subvendor id
- */
-struct alc_codec_rename_table {
-	unsigned int vendor_id;
-	unsigned short coef_mask;
-	unsigned short coef_bits;
-	const char *name;
-};
-
-struct alc_codec_rename_pci_table {
-	unsigned int codec_vendor_id;
-	unsigned short pci_subvendor;
-	unsigned short pci_subdevice;
-	const char *name;
-};
-
-static const struct alc_codec_rename_table rename_tbl[] = {
-	{ 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
-	{ 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
-	{ 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
-	{ 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
-	{ 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
-	{ 0x10ec0269, 0xffff, 0xa023, "ALC259" },
-	{ 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
-	{ 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
-	{ 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
-	{ 0x10ec0662, 0xffff, 0x4020, "ALC656" },
-	{ 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
-	{ 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
-	{ 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
-	{ 0x10ec0899, 0x2000, 0x2000, "ALC899" },
-	{ 0x10ec0892, 0xffff, 0x8020, "ALC661" },
-	{ 0x10ec0892, 0xffff, 0x8011, "ALC661" },
-	{ 0x10ec0892, 0xffff, 0x4011, "ALC656" },
-	{ } /* terminator */
-};
-
-static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
-	{ 0x10ec0280, 0x1028, 0, "ALC3220" },
-	{ 0x10ec0282, 0x1028, 0, "ALC3221" },
-	{ 0x10ec0283, 0x1028, 0, "ALC3223" },
-	{ 0x10ec0288, 0x1028, 0, "ALC3263" },
-	{ 0x10ec0292, 0x1028, 0, "ALC3226" },
-	{ 0x10ec0293, 0x1028, 0, "ALC3235" },
-	{ 0x10ec0255, 0x1028, 0, "ALC3234" },
-	{ 0x10ec0668, 0x1028, 0, "ALC3661" },
-	{ 0x10ec0275, 0x1028, 0, "ALC3260" },
-	{ 0x10ec0899, 0x1028, 0, "ALC3861" },
-	{ 0x10ec0298, 0x1028, 0, "ALC3266" },
-	{ 0x10ec0236, 0x1028, 0, "ALC3204" },
-	{ 0x10ec0256, 0x1028, 0, "ALC3246" },
-	{ 0x10ec0225, 0x1028, 0, "ALC3253" },
-	{ 0x10ec0295, 0x1028, 0, "ALC3254" },
-	{ 0x10ec0299, 0x1028, 0, "ALC3271" },
-	{ 0x10ec0670, 0x1025, 0, "ALC669X" },
-	{ 0x10ec0676, 0x1025, 0, "ALC679X" },
-	{ 0x10ec0282, 0x1043, 0, "ALC3229" },
-	{ 0x10ec0233, 0x1043, 0, "ALC3236" },
-	{ 0x10ec0280, 0x103c, 0, "ALC3228" },
-	{ 0x10ec0282, 0x103c, 0, "ALC3227" },
-	{ 0x10ec0286, 0x103c, 0, "ALC3242" },
-	{ 0x10ec0290, 0x103c, 0, "ALC3241" },
-	{ 0x10ec0668, 0x103c, 0, "ALC3662" },
-	{ 0x10ec0283, 0x17aa, 0, "ALC3239" },
-	{ 0x10ec0292, 0x17aa, 0, "ALC3232" },
-	{ 0x10ec0257, 0x12f0, 0, "ALC3328" },
-	{ } /* terminator */
-};
-
-static int alc_codec_rename_from_preset(struct hda_codec *codec)
-{
-	const struct alc_codec_rename_table *p;
-	const struct alc_codec_rename_pci_table *q;
-
-	for (p = rename_tbl; p->vendor_id; p++) {
-		if (p->vendor_id != codec->core.vendor_id)
-			continue;
-		if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
-			return alc_codec_rename(codec, p->name);
-	}
-
-	if (!codec->bus->pci)
-		return 0;
-	for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
-		if (q->codec_vendor_id != codec->core.vendor_id)
-			continue;
-		if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
-			continue;
-		if (!q->pci_subdevice ||
-		    q->pci_subdevice == codec->bus->pci->subsystem_device)
-			return alc_codec_rename(codec, q->name);
-	}
-
-	return 0;
-}
-
-
-/*
- * Digital-beep handlers
- */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-
-/* additional beep mixers; private_value will be overwritten */
-static const struct snd_kcontrol_new alc_beep_mixer[] = {
-	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
-	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
-};
-
-/* set up and create beep controls */
-static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
-			int idx, int dir)
-{
-	struct snd_kcontrol_new *knew;
-	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
-		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
-					    &alc_beep_mixer[i]);
-		if (!knew)
-			return -ENOMEM;
-		knew->private_value = beep_amp;
-	}
-	return 0;
-}
-
-static const struct snd_pci_quirk beep_allow_list[] = {
-	SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
-	SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
-	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
-	SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
-	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
-	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
-	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
-	SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
-	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
-	/* denylist -- no beep available */
-	SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
-	SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
-	{}
-};
-
-static inline int has_cdefine_beep(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	const struct snd_pci_quirk *q;
-	q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
-	if (q)
-		return q->value;
-	return spec->cdefine.enable_pcbeep;
-}
-#else
-#define set_beep_amp(spec, nid, idx, dir)	0
-#define has_cdefine_beep(codec)		0
-#endif
-
-/* parse the BIOS configuration and set up the alc_spec */
-/* return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
-static int alc_parse_auto_config(struct hda_codec *codec,
-				 const hda_nid_t *ignore_nids,
-				 const hda_nid_t *ssid_nids)
-{
-	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-	int err;
-
-	err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
-				       spec->parse_flags);
-	if (err < 0)
-		return err;
-
-	if (ssid_nids)
-		alc_ssid_check(codec, ssid_nids);
-
-	err = snd_hda_gen_parse_auto_config(codec, cfg);
-	if (err < 0)
-		return err;
-
-	return 1;
-}
-
-/* common preparation job for alc_spec */
-static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
-{
-	struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	int err;
-
-	if (!spec)
-		return -ENOMEM;
-	codec->spec = spec;
-	snd_hda_gen_spec_init(&spec->gen);
-	spec->gen.mixer_nid = mixer_nid;
-	spec->gen.own_eapd_ctl = 1;
-	codec->single_adc_amp = 1;
-	/* FIXME: do we need this for all Realtek codec models? */
-	codec->spdif_status_reset = 1;
-	codec->forced_resume = 1;
-	codec->patch_ops = alc_patch_ops;
-	mutex_init(&spec->coef_mutex);
-
-	err = alc_codec_rename_from_preset(codec);
-	if (err < 0) {
-		kfree(spec);
-		return err;
-	}
-	return 0;
-}
-
-static int alc880_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
-	static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
-}
-
-/*
- * ALC880 fix-ups
- */
-enum {
-	ALC880_FIXUP_GPIO1,
-	ALC880_FIXUP_GPIO2,
-	ALC880_FIXUP_MEDION_RIM,
-	ALC880_FIXUP_LG,
-	ALC880_FIXUP_LG_LW25,
-	ALC880_FIXUP_W810,
-	ALC880_FIXUP_EAPD_COEF,
-	ALC880_FIXUP_TCL_S700,
-	ALC880_FIXUP_VOL_KNOB,
-	ALC880_FIXUP_FUJITSU,
-	ALC880_FIXUP_F1734,
-	ALC880_FIXUP_UNIWILL,
-	ALC880_FIXUP_UNIWILL_DIG,
-	ALC880_FIXUP_Z71V,
-	ALC880_FIXUP_ASUS_W5A,
-	ALC880_FIXUP_3ST_BASE,
-	ALC880_FIXUP_3ST,
-	ALC880_FIXUP_3ST_DIG,
-	ALC880_FIXUP_5ST_BASE,
-	ALC880_FIXUP_5ST,
-	ALC880_FIXUP_5ST_DIG,
-	ALC880_FIXUP_6ST_BASE,
-	ALC880_FIXUP_6ST,
-	ALC880_FIXUP_6ST_DIG,
-	ALC880_FIXUP_6ST_AUTOMUTE,
-};
-
-/* enable the volume-knob widget support on NID 0x21 */
-static void alc880_fixup_vol_knob(struct hda_codec *codec,
-				  const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PROBE)
-		snd_hda_jack_detect_enable_callback(codec, 0x21,
-						    alc_update_knob_master);
-}
-
-static const struct hda_fixup alc880_fixups[] = {
-	[ALC880_FIXUP_GPIO1] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio1,
-	},
-	[ALC880_FIXUP_GPIO2] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio2,
-	},
-	[ALC880_FIXUP_MEDION_RIM] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_GPIO2,
-	},
-	[ALC880_FIXUP_LG] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			/* disable bogus unused pins */
-			{ 0x16, 0x411111f0 },
-			{ 0x18, 0x411111f0 },
-			{ 0x1a, 0x411111f0 },
-			{ }
-		}
-	},
-	[ALC880_FIXUP_LG_LW25] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1a, 0x0181344f }, /* line-in */
-			{ 0x1b, 0x0321403f }, /* headphone */
-			{ }
-		}
-	},
-	[ALC880_FIXUP_W810] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			/* disable bogus unused pins */
-			{ 0x17, 0x411111f0 },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_GPIO2,
-	},
-	[ALC880_FIXUP_EAPD_COEF] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* change to EAPD mode */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
-			{}
-		},
-	},
-	[ALC880_FIXUP_TCL_S700] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* change to EAPD mode */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_GPIO2,
-	},
-	[ALC880_FIXUP_VOL_KNOB] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc880_fixup_vol_knob,
-	},
-	[ALC880_FIXUP_FUJITSU] = {
-		/* override all pins as BIOS on old Amilo is broken */
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x0121401f }, /* HP */
-			{ 0x15, 0x99030120 }, /* speaker */
-			{ 0x16, 0x99030130 }, /* bass speaker */
-			{ 0x17, 0x411111f0 }, /* N/A */
-			{ 0x18, 0x411111f0 }, /* N/A */
-			{ 0x19, 0x01a19950 }, /* mic-in */
-			{ 0x1a, 0x411111f0 }, /* N/A */
-			{ 0x1b, 0x411111f0 }, /* N/A */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			{ 0x1e, 0x01454140 }, /* SPDIF out */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_VOL_KNOB,
-	},
-	[ALC880_FIXUP_F1734] = {
-		/* almost compatible with FUJITSU, but no bass and SPDIF */
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x0121401f }, /* HP */
-			{ 0x15, 0x99030120 }, /* speaker */
-			{ 0x16, 0x411111f0 }, /* N/A */
-			{ 0x17, 0x411111f0 }, /* N/A */
-			{ 0x18, 0x411111f0 }, /* N/A */
-			{ 0x19, 0x01a19950 }, /* mic-in */
-			{ 0x1a, 0x411111f0 }, /* N/A */
-			{ 0x1b, 0x411111f0 }, /* N/A */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			{ 0x1e, 0x411111f0 }, /* N/A */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_VOL_KNOB,
-	},
-	[ALC880_FIXUP_UNIWILL] = {
-		/* need to fix HP and speaker pins to be parsed correctly */
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x0121411f }, /* HP */
-			{ 0x15, 0x99030120 }, /* speaker */
-			{ 0x16, 0x99030130 }, /* bass speaker */
-			{ }
-		},
-	},
-	[ALC880_FIXUP_UNIWILL_DIG] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			/* disable bogus unused pins */
-			{ 0x17, 0x411111f0 },
-			{ 0x19, 0x411111f0 },
-			{ 0x1b, 0x411111f0 },
-			{ 0x1f, 0x411111f0 },
-			{ }
-		}
-	},
-	[ALC880_FIXUP_Z71V] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			/* set up the whole pins as BIOS is utterly broken */
-			{ 0x14, 0x99030120 }, /* speaker */
-			{ 0x15, 0x0121411f }, /* HP */
-			{ 0x16, 0x411111f0 }, /* N/A */
-			{ 0x17, 0x411111f0 }, /* N/A */
-			{ 0x18, 0x01a19950 }, /* mic-in */
-			{ 0x19, 0x411111f0 }, /* N/A */
-			{ 0x1a, 0x01813031 }, /* line-in */
-			{ 0x1b, 0x411111f0 }, /* N/A */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			{ 0x1e, 0x0144111e }, /* SPDIF */
-			{ }
-		}
-	},
-	[ALC880_FIXUP_ASUS_W5A] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			/* set up the whole pins as BIOS is utterly broken */
-			{ 0x14, 0x0121411f }, /* HP */
-			{ 0x15, 0x411111f0 }, /* N/A */
-			{ 0x16, 0x411111f0 }, /* N/A */
-			{ 0x17, 0x411111f0 }, /* N/A */
-			{ 0x18, 0x90a60160 }, /* mic */
-			{ 0x19, 0x411111f0 }, /* N/A */
-			{ 0x1a, 0x411111f0 }, /* N/A */
-			{ 0x1b, 0x411111f0 }, /* N/A */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			{ 0x1e, 0xb743111e }, /* SPDIF out */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_GPIO1,
-	},
-	[ALC880_FIXUP_3ST_BASE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x01014010 }, /* line-out */
-			{ 0x15, 0x411111f0 }, /* N/A */
-			{ 0x16, 0x411111f0 }, /* N/A */
-			{ 0x17, 0x411111f0 }, /* N/A */
-			{ 0x18, 0x01a19c30 }, /* mic-in */
-			{ 0x19, 0x0121411f }, /* HP */
-			{ 0x1a, 0x01813031 }, /* line-in */
-			{ 0x1b, 0x02a19c40 }, /* front-mic */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			/* 0x1e is filled in below */
-			{ 0x1f, 0x411111f0 }, /* N/A */
-			{ }
-		}
-	},
-	[ALC880_FIXUP_3ST] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x411111f0 }, /* N/A */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_3ST_BASE,
-	},
-	[ALC880_FIXUP_3ST_DIG] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x0144111e }, /* SPDIF */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_3ST_BASE,
-	},
-	[ALC880_FIXUP_5ST_BASE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x01014010 }, /* front */
-			{ 0x15, 0x411111f0 }, /* N/A */
-			{ 0x16, 0x01011411 }, /* CLFE */
-			{ 0x17, 0x01016412 }, /* surr */
-			{ 0x18, 0x01a19c30 }, /* mic-in */
-			{ 0x19, 0x0121411f }, /* HP */
-			{ 0x1a, 0x01813031 }, /* line-in */
-			{ 0x1b, 0x02a19c40 }, /* front-mic */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			/* 0x1e is filled in below */
-			{ 0x1f, 0x411111f0 }, /* N/A */
-			{ }
-		}
-	},
-	[ALC880_FIXUP_5ST] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x411111f0 }, /* N/A */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_5ST_BASE,
-	},
-	[ALC880_FIXUP_5ST_DIG] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x0144111e }, /* SPDIF */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_5ST_BASE,
-	},
-	[ALC880_FIXUP_6ST_BASE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x01014010 }, /* front */
-			{ 0x15, 0x01016412 }, /* surr */
-			{ 0x16, 0x01011411 }, /* CLFE */
-			{ 0x17, 0x01012414 }, /* side */
-			{ 0x18, 0x01a19c30 }, /* mic-in */
-			{ 0x19, 0x02a19c40 }, /* front-mic */
-			{ 0x1a, 0x01813031 }, /* line-in */
-			{ 0x1b, 0x0121411f }, /* HP */
-			{ 0x1c, 0x411111f0 }, /* N/A */
-			{ 0x1d, 0x411111f0 }, /* N/A */
-			/* 0x1e is filled in below */
-			{ 0x1f, 0x411111f0 }, /* N/A */
-			{ }
-		}
-	},
-	[ALC880_FIXUP_6ST] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x411111f0 }, /* N/A */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_6ST_BASE,
-	},
-	[ALC880_FIXUP_6ST_DIG] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x0144111e }, /* SPDIF */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC880_FIXUP_6ST_BASE,
-	},
-	[ALC880_FIXUP_6ST_AUTOMUTE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1b, 0x0121401f }, /* HP with jack detect */
-			{ }
-		},
-		.chained_before = true,
-		.chain_id = ALC880_FIXUP_6ST_BASE,
-	},
-};
-
-static const struct hda_quirk alc880_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
-	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
-	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
-	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
-	SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
-	SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
-	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
-	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
-	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
-	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
-	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
-	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
-	SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
-	SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
-	SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
-	SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
-	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
-	SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
-	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
-	SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
-	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
-	SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
-	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
-
-	/* Below is the copied entries from alc880_quirks.c.
-	 * It's not quite sure whether BIOS sets the correct pin-config table
-	 * on these machines, thus they are kept to be compatible with
-	 * the old static quirks.  Once when it's confirmed to work without
-	 * these overrides, it'd be better to remove.
-	 */
-	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
-	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
-	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
-	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
-	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
-	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
-	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
-	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
-	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
-	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-	/* default Intel */
-	SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
-	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
-	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
-	{}
-};
-
-static const struct hda_model_fixup alc880_fixup_models[] = {
-	{.id = ALC880_FIXUP_3ST, .name = "3stack"},
-	{.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
-	{.id = ALC880_FIXUP_5ST, .name = "5stack"},
-	{.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
-	{.id = ALC880_FIXUP_6ST, .name = "6stack"},
-	{.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
-	{.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
-	{}
-};
-
-
-/*
- * OK, here we have finally the patch for ALC880
- */
-static int patch_alc880(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x0b);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-	spec->gen.need_dac_fix = 1;
-	spec->gen.beep_nid = 0x01;
-
-	codec->patch_ops.unsol_event = alc880_unsol_event;
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
-		       alc880_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	/* automatic parse from the BIOS config */
-	err = alc880_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog) {
-		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-
-/*
- * ALC260 support
- */
-static int alc260_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
-	static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
-	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
-}
-
-/*
- * Pin config fixes
- */
-enum {
-	ALC260_FIXUP_HP_DC5750,
-	ALC260_FIXUP_HP_PIN_0F,
-	ALC260_FIXUP_COEF,
-	ALC260_FIXUP_GPIO1,
-	ALC260_FIXUP_GPIO1_TOGGLE,
-	ALC260_FIXUP_REPLACER,
-	ALC260_FIXUP_HP_B1900,
-	ALC260_FIXUP_KN1,
-	ALC260_FIXUP_FSC_S7020,
-	ALC260_FIXUP_FSC_S7020_JWSE,
-	ALC260_FIXUP_VAIO_PINS,
-};
-
-static void alc260_gpio1_automute(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
-}
-
-static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
-				      const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PROBE) {
-		/* although the machine has only one output pin, we need to
-		 * toggle GPIO1 according to the jack state
-		 */
-		spec->gen.automute_hook = alc260_gpio1_automute;
-		spec->gen.detect_hp = 1;
-		spec->gen.automute_speaker = 1;
-		spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
-		snd_hda_jack_detect_enable_callback(codec, 0x0f,
-						    snd_hda_gen_hp_automute);
-		alc_setup_gpio(codec, 0x01);
-	}
-}
-
-static void alc260_fixup_kn1(struct hda_codec *codec,
-			     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	static const struct hda_pintbl pincfgs[] = {
-		{ 0x0f, 0x02214000 }, /* HP/speaker */
-		{ 0x12, 0x90a60160 }, /* int mic */
-		{ 0x13, 0x02a19000 }, /* ext mic */
-		{ 0x18, 0x01446000 }, /* SPDIF out */
-		/* disable bogus I/O pins */
-		{ 0x10, 0x411111f0 },
-		{ 0x11, 0x411111f0 },
-		{ 0x14, 0x411111f0 },
-		{ 0x15, 0x411111f0 },
-		{ 0x16, 0x411111f0 },
-		{ 0x17, 0x411111f0 },
-		{ 0x19, 0x411111f0 },
-		{ }
-	};
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		snd_hda_apply_pincfgs(codec, pincfgs);
-		spec->init_amp = ALC_INIT_NONE;
-		break;
-	}
-}
-
-static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
-				   const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		spec->init_amp = ALC_INIT_NONE;
-}
-
-static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
-				   const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->gen.add_jack_modes = 1;
-		spec->gen.hp_mic = 1;
-	}
-}
-
-static const struct hda_fixup alc260_fixups[] = {
-	[ALC260_FIXUP_HP_DC5750] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x11, 0x90130110 }, /* speaker */
-			{ }
-		}
-	},
-	[ALC260_FIXUP_HP_PIN_0F] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x0f, 0x01214000 }, /* HP */
-			{ }
-		}
-	},
-	[ALC260_FIXUP_COEF] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
-			{ }
-		},
-	},
-	[ALC260_FIXUP_GPIO1] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio1,
-	},
-	[ALC260_FIXUP_GPIO1_TOGGLE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc260_fixup_gpio1_toggle,
-		.chained = true,
-		.chain_id = ALC260_FIXUP_HP_PIN_0F,
-	},
-	[ALC260_FIXUP_REPLACER] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
-	},
-	[ALC260_FIXUP_HP_B1900] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc260_fixup_gpio1_toggle,
-		.chained = true,
-		.chain_id = ALC260_FIXUP_COEF,
-	},
-	[ALC260_FIXUP_KN1] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc260_fixup_kn1,
-	},
-	[ALC260_FIXUP_FSC_S7020] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc260_fixup_fsc_s7020,
-	},
-	[ALC260_FIXUP_FSC_S7020_JWSE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc260_fixup_fsc_s7020_jwse,
-		.chained = true,
-		.chain_id = ALC260_FIXUP_FSC_S7020,
-	},
-	[ALC260_FIXUP_VAIO_PINS] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			/* Pin configs are missing completely on some VAIOs */
-			{ 0x0f, 0x01211020 },
-			{ 0x10, 0x0001003f },
-			{ 0x11, 0x411111f0 },
-			{ 0x12, 0x01a15930 },
-			{ 0x13, 0x411111f0 },
-			{ 0x14, 0x411111f0 },
-			{ 0x15, 0x411111f0 },
-			{ 0x16, 0x411111f0 },
-			{ 0x17, 0x411111f0 },
-			{ 0x18, 0x411111f0 },
-			{ 0x19, 0x411111f0 },
-			{ }
-		}
-	},
-};
-
-static const struct hda_quirk alc260_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
-	SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
-	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
-	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
-	SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
-	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
-	SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
-	SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
-	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
-	SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
-	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
-	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
-	{}
-};
-
-static const struct hda_model_fixup alc260_fixup_models[] = {
-	{.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
-	{.id = ALC260_FIXUP_COEF, .name = "coef"},
-	{.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
-	{.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
-	{}
-};
-
-/*
- */
-static int patch_alc260(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x07);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-	/* as quite a few machines require HP amp for speaker outputs,
-	 * it's easier to enable it unconditionally; even if it's unneeded,
-	 * it's almost harmless.
-	 */
-	spec->gen.prefer_hp_amp = 1;
-	spec->gen.beep_nid = 0x01;
-
-	spec->shutup = alc_eapd_shutup;
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
-			   alc260_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	/* automatic parse from the BIOS config */
-	err = alc260_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog) {
-		err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-
-/*
- * ALC882/883/885/888/889 support
- *
- * ALC882 is almost identical with ALC880 but has cleaner and more flexible
- * configuration.  Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs.  This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-
-/*
- * Pin config fixes
- */
-enum {
-	ALC882_FIXUP_ABIT_AW9D_MAX,
-	ALC882_FIXUP_LENOVO_Y530,
-	ALC882_FIXUP_PB_M5210,
-	ALC882_FIXUP_ACER_ASPIRE_7736,
-	ALC882_FIXUP_ASUS_W90V,
-	ALC889_FIXUP_CD,
-	ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
-	ALC889_FIXUP_VAIO_TT,
-	ALC888_FIXUP_EEE1601,
-	ALC886_FIXUP_EAPD,
-	ALC882_FIXUP_EAPD,
-	ALC883_FIXUP_EAPD,
-	ALC883_FIXUP_ACER_EAPD,
-	ALC882_FIXUP_GPIO1,
-	ALC882_FIXUP_GPIO2,
-	ALC882_FIXUP_GPIO3,
-	ALC889_FIXUP_COEF,
-	ALC882_FIXUP_ASUS_W2JC,
-	ALC882_FIXUP_ACER_ASPIRE_4930G,
-	ALC882_FIXUP_ACER_ASPIRE_8930G,
-	ALC882_FIXUP_ASPIRE_8930G_VERBS,
-	ALC885_FIXUP_MACPRO_GPIO,
-	ALC889_FIXUP_DAC_ROUTE,
-	ALC889_FIXUP_MBP_VREF,
-	ALC889_FIXUP_IMAC91_VREF,
-	ALC889_FIXUP_MBA11_VREF,
-	ALC889_FIXUP_MBA21_VREF,
-	ALC889_FIXUP_MP11_VREF,
-	ALC889_FIXUP_MP41_VREF,
-	ALC882_FIXUP_INV_DMIC,
-	ALC882_FIXUP_NO_PRIMARY_HP,
-	ALC887_FIXUP_ASUS_BASS,
-	ALC887_FIXUP_BASS_CHMAP,
-	ALC1220_FIXUP_GB_DUAL_CODECS,
-	ALC1220_FIXUP_GB_X570,
-	ALC1220_FIXUP_CLEVO_P950,
-	ALC1220_FIXUP_CLEVO_PB51ED,
-	ALC1220_FIXUP_CLEVO_PB51ED_PINS,
-	ALC887_FIXUP_ASUS_AUDIO,
-	ALC887_FIXUP_ASUS_HMIC,
-	ALCS1200A_FIXUP_MIC_VREF,
-	ALC888VD_FIXUP_MIC_100VREF,
-};
-
-static void alc889_fixup_coef(struct hda_codec *codec,
-			      const struct hda_fixup *fix, int action)
-{
-	if (action != HDA_FIXUP_ACT_INIT)
-		return;
-	alc_update_coef_idx(codec, 7, 0, 0x2030);
-}
-
-/* set up GPIO at initialization */
-static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	spec->gpio_write_delay = true;
-	alc_fixup_gpio3(codec, fix, action);
-}
-
-/* Fix the connection of some pins for ALC889:
- * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
- * work correctly (bko#42740)
- */
-static void alc889_fixup_dac_route(struct hda_codec *codec,
-				   const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		/* fake the connections during parsing the tree */
-		static const hda_nid_t conn1[] = { 0x0c, 0x0d };
-		static const hda_nid_t conn2[] = { 0x0e, 0x0f };
-		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
-		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
-		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
-	} else if (action == HDA_FIXUP_ACT_PROBE) {
-		/* restore the connections */
-		static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
-		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
-		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
-		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
-		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
-	}
-}
-
-/* Set VREF on HP pin */
-static void alc889_fixup_mbp_vref(struct hda_codec *codec,
-				  const struct hda_fixup *fix, int action)
-{
-	static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
-	struct alc_spec *spec = codec->spec;
-	int i;
-
-	if (action != HDA_FIXUP_ACT_INIT)
-		return;
-	for (i = 0; i < ARRAY_SIZE(nids); i++) {
-		unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
-		if (get_defcfg_device(val) != AC_JACK_HP_OUT)
-			continue;
-		val = snd_hda_codec_get_pin_target(codec, nids[i]);
-		val |= AC_PINCTL_VREF_80;
-		snd_hda_set_pin_ctl(codec, nids[i], val);
-		spec->gen.keep_vref_in_automute = 1;
-		break;
-	}
-}
-
-static void alc889_fixup_mac_pins(struct hda_codec *codec,
-				  const hda_nid_t *nids, int num_nids)
-{
-	struct alc_spec *spec = codec->spec;
-	int i;
-
-	for (i = 0; i < num_nids; i++) {
-		unsigned int val;
-		val = snd_hda_codec_get_pin_target(codec, nids[i]);
-		val |= AC_PINCTL_VREF_50;
-		snd_hda_set_pin_ctl(codec, nids[i], val);
-	}
-	spec->gen.keep_vref_in_automute = 1;
-}
-
-/* Set VREF on speaker pins on imac91 */
-static void alc889_fixup_imac91_vref(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	static const hda_nid_t nids[] = { 0x18, 0x1a };
-
-	if (action == HDA_FIXUP_ACT_INIT)
-		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Set VREF on speaker pins on mba11 */
-static void alc889_fixup_mba11_vref(struct hda_codec *codec,
-				    const struct hda_fixup *fix, int action)
-{
-	static const hda_nid_t nids[] = { 0x18 };
-
-	if (action == HDA_FIXUP_ACT_INIT)
-		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Set VREF on speaker pins on mba21 */
-static void alc889_fixup_mba21_vref(struct hda_codec *codec,
-				    const struct hda_fixup *fix, int action)
-{
-	static const hda_nid_t nids[] = { 0x18, 0x19 };
-
-	if (action == HDA_FIXUP_ACT_INIT)
-		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Don't take HP output as primary
- * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
- * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
- */
-static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
-				       const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->gen.no_primary_hp = 1;
-		spec->gen.no_multi_io = 1;
-	}
-}
-
-static void alc_fixup_bass_chmap(struct hda_codec *codec,
-				 const struct hda_fixup *fix, int action);
-
-/* For dual-codec configuration, we need to disable some features to avoid
- * conflicts of kctls and PCM streams
- */
-static void alc_fixup_dual_codecs(struct hda_codec *codec,
-				  const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (action != HDA_FIXUP_ACT_PRE_PROBE)
-		return;
-	/* disable vmaster */
-	spec->gen.suppress_vmaster = 1;
-	/* auto-mute and auto-mic switch don't work with multiple codecs */
-	spec->gen.suppress_auto_mute = 1;
-	spec->gen.suppress_auto_mic = 1;
-	/* disable aamix as well */
-	spec->gen.mixer_nid = 0;
-	/* add location prefix to avoid conflicts */
-	codec->force_pin_prefix = 1;
-}
-
-static void rename_ctl(struct hda_codec *codec, const char *oldname,
-		       const char *newname)
-{
-	struct snd_kcontrol *kctl;
-
-	kctl = snd_hda_find_mixer_ctl(codec, oldname);
-	if (kctl)
-		snd_ctl_rename(codec->card, kctl, newname);
-}
-
-static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
-					 const struct hda_fixup *fix,
-					 int action)
-{
-	alc_fixup_dual_codecs(codec, fix, action);
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		/* override card longname to provide a unique UCM profile */
-		strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
-		break;
-	case HDA_FIXUP_ACT_BUILD:
-		/* rename Capture controls depending on the codec */
-		rename_ctl(codec, "Capture Volume",
-			   codec->addr == 0 ?
-			   "Rear-Panel Capture Volume" :
-			   "Front-Panel Capture Volume");
-		rename_ctl(codec, "Capture Switch",
-			   codec->addr == 0 ?
-			   "Rear-Panel Capture Switch" :
-			   "Front-Panel Capture Switch");
-		break;
-	}
-}
-
-static void alc1220_fixup_gb_x570(struct hda_codec *codec,
-				     const struct hda_fixup *fix,
-				     int action)
-{
-	static const hda_nid_t conn1[] = { 0x0c };
-	static const struct coef_fw gb_x570_coefs[] = {
-		WRITE_COEF(0x07, 0x03c0),
-		WRITE_COEF(0x1a, 0x01c1),
-		WRITE_COEF(0x1b, 0x0202),
-		WRITE_COEF(0x43, 0x3005),
-		{}
-	};
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-		snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
-		break;
-	case HDA_FIXUP_ACT_INIT:
-		alc_process_coef_fw(codec, gb_x570_coefs);
-		break;
-	}
-}
-
-static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
-				     const struct hda_fixup *fix,
-				     int action)
-{
-	static const hda_nid_t conn1[] = { 0x0c };
-
-	if (action != HDA_FIXUP_ACT_PRE_PROBE)
-		return;
-
-	alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
-	/* We therefore want to make sure 0x14 (front headphone) and
-	 * 0x1b (speakers) use the stereo DAC 0x02
-	 */
-	snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-	snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
-}
-
-static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action);
-
-static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
-				     const struct hda_fixup *fix,
-				     int action)
-{
-	alc1220_fixup_clevo_p950(codec, fix, action);
-	alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
-}
-
-static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
-					 struct hda_jack_callback *jack)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int vref;
-
-	snd_hda_gen_hp_automute(codec, jack);
-
-	if (spec->gen.hp_jack_present)
-		vref = AC_PINCTL_VREF_80;
-	else
-		vref = AC_PINCTL_VREF_HIZ;
-	snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
-}
-
-static void alc887_fixup_asus_jack(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action != HDA_FIXUP_ACT_PROBE)
-		return;
-	snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
-	spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
-}
-
-static const struct hda_fixup alc882_fixups[] = {
-	[ALC882_FIXUP_ABIT_AW9D_MAX] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x01080104 }, /* side */
-			{ 0x16, 0x01011012 }, /* rear */
-			{ 0x17, 0x01016011 }, /* clfe */
-			{ }
-		}
-	},
-	[ALC882_FIXUP_LENOVO_Y530] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x99130112 }, /* rear int speakers */
-			{ 0x16, 0x99130111 }, /* subwoofer */
-			{ }
-		}
-	},
-	[ALC882_FIXUP_PB_M5210] = {
-		.type = HDA_FIXUP_PINCTLS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, PIN_VREF50 },
-			{}
-		}
-	},
-	[ALC882_FIXUP_ACER_ASPIRE_7736] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_sku_ignore,
-	},
-	[ALC882_FIXUP_ASUS_W90V] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x16, 0x99130110 }, /* fix sequence for CLFE */
-			{ }
-		}
-	},
-	[ALC889_FIXUP_CD] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1c, 0x993301f0 }, /* CD */
-			{ }
-		}
-	},
-	[ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC889_FIXUP_CD,
-	},
-	[ALC889_FIXUP_VAIO_TT] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x17, 0x90170111 }, /* hidden surround speaker */
-			{ }
-		}
-	},
-	[ALC888_FIXUP_EEE1601] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
-			{ 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
-			{ }
-		}
-	},
-	[ALC886_FIXUP_EAPD] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* change to EAPD mode */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
-			{ }
-		}
-	},
-	[ALC882_FIXUP_EAPD] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* change to EAPD mode */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
-			{ }
-		}
-	},
-	[ALC883_FIXUP_EAPD] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* change to EAPD mode */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
-			{ }
-		}
-	},
-	[ALC883_FIXUP_ACER_EAPD] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* eanable EAPD on Acer laptops */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
-			{ }
-		}
-	},
-	[ALC882_FIXUP_GPIO1] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio1,
-	},
-	[ALC882_FIXUP_GPIO2] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio2,
-	},
-	[ALC882_FIXUP_GPIO3] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio3,
-	},
-	[ALC882_FIXUP_ASUS_W2JC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_gpio1,
-		.chained = true,
-		.chain_id = ALC882_FIXUP_EAPD,
-	},
-	[ALC889_FIXUP_COEF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_coef,
-	},
-	[ALC882_FIXUP_ACER_ASPIRE_4930G] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x16, 0x99130111 }, /* CLFE speaker */
-			{ 0x17, 0x99130112 }, /* surround speaker */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC882_FIXUP_GPIO1,
-	},
-	[ALC882_FIXUP_ACER_ASPIRE_8930G] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x16, 0x99130111 }, /* CLFE speaker */
-			{ 0x1b, 0x99130112 }, /* surround speaker */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
-	},
-	[ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
-		/* additional init verbs for Acer Aspire 8930G */
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* Enable all DACs */
-			/* DAC DISABLE/MUTE 1? */
-			/*  setting bits 1-5 disables DAC nids 0x02-0x06
-			 *  apparently. Init=0x38 */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-			/* DAC DISABLE/MUTE 2? */
-			/*  some bit here disables the other DACs.
-			 *  Init=0x4900 */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-			/* DMIC fix
-			 * This laptop has a stereo digital microphone.
-			 * The mics are only 1cm apart which makes the stereo
-			 * useless. However, either the mic or the ALC889
-			 * makes the signal become a difference/sum signal
-			 * instead of standard stereo, which is annoying.
-			 * So instead we flip this bit which makes the
-			 * codec replicate the sum signal to both channels,
-			 * turning it into a normal mono mic.
-			 */
-			/* DMIC_CONTROL? Init value = 0x0001 */
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC882_FIXUP_GPIO1,
-	},
-	[ALC885_FIXUP_MACPRO_GPIO] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc885_fixup_macpro_gpio,
-	},
-	[ALC889_FIXUP_DAC_ROUTE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_dac_route,
-	},
-	[ALC889_FIXUP_MBP_VREF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_mbp_vref,
-		.chained = true,
-		.chain_id = ALC882_FIXUP_GPIO1,
-	},
-	[ALC889_FIXUP_IMAC91_VREF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_imac91_vref,
-		.chained = true,
-		.chain_id = ALC882_FIXUP_GPIO1,
-	},
-	[ALC889_FIXUP_MBA11_VREF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_mba11_vref,
-		.chained = true,
-		.chain_id = ALC889_FIXUP_MBP_VREF,
-	},
-	[ALC889_FIXUP_MBA21_VREF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_mba21_vref,
-		.chained = true,
-		.chain_id = ALC889_FIXUP_MBP_VREF,
-	},
-	[ALC889_FIXUP_MP11_VREF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_mba11_vref,
-		.chained = true,
-		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
-	},
-	[ALC889_FIXUP_MP41_VREF] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc889_fixup_mbp_vref,
-		.chained = true,
-		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
-	},
-	[ALC882_FIXUP_INV_DMIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic,
-	},
-	[ALC882_FIXUP_NO_PRIMARY_HP] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc882_fixup_no_primary_hp,
-	},
-	[ALC887_FIXUP_ASUS_BASS] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{0x16, 0x99130130}, /* bass speaker */
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC887_FIXUP_BASS_CHMAP,
-	},
-	[ALC887_FIXUP_BASS_CHMAP] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_bass_chmap,
-	},
-	[ALC1220_FIXUP_GB_DUAL_CODECS] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc1220_fixup_gb_dual_codecs,
-	},
-	[ALC1220_FIXUP_GB_X570] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc1220_fixup_gb_x570,
-	},
-	[ALC1220_FIXUP_CLEVO_P950] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc1220_fixup_clevo_p950,
-	},
-	[ALC1220_FIXUP_CLEVO_PB51ED] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc1220_fixup_clevo_pb51ed,
-	},
-	[ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
-	},
-	[ALC887_FIXUP_ASUS_AUDIO] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
-			{ 0x19, 0x22219420 },
-			{}
-		},
-	},
-	[ALC887_FIXUP_ASUS_HMIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc887_fixup_asus_jack,
-		.chained = true,
-		.chain_id = ALC887_FIXUP_ASUS_AUDIO,
-	},
-	[ALCS1200A_FIXUP_MIC_VREF] = {
-		.type = HDA_FIXUP_PINCTLS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x18, PIN_VREF50 }, /* rear mic */
-			{ 0x19, PIN_VREF50 }, /* front mic */
-			{}
-		}
-	},
-	[ALC888VD_FIXUP_MIC_100VREF] = {
-		.type = HDA_FIXUP_PINCTLS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x18, PIN_VREF100 }, /* headset mic */
-			{}
-		}
-	},
-};
-
-static const struct hda_quirk alc882_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
-	SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
-		      ALC882_FIXUP_ACER_ASPIRE_4930G),
-	SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
-		      ALC882_FIXUP_ACER_ASPIRE_4930G),
-	SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
-		      ALC882_FIXUP_ACER_ASPIRE_8930G),
-	SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
-		      ALC882_FIXUP_ACER_ASPIRE_8930G),
-	SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
-		      ALC882_FIXUP_ACER_ASPIRE_4930G),
-	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
-	SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
-		      ALC882_FIXUP_ACER_ASPIRE_4930G),
-	SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
-		      ALC882_FIXUP_ACER_ASPIRE_4930G),
-	SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
-		      ALC882_FIXUP_ACER_ASPIRE_4930G),
-	SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
-	SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
-	SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
-	SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
-	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
-	SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
-	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
-	SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
-	SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
-	SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
-	SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
-	SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
-	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
-	SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
-	SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
-
-	/* All Apple entries are in codec SSIDs */
-	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
-	SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
-	SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
-	SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
-	SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
-	SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
-	SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
-	SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
-	SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
-	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
-
-	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
-	SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
-	SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
-	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
-	SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
-	SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
-	SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
-	SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
-	SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
-	SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
-	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
-	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
-	SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
-	SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
-	SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
-	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
-	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
-	SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
-	{}
-};
-
-static const struct hda_model_fixup alc882_fixup_models[] = {
-	{.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
-	{.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
-	{.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
-	{.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
-	{.id = ALC889_FIXUP_CD, .name = "cd"},
-	{.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
-	{.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
-	{.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
-	{.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
-	{.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
-	{.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
-	{.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
-	{.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
-	{.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
-	{.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
-	{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
-	{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
-	{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
-	{.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
-	{.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
-	{.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
-	{.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
-	{.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
-	{.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
-	{.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
-	{.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
-	{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
-	{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
-	{.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
-	{.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
-	{.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
-	{.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
-	{}
-};
-
-static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
-	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
-		{0x14, 0x01014010},
-		{0x15, 0x01011012},
-		{0x16, 0x01016011},
-		{0x18, 0x01a19040},
-		{0x19, 0x02a19050},
-		{0x1a, 0x0181304f},
-		{0x1b, 0x0221401f},
-		{0x1e, 0x01456130}),
-	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
-		{0x14, 0x01015010},
-		{0x15, 0x01011012},
-		{0x16, 0x01011011},
-		{0x18, 0x01a11040},
-		{0x19, 0x02a19050},
-		{0x1a, 0x0181104f},
-		{0x1b, 0x0221401f},
-		{0x1e, 0x01451130}),
-	{}
-};
-
-/*
- * BIOS auto configuration
- */
-/* almost identical with ALC880 parser... */
-static int alc882_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
-	static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
-}
-
-/*
- */
-static int patch_alc882(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x0b);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0882:
-	case 0x10ec0885:
-	case 0x10ec0900:
-	case 0x10ec0b00:
-	case 0x10ec1220:
-		break;
-	default:
-		/* ALC883 and variants */
-		alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-		break;
-	}
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
-		       alc882_fixups);
-	snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	alc_auto_parse_customize_define(codec);
-
-	if (has_cdefine_beep(codec))
-		spec->gen.beep_nid = 0x01;
-
-	/* automatic parse from the BIOS config */
-	err = alc882_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog && spec->gen.beep_nid) {
-		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-
-/*
- * ALC262 support
- */
-static int alc262_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
-	static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
-}
-
-/*
- * Pin config fixes
- */
-enum {
-	ALC262_FIXUP_FSC_H270,
-	ALC262_FIXUP_FSC_S7110,
-	ALC262_FIXUP_HP_Z200,
-	ALC262_FIXUP_TYAN,
-	ALC262_FIXUP_LENOVO_3000,
-	ALC262_FIXUP_BENQ,
-	ALC262_FIXUP_BENQ_T31,
-	ALC262_FIXUP_INV_DMIC,
-	ALC262_FIXUP_INTEL_BAYLEYBAY,
-};
-
-static const struct hda_fixup alc262_fixups[] = {
-	[ALC262_FIXUP_FSC_H270] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x15, 0x0221142f }, /* front HP */
-			{ 0x1b, 0x0121141f }, /* rear HP */
-			{ }
-		}
-	},
-	[ALC262_FIXUP_FSC_S7110] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x90170110 }, /* speaker */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC262_FIXUP_BENQ,
-	},
-	[ALC262_FIXUP_HP_Z200] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x16, 0x99130120 }, /* internal speaker */
-			{ }
-		}
-	},
-	[ALC262_FIXUP_TYAN] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x1993e1f0 }, /* int AUX */
-			{ }
-		}
-	},
-	[ALC262_FIXUP_LENOVO_3000] = {
-		.type = HDA_FIXUP_PINCTLS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, PIN_VREF50 },
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC262_FIXUP_BENQ,
-	},
-	[ALC262_FIXUP_BENQ] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
-			{}
-		}
-	},
-	[ALC262_FIXUP_BENQ_T31] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
-			{}
-		}
-	},
-	[ALC262_FIXUP_INV_DMIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic,
-	},
-	[ALC262_FIXUP_INTEL_BAYLEYBAY] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_no_depop_delay,
-	},
-};
-
-static const struct hda_quirk alc262_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
-	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
-	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
-	SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
-	SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
-	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
-	SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
-	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
-	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
-	SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
-	{}
-};
-
-static const struct hda_model_fixup alc262_fixup_models[] = {
-	{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
-	{.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
-	{.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
-	{.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
-	{.id = ALC262_FIXUP_TYAN, .name = "tyan"},
-	{.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
-	{.id = ALC262_FIXUP_BENQ, .name = "benq"},
-	{.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
-	{.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
-	{}
-};
-
-/*
- */
-static int patch_alc262(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x0b);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-	spec->gen.shared_mic_vref_pin = 0x18;
-
-	spec->shutup = alc_eapd_shutup;
-
-#if 0
-	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
-	 * under-run
-	 */
-	alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
-#endif
-	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
-		       alc262_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	alc_auto_parse_customize_define(codec);
-
-	if (has_cdefine_beep(codec))
-		spec->gen.beep_nid = 0x01;
-
-	/* automatic parse from the BIOS config */
-	err = alc262_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog && spec->gen.beep_nid) {
-		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-/*
- *  ALC268
- */
-/* bind Beep switches of both NID 0x0f and 0x10 */
-static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	unsigned long pval;
-	int err;
-
-	mutex_lock(&codec->control_mutex);
-	pval = kcontrol->private_value;
-	kcontrol->private_value = (pval & ~0xff) | 0x0f;
-	err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-	if (err >= 0) {
-		kcontrol->private_value = (pval & ~0xff) | 0x10;
-		err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-	}
-	kcontrol->private_value = pval;
-	mutex_unlock(&codec->control_mutex);
-	return err;
-}
-
-static const struct snd_kcontrol_new alc268_beep_mixer[] = {
-	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Beep Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = alc268_beep_switch_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
-	},
-};
-
-/* set PCBEEP vol = 0, mute connections */
-static const struct hda_verb alc268_beep_init_verbs[] = {
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{ }
-};
-
-enum {
-	ALC268_FIXUP_INV_DMIC,
-	ALC268_FIXUP_HP_EAPD,
-	ALC268_FIXUP_SPDIF,
-};
-
-static const struct hda_fixup alc268_fixups[] = {
-	[ALC268_FIXUP_INV_DMIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic,
-	},
-	[ALC268_FIXUP_HP_EAPD] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
-			{}
-		}
-	},
-	[ALC268_FIXUP_SPDIF] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1e, 0x014b1180 }, /* enable SPDIF out */
-			{}
-		}
-	},
-};
-
-static const struct hda_model_fixup alc268_fixup_models[] = {
-	{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
-	{.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
-	{.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
-	{}
-};
-
-static const struct hda_quirk alc268_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
-	SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
-	/* below is codec SSID since multiple Toshiba laptops have the
-	 * same PCI SSID 1179:ff00
-	 */
-	SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
-	{}
-};
-
-/*
- * BIOS auto configuration
- */
-static int alc268_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	return alc_parse_auto_config(codec, NULL, alc268_ssids);
-}
-
-/*
- */
-static int patch_alc268(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int i, err;
-
-	/* ALC268 has no aa-loopback mixer */
-	err = alc_alloc_spec(codec, 0);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-	if (has_cdefine_beep(codec))
-		spec->gen.beep_nid = 0x01;
-
-	spec->shutup = alc_eapd_shutup;
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	/* automatic parse from the BIOS config */
-	err = alc268_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (err > 0 && !spec->gen.no_analog &&
-	    spec->gen.autocfg.speaker_pins[0] != 0x1d) {
-		for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
-			if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
-						  &alc268_beep_mixer[i])) {
-				err = -ENOMEM;
-				goto error;
-			}
-		}
-		snd_hda_add_verbs(codec, alc268_beep_init_verbs);
-		if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
-			/* override the amp caps for beep generator */
-			snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
-					  (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
-					  (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
-					  (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-					  (0 << AC_AMPCAP_MUTE_SHIFT));
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-/*
- * ALC269
- */
-
 static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
 	.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
 };
@@ -4191,15 +1046,6 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
 		alc_update_coef_idx(codec, 0x1e, 0, 0x80);
 }
 
-static void alc269_fixup_headset_mic(struct hda_codec *codec,
-				       const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-}
-
 static void alc271_fixup_dmic(struct hda_codec *codec,
 			      const struct hda_fixup *fix, int action)
 {
@@ -4470,61 +1316,6 @@ static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
 	alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
 }
 
-/* update LED status via GPIO */
-static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
-				int polarity, bool enabled)
-{
-	if (polarity)
-		enabled = !enabled;
-	alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
-}
-
-/* turn on/off mute LED via GPIO per vmaster hook */
-static int gpio_mute_led_set(struct led_classdev *led_cdev,
-			     enum led_brightness brightness)
-{
-	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-	struct alc_spec *spec = codec->spec;
-
-	alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
-			    spec->mute_led_polarity, !brightness);
-	return 0;
-}
-
-/* turn on/off mic-mute LED via GPIO per capture hook */
-static int micmute_led_set(struct led_classdev *led_cdev,
-			   enum led_brightness brightness)
-{
-	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-	struct alc_spec *spec = codec->spec;
-
-	alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
-			    spec->micmute_led_polarity, !brightness);
-	return 0;
-}
-
-/* setup mute and mic-mute GPIO bits, add hooks appropriately */
-static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
-				  int action,
-				  unsigned int mute_mask,
-				  unsigned int micmute_mask)
-{
-	struct alc_spec *spec = codec->spec;
-
-	alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
-
-	if (action != HDA_FIXUP_ACT_PRE_PROBE)
-		return;
-	if (mute_mask) {
-		spec->gpio_mute_led_mask = mute_mask;
-		snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
-	}
-	if (micmute_mask) {
-		spec->gpio_mic_led_mask = micmute_mask;
-		snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
-	}
-}
-
 static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
 				const struct hda_fixup *fix, int action)
 {
@@ -5167,985 +1958,6 @@ static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec,
 	alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
 }
 
-static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
-{
-	if (delay <= 0)
-		delay = 75;
-	snd_hda_codec_write(codec, 0x21, 0,
-		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-	msleep(delay);
-	snd_hda_codec_write(codec, 0x21, 0,
-		    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-	msleep(delay);
-}
-
-static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
-{
-	if (delay <= 0)
-		delay = 75;
-	snd_hda_codec_write(codec, 0x21, 0,
-		    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	msleep(delay);
-	snd_hda_codec_write(codec, 0x21, 0,
-		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-	msleep(delay);
-}
-
-static const struct coef_fw alc225_pre_hsmode[] = {
-	UPDATE_COEF(0x4a, 1<<8, 0),
-	UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
-	UPDATE_COEF(0x63, 3<<14, 3<<14),
-	UPDATE_COEF(0x4a, 3<<4, 2<<4),
-	UPDATE_COEF(0x4a, 3<<10, 3<<10),
-	UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
-	UPDATE_COEF(0x4a, 3<<10, 0),
-	{}
-};
-
-static void alc_headset_mode_unplugged(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	static const struct coef_fw coef0255[] = {
-		WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
-		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
-		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
-		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
-		WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
-		{}
-	};
-	static const struct coef_fw coef0256[] = {
-		WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
-		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
-		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
-		WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
-		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
-		{}
-	};
-	static const struct coef_fw coef0233[] = {
-		WRITE_COEF(0x1b, 0x0c0b),
-		WRITE_COEF(0x45, 0xc429),
-		UPDATE_COEF(0x35, 0x4000, 0),
-		WRITE_COEF(0x06, 0x2104),
-		WRITE_COEF(0x1a, 0x0001),
-		WRITE_COEF(0x26, 0x0004),
-		WRITE_COEF(0x32, 0x42a3),
-		{}
-	};
-	static const struct coef_fw coef0288[] = {
-		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
-		UPDATE_COEF(0x50, 0x2000, 0x2000),
-		UPDATE_COEF(0x56, 0x0006, 0x0006),
-		UPDATE_COEF(0x66, 0x0008, 0),
-		UPDATE_COEF(0x67, 0x2000, 0),
-		{}
-	};
-	static const struct coef_fw coef0298[] = {
-		UPDATE_COEF(0x19, 0x1300, 0x0300),
-		{}
-	};
-	static const struct coef_fw coef0292[] = {
-		WRITE_COEF(0x76, 0x000e),
-		WRITE_COEF(0x6c, 0x2400),
-		WRITE_COEF(0x18, 0x7308),
-		WRITE_COEF(0x6b, 0xc429),
-		{}
-	};
-	static const struct coef_fw coef0293[] = {
-		UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
-		UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
-		UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
-		UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
-		WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
-		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
-		{}
-	};
-	static const struct coef_fw coef0668[] = {
-		WRITE_COEF(0x15, 0x0d40),
-		WRITE_COEF(0xb7, 0x802b),
-		{}
-	};
-	static const struct coef_fw coef0225[] = {
-		UPDATE_COEF(0x63, 3<<14, 0),
-		{}
-	};
-	static const struct coef_fw coef0274[] = {
-		UPDATE_COEF(0x4a, 0x0100, 0),
-		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
-		UPDATE_COEF(0x6b, 0xf000, 0x5000),
-		UPDATE_COEF(0x4a, 0x0010, 0),
-		UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
-		WRITE_COEF(0x45, 0x5289),
-		UPDATE_COEF(0x4a, 0x0c00, 0),
-		{}
-	};
-
-	if (spec->no_internal_mic_pin) {
-		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
-		return;
-	}
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0255:
-		alc_process_coef_fw(codec, coef0255);
-		break;
-	case 0x10ec0230:
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x19e58326:
-		alc_hp_mute_disable(codec, 75);
-		alc_process_coef_fw(codec, coef0256);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-	case 0x10ec0294:
-		alc_process_coef_fw(codec, coef0274);
-		break;
-	case 0x10ec0233:
-	case 0x10ec0283:
-		alc_process_coef_fw(codec, coef0233);
-		break;
-	case 0x10ec0286:
-	case 0x10ec0288:
-		alc_process_coef_fw(codec, coef0288);
-		break;
-	case 0x10ec0298:
-		alc_process_coef_fw(codec, coef0298);
-		alc_process_coef_fw(codec, coef0288);
-		break;
-	case 0x10ec0292:
-		alc_process_coef_fw(codec, coef0292);
-		break;
-	case 0x10ec0293:
-		alc_process_coef_fw(codec, coef0293);
-		break;
-	case 0x10ec0668:
-		alc_process_coef_fw(codec, coef0668);
-		break;
-	case 0x10ec0215:
-	case 0x10ec0225:
-	case 0x10ec0285:
-	case 0x10ec0295:
-	case 0x10ec0289:
-	case 0x10ec0299:
-		alc_hp_mute_disable(codec, 75);
-		alc_process_coef_fw(codec, alc225_pre_hsmode);
-		alc_process_coef_fw(codec, coef0225);
-		break;
-	case 0x10ec0867:
-		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-		break;
-	}
-	codec_dbg(codec, "Headset jack set to unplugged mode.\n");
-}
-
-
-static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
-				    hda_nid_t mic_pin)
-{
-	static const struct coef_fw coef0255[] = {
-		WRITE_COEFEX(0x57, 0x03, 0x8aa6),
-		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
-		{}
-	};
-	static const struct coef_fw coef0256[] = {
-		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
-		WRITE_COEFEX(0x57, 0x03, 0x09a3),
-		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
-		{}
-	};
-	static const struct coef_fw coef0233[] = {
-		UPDATE_COEF(0x35, 0, 1<<14),
-		WRITE_COEF(0x06, 0x2100),
-		WRITE_COEF(0x1a, 0x0021),
-		WRITE_COEF(0x26, 0x008c),
-		{}
-	};
-	static const struct coef_fw coef0288[] = {
-		UPDATE_COEF(0x4f, 0x00c0, 0),
-		UPDATE_COEF(0x50, 0x2000, 0),
-		UPDATE_COEF(0x56, 0x0006, 0),
-		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
-		UPDATE_COEF(0x66, 0x0008, 0x0008),
-		UPDATE_COEF(0x67, 0x2000, 0x2000),
-		{}
-	};
-	static const struct coef_fw coef0292[] = {
-		WRITE_COEF(0x19, 0xa208),
-		WRITE_COEF(0x2e, 0xacf0),
-		{}
-	};
-	static const struct coef_fw coef0293[] = {
-		UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
-		UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
-		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
-		{}
-	};
-	static const struct coef_fw coef0688[] = {
-		WRITE_COEF(0xb7, 0x802b),
-		WRITE_COEF(0xb5, 0x1040),
-		UPDATE_COEF(0xc3, 0, 1<<12),
-		{}
-	};
-	static const struct coef_fw coef0225[] = {
-		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
-		UPDATE_COEF(0x4a, 3<<4, 2<<4),
-		UPDATE_COEF(0x63, 3<<14, 0),
-		{}
-	};
-	static const struct coef_fw coef0274[] = {
-		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
-		UPDATE_COEF(0x4a, 0x0010, 0),
-		UPDATE_COEF(0x6b, 0xf000, 0),
-		{}
-	};
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0255:
-		alc_write_coef_idx(codec, 0x45, 0xc489);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0255);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0230:
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x19e58326:
-		alc_write_coef_idx(codec, 0x45, 0xc489);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0256);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-	case 0x10ec0294:
-		alc_write_coef_idx(codec, 0x45, 0x4689);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0274);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0233:
-	case 0x10ec0283:
-		alc_write_coef_idx(codec, 0x45, 0xc429);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0233);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0286:
-	case 0x10ec0288:
-	case 0x10ec0298:
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0288);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0292:
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0292);
-		break;
-	case 0x10ec0293:
-		/* Set to TRS mode */
-		alc_write_coef_idx(codec, 0x45, 0xc429);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0293);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0867:
-		alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
-		fallthrough;
-	case 0x10ec0221:
-	case 0x10ec0662:
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0668:
-		alc_write_coef_idx(codec, 0x11, 0x0001);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0688);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	case 0x10ec0215:
-	case 0x10ec0225:
-	case 0x10ec0285:
-	case 0x10ec0295:
-	case 0x10ec0289:
-	case 0x10ec0299:
-		alc_process_coef_fw(codec, alc225_pre_hsmode);
-		alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
-		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-		alc_process_coef_fw(codec, coef0225);
-		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-		break;
-	}
-	codec_dbg(codec, "Headset jack set to mic-in mode.\n");
-}
-
-static void alc_headset_mode_default(struct hda_codec *codec)
-{
-	static const struct coef_fw coef0225[] = {
-		UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
-		UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
-		UPDATE_COEF(0x49, 3<<8, 0<<8),
-		UPDATE_COEF(0x4a, 3<<4, 3<<4),
-		UPDATE_COEF(0x63, 3<<14, 0),
-		UPDATE_COEF(0x67, 0xf000, 0x3000),
-		{}
-	};
-	static const struct coef_fw coef0255[] = {
-		WRITE_COEF(0x45, 0xc089),
-		WRITE_COEF(0x45, 0xc489),
-		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
-		WRITE_COEF(0x49, 0x0049),
-		{}
-	};
-	static const struct coef_fw coef0256[] = {
-		WRITE_COEF(0x45, 0xc489),
-		WRITE_COEFEX(0x57, 0x03, 0x0da3),
-		WRITE_COEF(0x49, 0x0049),
-		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
-		WRITE_COEF(0x06, 0x6100),
-		{}
-	};
-	static const struct coef_fw coef0233[] = {
-		WRITE_COEF(0x06, 0x2100),
-		WRITE_COEF(0x32, 0x4ea3),
-		{}
-	};
-	static const struct coef_fw coef0288[] = {
-		UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
-		UPDATE_COEF(0x50, 0x2000, 0x2000),
-		UPDATE_COEF(0x56, 0x0006, 0x0006),
-		UPDATE_COEF(0x66, 0x0008, 0),
-		UPDATE_COEF(0x67, 0x2000, 0),
-		{}
-	};
-	static const struct coef_fw coef0292[] = {
-		WRITE_COEF(0x76, 0x000e),
-		WRITE_COEF(0x6c, 0x2400),
-		WRITE_COEF(0x6b, 0xc429),
-		WRITE_COEF(0x18, 0x7308),
-		{}
-	};
-	static const struct coef_fw coef0293[] = {
-		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
-		WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
-		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
-		{}
-	};
-	static const struct coef_fw coef0688[] = {
-		WRITE_COEF(0x11, 0x0041),
-		WRITE_COEF(0x15, 0x0d40),
-		WRITE_COEF(0xb7, 0x802b),
-		{}
-	};
-	static const struct coef_fw coef0274[] = {
-		WRITE_COEF(0x45, 0x4289),
-		UPDATE_COEF(0x4a, 0x0010, 0x0010),
-		UPDATE_COEF(0x6b, 0x0f00, 0),
-		UPDATE_COEF(0x49, 0x0300, 0x0300),
-		{}
-	};
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0215:
-	case 0x10ec0225:
-	case 0x10ec0285:
-	case 0x10ec0295:
-	case 0x10ec0289:
-	case 0x10ec0299:
-		alc_process_coef_fw(codec, alc225_pre_hsmode);
-		alc_process_coef_fw(codec, coef0225);
-		alc_hp_enable_unmute(codec, 75);
-		break;
-	case 0x10ec0255:
-		alc_process_coef_fw(codec, coef0255);
-		break;
-	case 0x10ec0230:
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x19e58326:
-		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
-		alc_write_coef_idx(codec, 0x45, 0xc089);
-		msleep(50);
-		alc_process_coef_fw(codec, coef0256);
-		alc_hp_enable_unmute(codec, 75);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-	case 0x10ec0294:
-		alc_process_coef_fw(codec, coef0274);
-		break;
-	case 0x10ec0233:
-	case 0x10ec0283:
-		alc_process_coef_fw(codec, coef0233);
-		break;
-	case 0x10ec0286:
-	case 0x10ec0288:
-	case 0x10ec0298:
-		alc_process_coef_fw(codec, coef0288);
-		break;
-	case 0x10ec0292:
-		alc_process_coef_fw(codec, coef0292);
-		break;
-	case 0x10ec0293:
-		alc_process_coef_fw(codec, coef0293);
-		break;
-	case 0x10ec0668:
-		alc_process_coef_fw(codec, coef0688);
-		break;
-	case 0x10ec0867:
-		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-		break;
-	}
-	codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
-}
-
-/* Iphone type */
-static void alc_headset_mode_ctia(struct hda_codec *codec)
-{
-	int val;
-
-	static const struct coef_fw coef0255[] = {
-		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
-		WRITE_COEF(0x1b, 0x0c2b),
-		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
-		{}
-	};
-	static const struct coef_fw coef0256[] = {
-		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
-		WRITE_COEF(0x1b, 0x0e6b),
-		{}
-	};
-	static const struct coef_fw coef0233[] = {
-		WRITE_COEF(0x45, 0xd429),
-		WRITE_COEF(0x1b, 0x0c2b),
-		WRITE_COEF(0x32, 0x4ea3),
-		{}
-	};
-	static const struct coef_fw coef0288[] = {
-		UPDATE_COEF(0x50, 0x2000, 0x2000),
-		UPDATE_COEF(0x56, 0x0006, 0x0006),
-		UPDATE_COEF(0x66, 0x0008, 0),
-		UPDATE_COEF(0x67, 0x2000, 0),
-		{}
-	};
-	static const struct coef_fw coef0292[] = {
-		WRITE_COEF(0x6b, 0xd429),
-		WRITE_COEF(0x76, 0x0008),
-		WRITE_COEF(0x18, 0x7388),
-		{}
-	};
-	static const struct coef_fw coef0293[] = {
-		WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
-		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
-		{}
-	};
-	static const struct coef_fw coef0688[] = {
-		WRITE_COEF(0x11, 0x0001),
-		WRITE_COEF(0x15, 0x0d60),
-		WRITE_COEF(0xc3, 0x0000),
-		{}
-	};
-	static const struct coef_fw coef0225_1[] = {
-		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
-		UPDATE_COEF(0x63, 3<<14, 2<<14),
-		{}
-	};
-	static const struct coef_fw coef0225_2[] = {
-		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
-		UPDATE_COEF(0x63, 3<<14, 1<<14),
-		{}
-	};
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0255:
-		alc_process_coef_fw(codec, coef0255);
-		break;
-	case 0x10ec0230:
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x19e58326:
-		alc_process_coef_fw(codec, coef0256);
-		alc_hp_enable_unmute(codec, 75);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-	case 0x10ec0294:
-		alc_write_coef_idx(codec, 0x45, 0xd689);
-		break;
-	case 0x10ec0233:
-	case 0x10ec0283:
-		alc_process_coef_fw(codec, coef0233);
-		break;
-	case 0x10ec0298:
-		val = alc_read_coef_idx(codec, 0x50);
-		if (val & (1 << 12)) {
-			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
-			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
-			msleep(300);
-		} else {
-			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
-			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
-			msleep(300);
-		}
-		break;
-	case 0x10ec0286:
-	case 0x10ec0288:
-		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
-		msleep(300);
-		alc_process_coef_fw(codec, coef0288);
-		break;
-	case 0x10ec0292:
-		alc_process_coef_fw(codec, coef0292);
-		break;
-	case 0x10ec0293:
-		alc_process_coef_fw(codec, coef0293);
-		break;
-	case 0x10ec0668:
-		alc_process_coef_fw(codec, coef0688);
-		break;
-	case 0x10ec0215:
-	case 0x10ec0225:
-	case 0x10ec0285:
-	case 0x10ec0295:
-	case 0x10ec0289:
-	case 0x10ec0299:
-		val = alc_read_coef_idx(codec, 0x45);
-		if (val & (1 << 9))
-			alc_process_coef_fw(codec, coef0225_2);
-		else
-			alc_process_coef_fw(codec, coef0225_1);
-		alc_hp_enable_unmute(codec, 75);
-		break;
-	case 0x10ec0867:
-		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-		break;
-	}
-	codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
-}
-
-/* Nokia type */
-static void alc_headset_mode_omtp(struct hda_codec *codec)
-{
-	static const struct coef_fw coef0255[] = {
-		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
-		WRITE_COEF(0x1b, 0x0c2b),
-		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
-		{}
-	};
-	static const struct coef_fw coef0256[] = {
-		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
-		WRITE_COEF(0x1b, 0x0e6b),
-		{}
-	};
-	static const struct coef_fw coef0233[] = {
-		WRITE_COEF(0x45, 0xe429),
-		WRITE_COEF(0x1b, 0x0c2b),
-		WRITE_COEF(0x32, 0x4ea3),
-		{}
-	};
-	static const struct coef_fw coef0288[] = {
-		UPDATE_COEF(0x50, 0x2000, 0x2000),
-		UPDATE_COEF(0x56, 0x0006, 0x0006),
-		UPDATE_COEF(0x66, 0x0008, 0),
-		UPDATE_COEF(0x67, 0x2000, 0),
-		{}
-	};
-	static const struct coef_fw coef0292[] = {
-		WRITE_COEF(0x6b, 0xe429),
-		WRITE_COEF(0x76, 0x0008),
-		WRITE_COEF(0x18, 0x7388),
-		{}
-	};
-	static const struct coef_fw coef0293[] = {
-		WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
-		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
-		{}
-	};
-	static const struct coef_fw coef0688[] = {
-		WRITE_COEF(0x11, 0x0001),
-		WRITE_COEF(0x15, 0x0d50),
-		WRITE_COEF(0xc3, 0x0000),
-		{}
-	};
-	static const struct coef_fw coef0225[] = {
-		UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
-		UPDATE_COEF(0x63, 3<<14, 2<<14),
-		{}
-	};
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0255:
-		alc_process_coef_fw(codec, coef0255);
-		break;
-	case 0x10ec0230:
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x19e58326:
-		alc_process_coef_fw(codec, coef0256);
-		alc_hp_enable_unmute(codec, 75);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-	case 0x10ec0294:
-		alc_write_coef_idx(codec, 0x45, 0xe689);
-		break;
-	case 0x10ec0233:
-	case 0x10ec0283:
-		alc_process_coef_fw(codec, coef0233);
-		break;
-	case 0x10ec0298:
-		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
-		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
-		msleep(300);
-		break;
-	case 0x10ec0286:
-	case 0x10ec0288:
-		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
-		msleep(300);
-		alc_process_coef_fw(codec, coef0288);
-		break;
-	case 0x10ec0292:
-		alc_process_coef_fw(codec, coef0292);
-		break;
-	case 0x10ec0293:
-		alc_process_coef_fw(codec, coef0293);
-		break;
-	case 0x10ec0668:
-		alc_process_coef_fw(codec, coef0688);
-		break;
-	case 0x10ec0215:
-	case 0x10ec0225:
-	case 0x10ec0285:
-	case 0x10ec0295:
-	case 0x10ec0289:
-	case 0x10ec0299:
-		alc_process_coef_fw(codec, coef0225);
-		alc_hp_enable_unmute(codec, 75);
-		break;
-	}
-	codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
-}
-
-static void alc_determine_headset_type(struct hda_codec *codec)
-{
-	int val;
-	bool is_ctia = false;
-	struct alc_spec *spec = codec->spec;
-	static const struct coef_fw coef0255[] = {
-		WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
-		WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
- conteol) */
-		{}
-	};
-	static const struct coef_fw coef0288[] = {
-		UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
-		{}
-	};
-	static const struct coef_fw coef0298[] = {
-		UPDATE_COEF(0x50, 0x2000, 0x2000),
-		UPDATE_COEF(0x56, 0x0006, 0x0006),
-		UPDATE_COEF(0x66, 0x0008, 0),
-		UPDATE_COEF(0x67, 0x2000, 0),
-		UPDATE_COEF(0x19, 0x1300, 0x1300),
-		{}
-	};
-	static const struct coef_fw coef0293[] = {
-		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
-		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
-		{}
-	};
-	static const struct coef_fw coef0688[] = {
-		WRITE_COEF(0x11, 0x0001),
-		WRITE_COEF(0xb7, 0x802b),
-		WRITE_COEF(0x15, 0x0d60),
-		WRITE_COEF(0xc3, 0x0c00),
-		{}
-	};
-	static const struct coef_fw coef0274[] = {
-		UPDATE_COEF(0x4a, 0x0010, 0),
-		UPDATE_COEF(0x4a, 0x8000, 0),
-		WRITE_COEF(0x45, 0xd289),
-		UPDATE_COEF(0x49, 0x0300, 0x0300),
-		{}
-	};
-
-	if (spec->no_internal_mic_pin) {
-		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
-		return;
-	}
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0255:
-		alc_process_coef_fw(codec, coef0255);
-		msleep(300);
-		val = alc_read_coef_idx(codec, 0x46);
-		is_ctia = (val & 0x0070) == 0x0070;
-		break;
-	case 0x10ec0230:
-	case 0x10ec0236:
-	case 0x10ec0256:
-	case 0x19e58326:
-		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
-		alc_write_coef_idx(codec, 0x06, 0x6104);
-		alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
-
-		alc_process_coef_fw(codec, coef0255);
-		msleep(300);
-		val = alc_read_coef_idx(codec, 0x46);
-		is_ctia = (val & 0x0070) == 0x0070;
-		if (!is_ctia) {
-			alc_write_coef_idx(codec, 0x45, 0xe089);
-			msleep(100);
-			val = alc_read_coef_idx(codec, 0x46);
-			if ((val & 0x0070) == 0x0070)
-				is_ctia = false;
-			else
-				is_ctia = true;
-		}
-		alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
-		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-		break;
-	case 0x10ec0234:
-	case 0x10ec0274:
-	case 0x10ec0294:
-		alc_process_coef_fw(codec, coef0274);
-		msleep(850);
-		val = alc_read_coef_idx(codec, 0x46);
-		is_ctia = (val & 0x00f0) == 0x00f0;
-		break;
-	case 0x10ec0233:
-	case 0x10ec0283:
-		alc_write_coef_idx(codec, 0x45, 0xd029);
-		msleep(300);
-		val = alc_read_coef_idx(codec, 0x46);
-		is_ctia = (val & 0x0070) == 0x0070;
-		break;
-	case 0x10ec0298:
-		snd_hda_codec_write(codec, 0x21, 0,
-			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-		msleep(100);
-		snd_hda_codec_write(codec, 0x21, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-		msleep(200);
-
-		val = alc_read_coef_idx(codec, 0x50);
-		if (val & (1 << 12)) {
-			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
-			alc_process_coef_fw(codec, coef0288);
-			msleep(350);
-			val = alc_read_coef_idx(codec, 0x50);
-			is_ctia = (val & 0x0070) == 0x0070;
-		} else {
-			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
-			alc_process_coef_fw(codec, coef0288);
-			msleep(350);
-			val = alc_read_coef_idx(codec, 0x50);
-			is_ctia = (val & 0x0070) == 0x0070;
-		}
-		alc_process_coef_fw(codec, coef0298);
-		snd_hda_codec_write(codec, 0x21, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
-		msleep(75);
-		snd_hda_codec_write(codec, 0x21, 0,
-			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-		break;
-	case 0x10ec0286:
-	case 0x10ec0288:
-		alc_process_coef_fw(codec, coef0288);
-		msleep(350);
-		val = alc_read_coef_idx(codec, 0x50);
-		is_ctia = (val & 0x0070) == 0x0070;
-		break;
-	case 0x10ec0292:
-		alc_write_coef_idx(codec, 0x6b, 0xd429);
-		msleep(300);
-		val = alc_read_coef_idx(codec, 0x6c);
-		is_ctia = (val & 0x001c) == 0x001c;
-		break;
-	case 0x10ec0293:
-		alc_process_coef_fw(codec, coef0293);
-		msleep(300);
-		val = alc_read_coef_idx(codec, 0x46);
-		is_ctia = (val & 0x0070) == 0x0070;
-		break;
-	case 0x10ec0668:
-		alc_process_coef_fw(codec, coef0688);
-		msleep(300);
-		val = alc_read_coef_idx(codec, 0xbe);
-		is_ctia = (val & 0x1c02) == 0x1c02;
-		break;
-	case 0x10ec0215:
-	case 0x10ec0225:
-	case 0x10ec0285:
-	case 0x10ec0295:
-	case 0x10ec0289:
-	case 0x10ec0299:
-		alc_process_coef_fw(codec, alc225_pre_hsmode);
-		alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
-		val = alc_read_coef_idx(codec, 0x45);
-		if (val & (1 << 9)) {
-			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
-			alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
-			msleep(800);
-			val = alc_read_coef_idx(codec, 0x46);
-			is_ctia = (val & 0x00f0) == 0x00f0;
-		} else {
-			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
-			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
-			msleep(800);
-			val = alc_read_coef_idx(codec, 0x46);
-			is_ctia = (val & 0x00f0) == 0x00f0;
-		}
-		if (!is_ctia) {
-			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
-			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
-			msleep(100);
-			val = alc_read_coef_idx(codec, 0x46);
-			if ((val & 0x00f0) == 0x00f0)
-				is_ctia = false;
-			else
-				is_ctia = true;
-		}
-		alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
-		alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
-		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
-		break;
-	case 0x10ec0867:
-		is_ctia = true;
-		break;
-	}
-
-	codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
-		  str_yes_no(is_ctia));
-	spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
-}
-
-static void alc_update_headset_mode(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-
-	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
-	hda_nid_t hp_pin = alc_get_hp_pin(spec);
-
-	int new_headset_mode;
-
-	if (!snd_hda_jack_detect(codec, hp_pin))
-		new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
-	else if (mux_pin == spec->headset_mic_pin)
-		new_headset_mode = ALC_HEADSET_MODE_HEADSET;
-	else if (mux_pin == spec->headphone_mic_pin)
-		new_headset_mode = ALC_HEADSET_MODE_MIC;
-	else
-		new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
-
-	if (new_headset_mode == spec->current_headset_mode) {
-		snd_hda_gen_update_outputs(codec);
-		return;
-	}
-
-	switch (new_headset_mode) {
-	case ALC_HEADSET_MODE_UNPLUGGED:
-		alc_headset_mode_unplugged(codec);
-		spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
-		spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
-		spec->gen.hp_jack_present = false;
-		break;
-	case ALC_HEADSET_MODE_HEADSET:
-		if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
-			alc_determine_headset_type(codec);
-		if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
-			alc_headset_mode_ctia(codec);
-		else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
-			alc_headset_mode_omtp(codec);
-		spec->gen.hp_jack_present = true;
-		break;
-	case ALC_HEADSET_MODE_MIC:
-		alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
-		spec->gen.hp_jack_present = false;
-		break;
-	case ALC_HEADSET_MODE_HEADPHONE:
-		alc_headset_mode_default(codec);
-		spec->gen.hp_jack_present = true;
-		break;
-	}
-	if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
-		snd_hda_set_pin_ctl_cache(codec, hp_pin,
-					  AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
-		if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
-			snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
-						  PIN_VREFHIZ);
-	}
-	spec->current_headset_mode = new_headset_mode;
-
-	snd_hda_gen_update_outputs(codec);
-}
-
-static void alc_update_headset_mode_hook(struct hda_codec *codec,
-					 struct snd_kcontrol *kcontrol,
-					 struct snd_ctl_elem_value *ucontrol)
-{
-	alc_update_headset_mode(codec);
-}
-
-static void alc_update_headset_jack_cb(struct hda_codec *codec,
-				       struct hda_jack_callback *jack)
-{
-	snd_hda_gen_hp_automute(codec, jack);
-	alc_update_headset_mode(codec);
-}
-
-static void alc_probe_headset_mode(struct hda_codec *codec)
-{
-	int i;
-	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-
-	/* Find mic pins */
-	for (i = 0; i < cfg->num_inputs; i++) {
-		if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
-			spec->headset_mic_pin = cfg->inputs[i].pin;
-		if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
-			spec->headphone_mic_pin = cfg->inputs[i].pin;
-	}
-
-	WARN_ON(spec->gen.cap_sync_hook);
-	spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
-	spec->gen.automute_hook = alc_update_headset_mode;
-	spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
-}
-
-static void alc_fixup_headset_mode(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
-		break;
-	case HDA_FIXUP_ACT_PROBE:
-		alc_probe_headset_mode(codec);
-		break;
-	case HDA_FIXUP_ACT_INIT:
-		if (is_s3_resume(codec) || is_s4_resume(codec)) {
-			spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
-			spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
-		}
-		alc_update_headset_mode(codec);
-		break;
-	}
-}
-
-static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		struct alc_spec *spec = codec->spec;
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-	}
-	else
-		alc_fixup_headset_mode(codec, fix, action);
-}
-
 static void alc255_set_default_jack_type(struct hda_codec *codec)
 {
 	/* Set to iphone type */
@@ -6223,15 +2035,6 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
 	}
 }
 
-static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
-					const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		struct alc_spec *spec = codec->spec;
-		spec->gen.auto_mute_via_amp = 1;
-	}
-}
-
 static void alc_fixup_no_shutup(struct hda_codec *codec,
 				const struct hda_fixup *fix, int action)
 {
@@ -6241,16 +2044,6 @@ static void alc_fixup_no_shutup(struct hda_codec *codec,
 	}
 }
 
-static void alc_fixup_disable_aamix(struct hda_codec *codec,
-				    const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		struct alc_spec *spec = codec->spec;
-		/* Disable AA-loopback as it causes white noise */
-		spec->gen.mixer_nid = 0;
-	}
-}
-
 /* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */
 static void alc_fixup_tpt440_dock(struct hda_codec *codec,
 				  const struct hda_fixup *fix, int action)
@@ -6321,94 +2114,6 @@ static void alc295_fixup_asus_dacs(struct hda_codec *codec,
 		spec->gen.preferred_dacs = preferred_pairs;
 }
 
-static void alc_shutup_dell_xps13(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	int hp_pin = alc_get_hp_pin(spec);
-
-	/* Prevent pop noises when headphones are plugged in */
-	snd_hda_codec_write(codec, hp_pin, 0,
-			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-	msleep(20);
-}
-
-static void alc_fixup_dell_xps13(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	struct hda_input_mux *imux = &spec->gen.input_mux;
-	int i;
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		/* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
-		 * it causes a click noise at start up
-		 */
-		snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
-		spec->shutup = alc_shutup_dell_xps13;
-		break;
-	case HDA_FIXUP_ACT_PROBE:
-		/* Make the internal mic the default input source. */
-		for (i = 0; i < imux->num_items; i++) {
-			if (spec->gen.imux_pins[i] == 0x12) {
-				spec->gen.cur_mux[0] = i;
-				break;
-			}
-		}
-		break;
-	}
-}
-
-static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-		spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
-
-		/* Disable boost for mic-in permanently. (This code is only called
-		   from quirks that guarantee that the headphone is at NID 0x1b.) */
-		snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
-		snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
-	} else
-		alc_fixup_headset_mode(codec, fix, action);
-}
-
-static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		alc_write_coef_idx(codec, 0xc4, 0x8000);
-		alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
-		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
-	}
-	alc_fixup_headset_mode(codec, fix, action);
-}
-
-/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
-static int find_ext_mic_pin(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-	hda_nid_t nid;
-	unsigned int defcfg;
-	int i;
-
-	for (i = 0; i < cfg->num_inputs; i++) {
-		if (cfg->inputs[i].type != AUTO_PIN_MIC)
-			continue;
-		nid = cfg->inputs[i].pin;
-		defcfg = snd_hda_codec_get_pincfg(codec, nid);
-		if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
-			continue;
-		return nid;
-	}
-
-	return 0;
-}
-
 static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
 				    const struct hda_fixup *fix,
 				    int action)
@@ -6416,7 +2121,7 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
 	struct alc_spec *spec = codec->spec;
 
 	if (action == HDA_FIXUP_ACT_PROBE) {
-		int mic_pin = find_ext_mic_pin(codec);
+		int mic_pin = alc_find_ext_mic_pin(codec);
 		int hp_pin = alc_get_hp_pin(spec);
 
 		if (snd_BUG_ON(!mic_pin || !hp_pin))
@@ -6694,30 +2399,6 @@ static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec,
 	}
 }
 
-static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
-					 const struct hda_fixup *fix,
-					 int action)
-{
-	alc_fixup_dual_codecs(codec, fix, action);
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		/* override card longname to provide a unique UCM profile */
-		strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
-		break;
-	case HDA_FIXUP_ACT_BUILD:
-		/* rename Capture controls depending on the codec */
-		rename_ctl(codec, "Capture Volume",
-			   codec->addr == 0 ?
-			   "Rear-Panel Capture Volume" :
-			   "Front-Panel Capture Volume");
-		rename_ctl(codec, "Capture Switch",
-			   codec->addr == 0 ?
-			   "Rear-Panel Capture Switch" :
-			   "Front-Panel Capture Switch");
-		break;
-	}
-}
-
 static void alc225_fixup_s3_pop_noise(struct hda_codec *codec,
 				      const struct hda_fixup *fix, int action)
 {
@@ -7120,7 +2801,7 @@ static void alc285_fixup_hp_beep(struct hda_codec *codec,
 }
 
 /* for hda_fixup_thinkpad_acpi() */
-#include "helpers/thinkpad.c"
+#include "../helpers/thinkpad.c"
 
 static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 				    const struct hda_fixup *fix, int action)
@@ -7130,7 +2811,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
 }
 
 /* for hda_fixup_ideapad_acpi() */
-#include "helpers/ideapad_hotkey_led.c"
+#include "../helpers/ideapad_hotkey_led.c"
 
 static void alc_fixup_ideapad_acpi(struct hda_codec *codec,
 				   const struct hda_fixup *fix, int action)
@@ -7362,10 +3043,10 @@ static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
 
 
 /* for alc295_fixup_hp_top_speakers */
-#include "helpers/hp_x360.c"
+#include "../helpers/hp_x360.c"
 
 /* for alc285_fixup_ideapad_s740_coef() */
-#include "helpers/ideapad_s740.c"
+#include "../helpers/ideapad_s740.c"
 
 static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
 	WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
@@ -7567,9 +3248,10 @@ static void alc287_fixup_bind_dacs(struct hda_codec *codec,
 					0x0); /* Make sure 0x14 was disable */
 	}
 }
+
 /* Fix none verb table of Headset Mic pin */
-static void alc_fixup_headset_mic(struct hda_codec *codec,
-				   const struct hda_fixup *fix, int action)
+static void alc2xx_fixup_headset_mic(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
 {
 	struct alc_spec *spec = codec->spec;
 	static const struct hda_pintbl pincfgs[] = {
@@ -8164,7 +3846,7 @@ static const struct hda_fixup alc269_fixups[] = {
 	},
 	[ALC269_FIXUP_HEADSET_MIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc269_fixup_headset_mic,
+		.v.func = alc_fixup_headset_mic,
 	},
 	[ALC269_FIXUP_QUANTA_MUTE] = {
 		.type = HDA_FIXUP_FUNC,
@@ -10324,7 +6006,7 @@ static const struct hda_fixup alc269_fixups[] = {
 	},
 	[ALC2XX_FIXUP_HEADSET_MIC] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_headset_mic,
+		.v.func = alc2xx_fixup_headset_mic,
 	},
 	[ALC289_FIXUP_DELL_CS35L41_SPI_2] = {
 		.type = HDA_FIXUP_FUNC,
@@ -12159,6 +7841,16 @@ static void alc269_fill_coef(struct hda_codec *codec)
 	alc_update_coef_idx(codec, 0x4, 0, 1<<11);
 }
 
+static void alc269_free(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (spec)
+		hda_component_manager_free(&spec->comps, &comp_master_ops);
+
+	alc_free(codec);
+}
+
 /*
  */
 static int patch_alc269(struct hda_codec *codec)
@@ -12177,6 +7869,7 @@ static int patch_alc269(struct hda_codec *codec)
 
 	codec->patch_ops.suspend = alc269_suspend;
 	codec->patch_ops.resume = alc269_resume;
+	codec->patch_ops.free = alc269_free;
 	spec->shutup = alc_default_shutup;
 	spec->init_hook = alc_default_init;
 
@@ -12379,1327 +8072,9 @@ static int patch_alc269(struct hda_codec *codec)
 }
 
 /*
- * ALC861
+ * driver entries
  */
-
-static int alc861_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
-	static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
-	return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
-}
-
-/* Pin config fixes */
-enum {
-	ALC861_FIXUP_FSC_AMILO_PI1505,
-	ALC861_FIXUP_AMP_VREF_0F,
-	ALC861_FIXUP_NO_JACK_DETECT,
-	ALC861_FIXUP_ASUS_A6RP,
-	ALC660_FIXUP_ASUS_W7J,
-};
-
-/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
-static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
-			const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	unsigned int val;
-
-	if (action != HDA_FIXUP_ACT_INIT)
-		return;
-	val = snd_hda_codec_get_pin_target(codec, 0x0f);
-	if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
-		val |= AC_PINCTL_IN_EN;
-	val |= AC_PINCTL_VREF_50;
-	snd_hda_set_pin_ctl(codec, 0x0f, val);
-	spec->gen.keep_vref_in_automute = 1;
-}
-
-/* suppress the jack-detection */
-static void alc_fixup_no_jack_detect(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		codec->no_jack_detect = 1;
-}
-
-static const struct hda_fixup alc861_fixups[] = {
-	[ALC861_FIXUP_FSC_AMILO_PI1505] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x0b, 0x0221101f }, /* HP */
-			{ 0x0f, 0x90170310 }, /* speaker */
-			{ }
-		}
-	},
-	[ALC861_FIXUP_AMP_VREF_0F] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc861_fixup_asus_amp_vref_0f,
-	},
-	[ALC861_FIXUP_NO_JACK_DETECT] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_no_jack_detect,
-	},
-	[ALC861_FIXUP_ASUS_A6RP] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc861_fixup_asus_amp_vref_0f,
-		.chained = true,
-		.chain_id = ALC861_FIXUP_NO_JACK_DETECT,
-	},
-	[ALC660_FIXUP_ASUS_W7J] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			/* ASUS W7J needs a magic pin setup on unused NID 0x10
-			 * for enabling outputs
-			 */
-			{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-			{ }
-		},
-	}
-};
-
-static const struct hda_quirk alc861_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
-	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
-	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
-	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
-	SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
-	SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
-	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
-	{}
-};
-
-/*
- */
-static int patch_alc861(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x15);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-	if (has_cdefine_beep(codec))
-		spec->gen.beep_nid = 0x23;
-
-	spec->power_hook = alc_power_eapd;
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	/* automatic parse from the BIOS config */
-	err = alc861_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog) {
-		err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-/*
- * ALC861-VD support
- *
- * Based on ALC882
- *
- * In addition, an independent DAC
- */
-static int alc861vd_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
-	static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
-}
-
-enum {
-	ALC660VD_FIX_ASUS_GPIO1,
-	ALC861VD_FIX_DALLAS,
-};
-
-/* exclude VREF80 */
-static void alc861vd_fixup_dallas(struct hda_codec *codec,
-				  const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
-		snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
-	}
-}
-
-/* reset GPIO1 */
-static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
-				      const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		spec->gpio_mask |= 0x02;
-	alc_fixup_gpio(codec, action, 0x01);
-}
-
-static const struct hda_fixup alc861vd_fixups[] = {
-	[ALC660VD_FIX_ASUS_GPIO1] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc660vd_fixup_asus_gpio1,
-	},
-	[ALC861VD_FIX_DALLAS] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc861vd_fixup_dallas,
-	},
-};
-
-static const struct hda_quirk alc861vd_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
-	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
-	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
-	{}
-};
-
-/*
- */
-static int patch_alc861vd(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x0b);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-	if (has_cdefine_beep(codec))
-		spec->gen.beep_nid = 0x23;
-
-	spec->shutup = alc_eapd_shutup;
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	/* automatic parse from the BIOS config */
-	err = alc861vd_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog) {
-		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-/*
- * ALC662 support
- *
- * ALC662 is almost identical with ALC880 but has cleaner and more flexible
- * configuration.  Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs.  This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-
-/*
- * BIOS auto configuration
- */
-
-static int alc662_parse_auto_config(struct hda_codec *codec)
-{
-	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
-	static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
-	static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-	const hda_nid_t *ssids;
-
-	if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
-	    codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
-	    codec->core.vendor_id == 0x10ec0671)
-		ssids = alc663_ssids;
-	else
-		ssids = alc662_ssids;
-	return alc_parse_auto_config(codec, alc662_ignore, ssids);
-}
-
-static void alc272_fixup_mario(struct hda_codec *codec,
-			       const struct hda_fixup *fix, int action)
-{
-	if (action != HDA_FIXUP_ACT_PRE_PROBE)
-		return;
-	if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
-				      (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
-				      (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
-				      (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-				      (0 << AC_AMPCAP_MUTE_SHIFT)))
-		codec_warn(codec, "failed to override amp caps for NID 0x2\n");
-}
-
-static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
-	{ .channels = 2,
-	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
-	{ .channels = 4,
-	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
-		   SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
-	{ }
-};
-
-/* override the 2.1 chmap */
-static void alc_fixup_bass_chmap(struct hda_codec *codec,
-				    const struct hda_fixup *fix, int action)
-{
-	if (action == HDA_FIXUP_ACT_BUILD) {
-		struct alc_spec *spec = codec->spec;
-		spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
-	}
-}
-
-/* avoid D3 for keeping GPIO up */
-static unsigned int gpio_led_power_filter(struct hda_codec *codec,
-					  hda_nid_t nid,
-					  unsigned int power_state)
-{
-	struct alc_spec *spec = codec->spec;
-	if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
-		return AC_PWRST_D0;
-	return power_state;
-}
-
-static void alc662_fixup_led_gpio1(struct hda_codec *codec,
-				   const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->mute_led_polarity = 1;
-		codec->power_filter = gpio_led_power_filter;
-	}
-}
-
-static void alc662_usi_automute_hook(struct hda_codec *codec,
-					 struct hda_jack_callback *jack)
-{
-	struct alc_spec *spec = codec->spec;
-	int vref;
-	msleep(200);
-	snd_hda_gen_hp_automute(codec, jack);
-
-	vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
-	msleep(100);
-	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    vref);
-}
-
-static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-		spec->gen.hp_automute_hook = alc662_usi_automute_hook;
-	}
-}
-
-static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
-					struct hda_jack_callback *cb)
-{
-	/* surround speakers at 0x1b already get muted automatically when
-	 * headphones are plugged in, but we have to mute/unmute the remaining
-	 * channels manually:
-	 * 0x15 - front left/front right
-	 * 0x18 - front center/ LFE
-	 */
-	if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
-		snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
-		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
-	} else {
-		snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
-		snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
-	}
-}
-
-static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
-					const struct hda_fixup *fix, int action)
-{
-    /* Pin 0x1b: shared headphones jack and surround speakers */
-	if (!is_jack_detectable(codec, 0x1b))
-		return;
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		snd_hda_jack_detect_enable_callback(codec, 0x1b,
-				alc662_aspire_ethos_mute_speakers);
-		/* subwoofer needs an extra GPIO setting to become audible */
-		alc_setup_gpio(codec, 0x02);
-		break;
-	case HDA_FIXUP_ACT_INIT:
-		/* Make sure to start in a correct state, i.e. if
-		 * headphones have been plugged in before powering up the system
-		 */
-		alc662_aspire_ethos_mute_speakers(codec, NULL);
-		break;
-	}
-}
-
-static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
-					     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	static const struct hda_pintbl pincfgs[] = {
-		{ 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
-		{ 0x1b, 0x0181304f },
-		{ }
-	};
-
-	switch (action) {
-	case HDA_FIXUP_ACT_PRE_PROBE:
-		spec->gen.mixer_nid = 0;
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-		snd_hda_apply_pincfgs(codec, pincfgs);
-		break;
-	case HDA_FIXUP_ACT_INIT:
-		alc_write_coef_idx(codec, 0x19, 0xa054);
-		break;
-	}
-}
-
-static void alc897_hp_automute_hook(struct hda_codec *codec,
-					 struct hda_jack_callback *jack)
-{
-	struct alc_spec *spec = codec->spec;
-	int vref;
-
-	snd_hda_gen_hp_automute(codec, jack);
-	vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
-	snd_hda_set_pin_ctl(codec, 0x1b, vref);
-}
-
-static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
-		spec->no_shutup_pins = 1;
-	}
-	if (action == HDA_FIXUP_ACT_PROBE) {
-		snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
-	}
-}
-
-static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
-				     const struct hda_fixup *fix, int action)
-{
-	struct alc_spec *spec = codec->spec;
-
-	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
-	}
-}
-
-static const struct coef_fw alc668_coefs[] = {
-	WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
-	WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
-	WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b,    0x0),
-	WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
-	WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
-	WRITE_COEF(0x13,    0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
-	WRITE_COEF(0x19,    0x0), WRITE_COEF(0x1a,    0x0), WRITE_COEF(0x1b,    0x0),
-	WRITE_COEF(0x1c,    0x0), WRITE_COEF(0x1d,    0x0), WRITE_COEF(0x1e, 0x7418),
-	WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
-	WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
-	WRITE_COEF(0x27,    0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
-	WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
-	WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac,    0x0),
-	WRITE_COEF(0xad,    0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
-	WRITE_COEF(0xb0,    0x0), WRITE_COEF(0xb1,    0x0), WRITE_COEF(0xb2,    0x0),
-	WRITE_COEF(0xb3,    0x0), WRITE_COEF(0xb4,    0x0), WRITE_COEF(0xb5, 0x1040),
-	WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
-	WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
-	WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
-	WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
-	{}
-};
-
-static void alc668_restore_default_value(struct hda_codec *codec)
-{
-	alc_process_coef_fw(codec, alc668_coefs);
-}
-
-enum {
-	ALC662_FIXUP_ASPIRE,
-	ALC662_FIXUP_LED_GPIO1,
-	ALC662_FIXUP_IDEAPAD,
-	ALC272_FIXUP_MARIO,
-	ALC662_FIXUP_CZC_ET26,
-	ALC662_FIXUP_CZC_P10T,
-	ALC662_FIXUP_SKU_IGNORE,
-	ALC662_FIXUP_HP_RP5800,
-	ALC662_FIXUP_ASUS_MODE1,
-	ALC662_FIXUP_ASUS_MODE2,
-	ALC662_FIXUP_ASUS_MODE3,
-	ALC662_FIXUP_ASUS_MODE4,
-	ALC662_FIXUP_ASUS_MODE5,
-	ALC662_FIXUP_ASUS_MODE6,
-	ALC662_FIXUP_ASUS_MODE7,
-	ALC662_FIXUP_ASUS_MODE8,
-	ALC662_FIXUP_NO_JACK_DETECT,
-	ALC662_FIXUP_ZOTAC_Z68,
-	ALC662_FIXUP_INV_DMIC,
-	ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
-	ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
-	ALC662_FIXUP_HEADSET_MODE,
-	ALC668_FIXUP_HEADSET_MODE,
-	ALC662_FIXUP_BASS_MODE4_CHMAP,
-	ALC662_FIXUP_BASS_16,
-	ALC662_FIXUP_BASS_1A,
-	ALC662_FIXUP_BASS_CHMAP,
-	ALC668_FIXUP_AUTO_MUTE,
-	ALC668_FIXUP_DELL_DISABLE_AAMIX,
-	ALC668_FIXUP_DELL_XPS13,
-	ALC662_FIXUP_ASUS_Nx50,
-	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
-	ALC668_FIXUP_ASUS_Nx51,
-	ALC668_FIXUP_MIC_COEF,
-	ALC668_FIXUP_ASUS_G751,
-	ALC891_FIXUP_HEADSET_MODE,
-	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
-	ALC662_FIXUP_ACER_VERITON,
-	ALC892_FIXUP_ASROCK_MOBO,
-	ALC662_FIXUP_USI_FUNC,
-	ALC662_FIXUP_USI_HEADSET_MODE,
-	ALC662_FIXUP_LENOVO_MULTI_CODECS,
-	ALC669_FIXUP_ACER_ASPIRE_ETHOS,
-	ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
-	ALC671_FIXUP_HP_HEADSET_MIC2,
-	ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
-	ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
-	ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
-	ALC668_FIXUP_HEADSET_MIC,
-	ALC668_FIXUP_MIC_DET_COEF,
-	ALC897_FIXUP_LENOVO_HEADSET_MIC,
-	ALC897_FIXUP_HEADSET_MIC_PIN,
-	ALC897_FIXUP_HP_HSMIC_VERB,
-	ALC897_FIXUP_LENOVO_HEADSET_MODE,
-	ALC897_FIXUP_HEADSET_MIC_PIN2,
-	ALC897_FIXUP_UNIS_H3C_X500S,
-	ALC897_FIXUP_HEADSET_MIC_PIN3,
-};
-
-static const struct hda_fixup alc662_fixups[] = {
-	[ALC662_FIXUP_ASPIRE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x99130112 }, /* subwoofer */
-			{ }
-		}
-	},
-	[ALC662_FIXUP_LED_GPIO1] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc662_fixup_led_gpio1,
-	},
-	[ALC662_FIXUP_IDEAPAD] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x17, 0x99130112 }, /* subwoofer */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_LED_GPIO1,
-	},
-	[ALC272_FIXUP_MARIO] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc272_fixup_mario,
-	},
-	[ALC662_FIXUP_CZC_ET26] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{0x12, 0x403cc000},
-			{0x14, 0x90170110}, /* speaker */
-			{0x15, 0x411111f0},
-			{0x16, 0x411111f0},
-			{0x18, 0x01a19030}, /* mic */
-			{0x19, 0x90a7013f}, /* int-mic */
-			{0x1a, 0x01014020},
-			{0x1b, 0x0121401f},
-			{0x1c, 0x411111f0},
-			{0x1d, 0x411111f0},
-			{0x1e, 0x40478e35},
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_CZC_P10T] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
-			{}
-		}
-	},
-	[ALC662_FIXUP_SKU_IGNORE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_sku_ignore,
-	},
-	[ALC662_FIXUP_HP_RP5800] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x0221201f }, /* HP out */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE1] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x18, 0x01a19c20 }, /* mic */
-			{ 0x19, 0x99a3092f }, /* int-mic */
-			{ 0x21, 0x0121401f }, /* HP out */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE2] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x18, 0x01a19820 }, /* mic */
-			{ 0x19, 0x99a3092f }, /* int-mic */
-			{ 0x1b, 0x0121401f }, /* HP out */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE3] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x15, 0x0121441f }, /* HP */
-			{ 0x18, 0x01a19840 }, /* mic */
-			{ 0x19, 0x99a3094f }, /* int-mic */
-			{ 0x21, 0x01211420 }, /* HP2 */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE4] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x16, 0x99130111 }, /* speaker */
-			{ 0x18, 0x01a19840 }, /* mic */
-			{ 0x19, 0x99a3094f }, /* int-mic */
-			{ 0x21, 0x0121441f }, /* HP */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE5] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x15, 0x0121441f }, /* HP */
-			{ 0x16, 0x99130111 }, /* speaker */
-			{ 0x18, 0x01a19840 }, /* mic */
-			{ 0x19, 0x99a3094f }, /* int-mic */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE6] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x15, 0x01211420 }, /* HP2 */
-			{ 0x18, 0x01a19840 }, /* mic */
-			{ 0x19, 0x99a3094f }, /* int-mic */
-			{ 0x1b, 0x0121441f }, /* HP */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE7] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x17, 0x99130111 }, /* speaker */
-			{ 0x18, 0x01a19840 }, /* mic */
-			{ 0x19, 0x99a3094f }, /* int-mic */
-			{ 0x1b, 0x01214020 }, /* HP */
-			{ 0x21, 0x0121401f }, /* HP */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_ASUS_MODE8] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x14, 0x99130110 }, /* speaker */
-			{ 0x12, 0x99a30970 }, /* int-mic */
-			{ 0x15, 0x01214020 }, /* HP */
-			{ 0x17, 0x99130111 }, /* speaker */
-			{ 0x18, 0x01a19840 }, /* mic */
-			{ 0x21, 0x0121401f }, /* HP */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_SKU_IGNORE
-	},
-	[ALC662_FIXUP_NO_JACK_DETECT] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_no_jack_detect,
-	},
-	[ALC662_FIXUP_ZOTAC_Z68] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1b, 0x02214020 }, /* Front HP */
-			{ }
-		}
-	},
-	[ALC662_FIXUP_INV_DMIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_inv_dmic,
-	},
-	[ALC668_FIXUP_DELL_XPS13] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_dell_xps13,
-		.chained = true,
-		.chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
-	},
-	[ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_disable_aamix,
-		.chained = true,
-		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
-	},
-	[ALC668_FIXUP_AUTO_MUTE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_auto_mute_via_amp,
-		.chained = true,
-		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
-	},
-	[ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-			/* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_HEADSET_MODE
-	},
-	[ALC662_FIXUP_HEADSET_MODE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_headset_mode_alc662,
-	},
-	[ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC668_FIXUP_HEADSET_MODE
-	},
-	[ALC668_FIXUP_HEADSET_MODE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_headset_mode_alc668,
-	},
-	[ALC662_FIXUP_BASS_MODE4_CHMAP] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_bass_chmap,
-		.chained = true,
-		.chain_id = ALC662_FIXUP_ASUS_MODE4
-	},
-	[ALC662_FIXUP_BASS_16] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{0x16, 0x80106111}, /* bass speaker */
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_BASS_CHMAP,
-	},
-	[ALC662_FIXUP_BASS_1A] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{0x1a, 0x80106111}, /* bass speaker */
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_BASS_CHMAP,
-	},
-	[ALC662_FIXUP_BASS_CHMAP] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_bass_chmap,
-	},
-	[ALC662_FIXUP_ASUS_Nx50] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_auto_mute_via_amp,
-		.chained = true,
-		.chain_id = ALC662_FIXUP_BASS_1A
-	},
-	[ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_headset_mode_alc668,
-		.chain_id = ALC662_FIXUP_BASS_CHMAP
-	},
-	[ALC668_FIXUP_ASUS_Nx51] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-			{ 0x1a, 0x90170151 }, /* bass speaker */
-			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
-	},
-	[ALC668_FIXUP_MIC_COEF] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
-			{}
-		},
-	},
-	[ALC668_FIXUP_ASUS_G751] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x16, 0x0421101f }, /* HP */
-			{}
-		},
-		.chained = true,
-		.chain_id = ALC668_FIXUP_MIC_COEF
-	},
-	[ALC891_FIXUP_HEADSET_MODE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc_fixup_headset_mode,
-	},
-	[ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC891_FIXUP_HEADSET_MODE
-	},
-	[ALC662_FIXUP_ACER_VERITON] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x50170120 }, /* no internal speaker */
-			{ }
-		}
-	},
-	[ALC892_FIXUP_ASROCK_MOBO] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x40f000f0 }, /* disabled */
-			{ 0x16, 0x40f000f0 }, /* disabled */
-			{ }
-		}
-	},
-	[ALC662_FIXUP_USI_FUNC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc662_fixup_usi_headset_mic,
-	},
-	[ALC662_FIXUP_USI_HEADSET_MODE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
-			{ 0x18, 0x01a1903d },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_USI_FUNC
-	},
-	[ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc233_alc662_fixup_lenovo_dual_codecs,
-	},
-	[ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc662_fixup_aspire_ethos_hp,
-	},
-	[ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x15, 0x92130110 }, /* front speakers */
-			{ 0x18, 0x99130111 }, /* center/subwoofer */
-			{ 0x1b, 0x11130012 }, /* surround plus jack for HP */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
-	},
-	[ALC671_FIXUP_HP_HEADSET_MIC2] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc671_fixup_hp_headset_mic2,
-	},
-	[ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_USI_FUNC
-	},
-	[ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
-			{ 0x1b, 0x0221144f },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC662_FIXUP_USI_FUNC
-	},
-	[ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1b, 0x04a1112c },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC668_FIXUP_HEADSET_MIC
-	},
-	[ALC668_FIXUP_HEADSET_MIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc269_fixup_headset_mic,
-		.chained = true,
-		.chain_id = ALC668_FIXUP_MIC_DET_COEF
-	},
-	[ALC668_FIXUP_MIC_DET_COEF] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
-			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
-			{}
-		},
-	},
-	[ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc897_fixup_lenovo_headset_mic,
-	},
-	[ALC897_FIXUP_HEADSET_MIC_PIN] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1a, 0x03a11050 },
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
-	},
-	[ALC897_FIXUP_HP_HSMIC_VERB] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-			{ }
-		},
-	},
-	[ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = alc897_fixup_lenovo_headset_mode,
-	},
-	[ALC897_FIXUP_HEADSET_MIC_PIN2] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
-			{ }
-		},
-		.chained = true,
-		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
-	},
-	[ALC897_FIXUP_UNIS_H3C_X500S] = {
-		.type = HDA_FIXUP_VERBS,
-		.v.verbs = (const struct hda_verb[]) {
-			{ 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
-			{}
-		},
-	},
-	[ALC897_FIXUP_HEADSET_MIC_PIN3] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = (const struct hda_pintbl[]) {
-			{ 0x19, 0x03a11050 }, /* use as headset mic */
-			{ }
-		},
-	},
-};
-
-static const struct hda_quirk alc662_fixup_tbl[] = {
-	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
-	SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
-	SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
-	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
-	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
-	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
-	SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
-	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
-	SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
-	SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
-	SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
-	SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
-	SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
-	SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
-	SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
-	SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
-	SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
-	SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
-	SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
-	SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
-	SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
-	SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
-	SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
-	SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
-	SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
-	SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
-	SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
-	SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
-	SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
-	SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
-	SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
-	SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
-	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
-	SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
-	SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
-	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
-	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
-	SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
-	SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
-	SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
-	SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
-	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
-	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
-	SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
-	SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
-	SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
-	SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
-	SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
-	SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
-
-#if 0
-	/* Below is a quirk table taken from the old code.
-	 * Basically the device should work as is without the fixup table.
-	 * If BIOS doesn't give a proper info, enable the corresponding
-	 * fixup entry.
-	 */
-	SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
-	SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
-	SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
-	SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
-	SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
-	SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
-	SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
-	SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
-	SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
-	SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-	SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
-#endif
-	{}
-};
-
-static const struct hda_model_fixup alc662_fixup_models[] = {
-	{.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
-	{.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
-	{.id = ALC272_FIXUP_MARIO, .name = "mario"},
-	{.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
-	{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
-	{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
-	{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
-	{.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
-	{.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
-	{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
-	{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
-	{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
-	{.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
-	{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
-	{.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
-	{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
-	{.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
-	{.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
-	{.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
-	{.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
-	{.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
-	{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
-	{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
-	{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
-	{.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
-	{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
-	{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
-	{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
-	{.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
-	{.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
-	{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
-	{.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
-	{.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
-	{}
-};
-
-static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
-	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
-		{0x17, 0x02211010},
-		{0x18, 0x01a19030},
-		{0x1a, 0x01813040},
-		{0x21, 0x01014020}),
-	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
-		{0x16, 0x01813030},
-		{0x17, 0x02211010},
-		{0x18, 0x01a19040},
-		{0x21, 0x01014020}),
-	SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
-		{0x14, 0x01014010},
-		{0x18, 0x01a19020},
-		{0x1a, 0x0181302f},
-		{0x1b, 0x0221401f}),
-	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-		{0x12, 0x99a30130},
-		{0x14, 0x90170110},
-		{0x15, 0x0321101f},
-		{0x16, 0x03011020}),
-	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-		{0x12, 0x99a30140},
-		{0x14, 0x90170110},
-		{0x15, 0x0321101f},
-		{0x16, 0x03011020}),
-	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-		{0x12, 0x99a30150},
-		{0x14, 0x90170110},
-		{0x15, 0x0321101f},
-		{0x16, 0x03011020}),
-	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-		{0x14, 0x90170110},
-		{0x15, 0x0321101f},
-		{0x16, 0x03011020}),
-	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
-		{0x12, 0x90a60130},
-		{0x14, 0x90170110},
-		{0x15, 0x0321101f}),
-	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
-		{0x14, 0x01014010},
-		{0x17, 0x90170150},
-		{0x19, 0x02a11060},
-		{0x1b, 0x01813030},
-		{0x21, 0x02211020}),
-	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
-		{0x14, 0x01014010},
-		{0x18, 0x01a19040},
-		{0x1b, 0x01813030},
-		{0x21, 0x02211020}),
-	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
-		{0x14, 0x01014020},
-		{0x17, 0x90170110},
-		{0x18, 0x01a19050},
-		{0x1b, 0x01813040},
-		{0x21, 0x02211030}),
-	{}
-};
-
-/*
- */
-static int patch_alc662(struct hda_codec *codec)
-{
-	struct alc_spec *spec;
-	int err;
-
-	err = alc_alloc_spec(codec, 0x0b);
-	if (err < 0)
-		return err;
-
-	spec = codec->spec;
-
-	spec->shutup = alc_eapd_shutup;
-
-	/* handle multiple HPs as is */
-	spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
-
-	alc_fix_pll_init(codec, 0x20, 0x04, 15);
-
-	switch (codec->core.vendor_id) {
-	case 0x10ec0668:
-		spec->init_hook = alc668_restore_default_value;
-		break;
-	}
-
-	alc_pre_init(codec);
-
-	snd_hda_pick_fixup(codec, alc662_fixup_models,
-		       alc662_fixup_tbl, alc662_fixups);
-	snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	alc_auto_parse_customize_define(codec);
-
-	if (has_cdefine_beep(codec))
-		spec->gen.beep_nid = 0x01;
-
-	if ((alc_get_coef0(codec) & (1 << 14)) &&
-	    codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
-	    spec->cdefine.platform_type == 1) {
-		err = alc_codec_rename(codec, "ALC272X");
-		if (err < 0)
-			goto error;
-	}
-
-	/* automatic parse from the BIOS config */
-	err = alc662_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	if (!spec->gen.no_analog && spec->gen.beep_nid) {
-		switch (codec->core.vendor_id) {
-		case 0x10ec0662:
-			err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-			break;
-		case 0x10ec0272:
-		case 0x10ec0663:
-		case 0x10ec0665:
-		case 0x10ec0668:
-			err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-			break;
-		case 0x10ec0273:
-			err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
-			break;
-		}
-		if (err < 0)
-			goto error;
-	}
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	alc_free(codec);
-	return err;
-}
-
-/*
- * ALC680 support
- */
-
-static int alc680_parse_auto_config(struct hda_codec *codec)
-{
-	return alc_parse_auto_config(codec, NULL, NULL);
-}
-
-/*
- */
-static int patch_alc680(struct hda_codec *codec)
-{
-	int err;
-
-	/* ALC680 has no aa-loopback mixer */
-	err = alc_alloc_spec(codec, 0);
-	if (err < 0)
-		return err;
-
-	/* automatic parse from the BIOS config */
-	err = alc680_parse_auto_config(codec);
-	if (err < 0) {
-		alc_free(codec);
-		return err;
-	}
-
-	return 0;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_realtek[] = {
+static const struct hda_device_id snd_hda_id_alc269[] = {
 	HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
@@ -13714,13 +8089,8 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
 	HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
-	HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
-	HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
-	HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
 	HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
 	HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
@@ -13742,53 +8112,22 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
 	HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269),
-	HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
-	HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
-	HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
-	HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
-	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
-	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
 	HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
 	HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
-	HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
 	HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269),
 	{} /* terminator */
 };
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc269);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Realtek HD-audio codec");
+MODULE_DESCRIPTION("Realtek ALC269 and compatible HD-audio codecs");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
 
-static struct hda_codec_driver realtek_driver = {
-	.id = snd_hda_id_realtek,
+static struct hda_codec_driver alc269_driver = {
+	.id = snd_hda_id_alc269,
 };
 
-module_hda_codec_driver(realtek_driver);
+module_hda_codec_driver(alc269_driver);
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
new file mode 100644
index 000000000000..94e4a313e5e2
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -0,0 +1,1102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC662 and compatible codecs
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/*
+ * ALC662 support
+ *
+ * ALC662 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+
+/*
+ * BIOS auto configuration
+ */
+
+static int alc662_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
+	static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+	const hda_nid_t *ssids;
+
+	if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
+	    codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
+	    codec->core.vendor_id == 0x10ec0671)
+		ssids = alc663_ssids;
+	else
+		ssids = alc662_ssids;
+	return alc_parse_auto_config(codec, alc662_ignore, ssids);
+}
+
+static void alc272_fixup_mario(struct hda_codec *codec,
+			       const struct hda_fixup *fix, int action)
+{
+	if (action != HDA_FIXUP_ACT_PRE_PROBE)
+		return;
+	if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
+				      (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
+				      (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
+				      (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+				      (0 << AC_AMPCAP_MUTE_SHIFT)))
+		codec_warn(codec, "failed to override amp caps for NID 0x2\n");
+}
+
+/* avoid D3 for keeping GPIO up */
+static unsigned int gpio_led_power_filter(struct hda_codec *codec,
+					  hda_nid_t nid,
+					  unsigned int power_state)
+{
+	struct alc_spec *spec = codec->spec;
+	if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
+		return AC_PWRST_D0;
+	return power_state;
+}
+
+static void alc662_fixup_led_gpio1(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->mute_led_polarity = 1;
+		codec->power_filter = gpio_led_power_filter;
+	}
+}
+
+static void alc662_usi_automute_hook(struct hda_codec *codec,
+					 struct hda_jack_callback *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	int vref;
+	msleep(200);
+	snd_hda_gen_hp_automute(codec, jack);
+
+	vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+	msleep(100);
+	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    vref);
+}
+
+static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+		spec->gen.hp_automute_hook = alc662_usi_automute_hook;
+	}
+}
+
+static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
+					struct hda_jack_callback *cb)
+{
+	/* surround speakers at 0x1b already get muted automatically when
+	 * headphones are plugged in, but we have to mute/unmute the remaining
+	 * channels manually:
+	 * 0x15 - front left/front right
+	 * 0x18 - front center/ LFE
+	 */
+	if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
+		snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
+		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+	} else {
+		snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
+		snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
+	}
+}
+
+static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
+					const struct hda_fixup *fix, int action)
+{
+    /* Pin 0x1b: shared headphones jack and surround speakers */
+	if (!is_jack_detectable(codec, 0x1b))
+		return;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		snd_hda_jack_detect_enable_callback(codec, 0x1b,
+				alc662_aspire_ethos_mute_speakers);
+		/* subwoofer needs an extra GPIO setting to become audible */
+		alc_setup_gpio(codec, 0x02);
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		/* Make sure to start in a correct state, i.e. if
+		 * headphones have been plugged in before powering up the system
+		 */
+		alc662_aspire_ethos_mute_speakers(codec, NULL);
+		break;
+	}
+}
+
+static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
+					     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	static const struct hda_pintbl pincfgs[] = {
+		{ 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
+		{ 0x1b, 0x0181304f },
+		{ }
+	};
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		spec->gen.mixer_nid = 0;
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+		snd_hda_apply_pincfgs(codec, pincfgs);
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		alc_write_coef_idx(codec, 0x19, 0xa054);
+		break;
+	}
+}
+
+static void alc897_hp_automute_hook(struct hda_codec *codec,
+					 struct hda_jack_callback *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	int vref;
+
+	snd_hda_gen_hp_automute(codec, jack);
+	vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
+	snd_hda_set_pin_ctl(codec, 0x1b, vref);
+}
+
+static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+		spec->no_shutup_pins = 1;
+	}
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
+	}
+}
+
+static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+	}
+}
+
+static const struct coef_fw alc668_coefs[] = {
+	WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
+	WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
+	WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b,    0x0),
+	WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
+	WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
+	WRITE_COEF(0x13,    0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
+	WRITE_COEF(0x19,    0x0), WRITE_COEF(0x1a,    0x0), WRITE_COEF(0x1b,    0x0),
+	WRITE_COEF(0x1c,    0x0), WRITE_COEF(0x1d,    0x0), WRITE_COEF(0x1e, 0x7418),
+	WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
+	WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
+	WRITE_COEF(0x27,    0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
+	WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
+	WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac,    0x0),
+	WRITE_COEF(0xad,    0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
+	WRITE_COEF(0xb0,    0x0), WRITE_COEF(0xb1,    0x0), WRITE_COEF(0xb2,    0x0),
+	WRITE_COEF(0xb3,    0x0), WRITE_COEF(0xb4,    0x0), WRITE_COEF(0xb5, 0x1040),
+	WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
+	WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
+	WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
+	WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
+	{}
+};
+
+static void alc668_restore_default_value(struct hda_codec *codec)
+{
+	alc_process_coef_fw(codec, alc668_coefs);
+}
+
+static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+		spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
+
+		/* Disable boost for mic-in permanently. (This code is only called
+		   from quirks that guarantee that the headphone is at NID 0x1b.) */
+		snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
+		snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
+	} else
+		alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		alc_write_coef_idx(codec, 0xc4, 0x8000);
+		alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
+		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+	}
+	alc_fixup_headset_mode(codec, fix, action);
+}
+
+enum {
+	ALC662_FIXUP_ASPIRE,
+	ALC662_FIXUP_LED_GPIO1,
+	ALC662_FIXUP_IDEAPAD,
+	ALC272_FIXUP_MARIO,
+	ALC662_FIXUP_CZC_ET26,
+	ALC662_FIXUP_CZC_P10T,
+	ALC662_FIXUP_SKU_IGNORE,
+	ALC662_FIXUP_HP_RP5800,
+	ALC662_FIXUP_ASUS_MODE1,
+	ALC662_FIXUP_ASUS_MODE2,
+	ALC662_FIXUP_ASUS_MODE3,
+	ALC662_FIXUP_ASUS_MODE4,
+	ALC662_FIXUP_ASUS_MODE5,
+	ALC662_FIXUP_ASUS_MODE6,
+	ALC662_FIXUP_ASUS_MODE7,
+	ALC662_FIXUP_ASUS_MODE8,
+	ALC662_FIXUP_NO_JACK_DETECT,
+	ALC662_FIXUP_ZOTAC_Z68,
+	ALC662_FIXUP_INV_DMIC,
+	ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+	ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+	ALC662_FIXUP_HEADSET_MODE,
+	ALC668_FIXUP_HEADSET_MODE,
+	ALC662_FIXUP_BASS_MODE4_CHMAP,
+	ALC662_FIXUP_BASS_16,
+	ALC662_FIXUP_BASS_1A,
+	ALC662_FIXUP_BASS_CHMAP,
+	ALC668_FIXUP_AUTO_MUTE,
+	ALC668_FIXUP_DELL_DISABLE_AAMIX,
+	ALC668_FIXUP_DELL_XPS13,
+	ALC662_FIXUP_ASUS_Nx50,
+	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
+	ALC668_FIXUP_ASUS_Nx51,
+	ALC668_FIXUP_MIC_COEF,
+	ALC668_FIXUP_ASUS_G751,
+	ALC891_FIXUP_HEADSET_MODE,
+	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+	ALC662_FIXUP_ACER_VERITON,
+	ALC892_FIXUP_ASROCK_MOBO,
+	ALC662_FIXUP_USI_FUNC,
+	ALC662_FIXUP_USI_HEADSET_MODE,
+	ALC662_FIXUP_LENOVO_MULTI_CODECS,
+	ALC669_FIXUP_ACER_ASPIRE_ETHOS,
+	ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
+	ALC671_FIXUP_HP_HEADSET_MIC2,
+	ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
+	ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
+	ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
+	ALC668_FIXUP_HEADSET_MIC,
+	ALC668_FIXUP_MIC_DET_COEF,
+	ALC897_FIXUP_LENOVO_HEADSET_MIC,
+	ALC897_FIXUP_HEADSET_MIC_PIN,
+	ALC897_FIXUP_HP_HSMIC_VERB,
+	ALC897_FIXUP_LENOVO_HEADSET_MODE,
+	ALC897_FIXUP_HEADSET_MIC_PIN2,
+	ALC897_FIXUP_UNIS_H3C_X500S,
+	ALC897_FIXUP_HEADSET_MIC_PIN3,
+};
+
+static const struct hda_fixup alc662_fixups[] = {
+	[ALC662_FIXUP_ASPIRE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x99130112 }, /* subwoofer */
+			{ }
+		}
+	},
+	[ALC662_FIXUP_LED_GPIO1] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc662_fixup_led_gpio1,
+	},
+	[ALC662_FIXUP_IDEAPAD] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x17, 0x99130112 }, /* subwoofer */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_LED_GPIO1,
+	},
+	[ALC272_FIXUP_MARIO] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc272_fixup_mario,
+	},
+	[ALC662_FIXUP_CZC_ET26] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{0x12, 0x403cc000},
+			{0x14, 0x90170110}, /* speaker */
+			{0x15, 0x411111f0},
+			{0x16, 0x411111f0},
+			{0x18, 0x01a19030}, /* mic */
+			{0x19, 0x90a7013f}, /* int-mic */
+			{0x1a, 0x01014020},
+			{0x1b, 0x0121401f},
+			{0x1c, 0x411111f0},
+			{0x1d, 0x411111f0},
+			{0x1e, 0x40478e35},
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_CZC_P10T] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+			{}
+		}
+	},
+	[ALC662_FIXUP_SKU_IGNORE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_sku_ignore,
+	},
+	[ALC662_FIXUP_HP_RP5800] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x0221201f }, /* HP out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE1] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x18, 0x01a19c20 }, /* mic */
+			{ 0x19, 0x99a3092f }, /* int-mic */
+			{ 0x21, 0x0121401f }, /* HP out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE2] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x18, 0x01a19820 }, /* mic */
+			{ 0x19, 0x99a3092f }, /* int-mic */
+			{ 0x1b, 0x0121401f }, /* HP out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE3] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x15, 0x0121441f }, /* HP */
+			{ 0x18, 0x01a19840 }, /* mic */
+			{ 0x19, 0x99a3094f }, /* int-mic */
+			{ 0x21, 0x01211420 }, /* HP2 */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE4] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x16, 0x99130111 }, /* speaker */
+			{ 0x18, 0x01a19840 }, /* mic */
+			{ 0x19, 0x99a3094f }, /* int-mic */
+			{ 0x21, 0x0121441f }, /* HP */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE5] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x15, 0x0121441f }, /* HP */
+			{ 0x16, 0x99130111 }, /* speaker */
+			{ 0x18, 0x01a19840 }, /* mic */
+			{ 0x19, 0x99a3094f }, /* int-mic */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE6] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x15, 0x01211420 }, /* HP2 */
+			{ 0x18, 0x01a19840 }, /* mic */
+			{ 0x19, 0x99a3094f }, /* int-mic */
+			{ 0x1b, 0x0121441f }, /* HP */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE7] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x17, 0x99130111 }, /* speaker */
+			{ 0x18, 0x01a19840 }, /* mic */
+			{ 0x19, 0x99a3094f }, /* int-mic */
+			{ 0x1b, 0x01214020 }, /* HP */
+			{ 0x21, 0x0121401f }, /* HP */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_ASUS_MODE8] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x12, 0x99a30970 }, /* int-mic */
+			{ 0x15, 0x01214020 }, /* HP */
+			{ 0x17, 0x99130111 }, /* speaker */
+			{ 0x18, 0x01a19840 }, /* mic */
+			{ 0x21, 0x0121401f }, /* HP */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_SKU_IGNORE
+	},
+	[ALC662_FIXUP_NO_JACK_DETECT] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_no_jack_detect,
+	},
+	[ALC662_FIXUP_ZOTAC_Z68] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x02214020 }, /* Front HP */
+			{ }
+		}
+	},
+	[ALC662_FIXUP_INV_DMIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic,
+	},
+	[ALC668_FIXUP_DELL_XPS13] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_dell_xps13,
+		.chained = true,
+		.chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
+	},
+	[ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_disable_aamix,
+		.chained = true,
+		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+	},
+	[ALC668_FIXUP_AUTO_MUTE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_auto_mute_via_amp,
+		.chained = true,
+		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+	},
+	[ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+			/* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_HEADSET_MODE
+	},
+	[ALC662_FIXUP_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_alc662,
+	},
+	[ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC668_FIXUP_HEADSET_MODE
+	},
+	[ALC668_FIXUP_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_alc668,
+	},
+	[ALC662_FIXUP_BASS_MODE4_CHMAP] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_bass_chmap,
+		.chained = true,
+		.chain_id = ALC662_FIXUP_ASUS_MODE4
+	},
+	[ALC662_FIXUP_BASS_16] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{0x16, 0x80106111}, /* bass speaker */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_BASS_CHMAP,
+	},
+	[ALC662_FIXUP_BASS_1A] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{0x1a, 0x80106111}, /* bass speaker */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_BASS_CHMAP,
+	},
+	[ALC662_FIXUP_BASS_CHMAP] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_bass_chmap,
+	},
+	[ALC662_FIXUP_ASUS_Nx50] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_auto_mute_via_amp,
+		.chained = true,
+		.chain_id = ALC662_FIXUP_BASS_1A
+	},
+	[ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_alc668,
+		.chain_id = ALC662_FIXUP_BASS_CHMAP
+	},
+	[ALC668_FIXUP_ASUS_Nx51] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+			{ 0x1a, 0x90170151 }, /* bass speaker */
+			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
+	},
+	[ALC668_FIXUP_MIC_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
+			{}
+		},
+	},
+	[ALC668_FIXUP_ASUS_G751] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x0421101f }, /* HP */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC668_FIXUP_MIC_COEF
+	},
+	[ALC891_FIXUP_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode,
+	},
+	[ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC891_FIXUP_HEADSET_MODE
+	},
+	[ALC662_FIXUP_ACER_VERITON] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x50170120 }, /* no internal speaker */
+			{ }
+		}
+	},
+	[ALC892_FIXUP_ASROCK_MOBO] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x40f000f0 }, /* disabled */
+			{ 0x16, 0x40f000f0 }, /* disabled */
+			{ }
+		}
+	},
+	[ALC662_FIXUP_USI_FUNC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc662_fixup_usi_headset_mic,
+	},
+	[ALC662_FIXUP_USI_HEADSET_MODE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
+			{ 0x18, 0x01a1903d },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_USI_FUNC
+	},
+	[ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+	},
+	[ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc662_fixup_aspire_ethos_hp,
+	},
+	[ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x92130110 }, /* front speakers */
+			{ 0x18, 0x99130111 }, /* center/subwoofer */
+			{ 0x1b, 0x11130012 }, /* surround plus jack for HP */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
+	},
+	[ALC671_FIXUP_HP_HEADSET_MIC2] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc671_fixup_hp_headset_mic2,
+	},
+	[ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_USI_FUNC
+	},
+	[ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+			{ 0x1b, 0x0221144f },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC662_FIXUP_USI_FUNC
+	},
+	[ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x04a1112c },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC668_FIXUP_HEADSET_MIC
+	},
+	[ALC668_FIXUP_HEADSET_MIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mic,
+		.chained = true,
+		.chain_id = ALC668_FIXUP_MIC_DET_COEF
+	},
+	[ALC668_FIXUP_MIC_DET_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
+			{}
+		},
+	},
+	[ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc897_fixup_lenovo_headset_mic,
+	},
+	[ALC897_FIXUP_HEADSET_MIC_PIN] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x03a11050 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
+	},
+	[ALC897_FIXUP_HP_HSMIC_VERB] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+	},
+	[ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc897_fixup_lenovo_headset_mode,
+	},
+	[ALC897_FIXUP_HEADSET_MIC_PIN2] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
+	},
+	[ALC897_FIXUP_UNIS_H3C_X500S] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
+			{}
+		},
+	},
+	[ALC897_FIXUP_HEADSET_MIC_PIN3] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x03a11050 }, /* use as headset mic */
+			{ }
+		},
+	},
+};
+
+static const struct hda_quirk alc662_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
+	SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
+	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
+	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+	SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
+	SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
+	SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
+	SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
+	SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
+	SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
+	SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+	SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+	SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+	SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+	SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+	SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
+	SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
+	SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
+	SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
+	SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
+	SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
+	SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
+	SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
+	SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+	SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
+	SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
+	SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
+	SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
+	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
+	SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
+	SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
+	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
+	SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
+	SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
+	SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
+	SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
+	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+	SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
+	SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
+	SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
+	SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
+	SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
+	SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
+
+#if 0
+	/* Below is a quirk table taken from the old code.
+	 * Basically the device should work as is without the fixup table.
+	 * If BIOS doesn't give a proper info, enable the corresponding
+	 * fixup entry.
+	 */
+	SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
+	SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
+	SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
+	SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+	SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+	SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
+	SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+	SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
+	SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+	SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
+#endif
+	{}
+};
+
+static const struct hda_model_fixup alc662_fixup_models[] = {
+	{.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
+	{.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
+	{.id = ALC272_FIXUP_MARIO, .name = "mario"},
+	{.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
+	{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
+	{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
+	{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
+	{.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
+	{.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
+	{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
+	{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
+	{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
+	{.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
+	{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
+	{.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
+	{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+	{.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
+	{.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
+	{.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
+	{.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
+	{.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
+	{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
+	{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
+	{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+	{.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
+	{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
+	{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
+	{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
+	{.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
+	{.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
+	{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
+	{.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
+	{.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
+	{}
+};
+
+static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
+	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+		{0x17, 0x02211010},
+		{0x18, 0x01a19030},
+		{0x1a, 0x01813040},
+		{0x21, 0x01014020}),
+	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+		{0x16, 0x01813030},
+		{0x17, 0x02211010},
+		{0x18, 0x01a19040},
+		{0x21, 0x01014020}),
+	SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+		{0x14, 0x01014010},
+		{0x18, 0x01a19020},
+		{0x1a, 0x0181302f},
+		{0x1b, 0x0221401f}),
+	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+		{0x12, 0x99a30130},
+		{0x14, 0x90170110},
+		{0x15, 0x0321101f},
+		{0x16, 0x03011020}),
+	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+		{0x12, 0x99a30140},
+		{0x14, 0x90170110},
+		{0x15, 0x0321101f},
+		{0x16, 0x03011020}),
+	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+		{0x12, 0x99a30150},
+		{0x14, 0x90170110},
+		{0x15, 0x0321101f},
+		{0x16, 0x03011020}),
+	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+		{0x14, 0x90170110},
+		{0x15, 0x0321101f},
+		{0x16, 0x03011020}),
+	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
+		{0x12, 0x90a60130},
+		{0x14, 0x90170110},
+		{0x15, 0x0321101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+		{0x14, 0x01014010},
+		{0x17, 0x90170150},
+		{0x19, 0x02a11060},
+		{0x1b, 0x01813030},
+		{0x21, 0x02211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+		{0x14, 0x01014010},
+		{0x18, 0x01a19040},
+		{0x1b, 0x01813030},
+		{0x21, 0x02211020}),
+	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+		{0x14, 0x01014020},
+		{0x17, 0x90170110},
+		{0x18, 0x01a19050},
+		{0x1b, 0x01813040},
+		{0x21, 0x02211030}),
+	{}
+};
+
+/*
+ */
+static int patch_alc662(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+
+	spec->shutup = alc_eapd_shutup;
+
+	/* handle multiple HPs as is */
+	spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+
+	alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0668:
+		spec->init_hook = alc668_restore_default_value;
+		break;
+	}
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, alc662_fixup_models,
+		       alc662_fixup_tbl, alc662_fixups);
+	snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	alc_auto_parse_customize_define(codec);
+
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
+	if ((alc_get_coef0(codec) & (1 << 14)) &&
+	    codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
+	    spec->cdefine.platform_type == 1) {
+		err = alc_codec_rename(codec, "ALC272X");
+		if (err < 0)
+			goto error;
+	}
+
+	/* automatic parse from the BIOS config */
+	err = alc662_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog && spec->gen.beep_nid) {
+		switch (codec->core.vendor_id) {
+		case 0x10ec0662:
+			err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+			break;
+		case 0x10ec0272:
+		case 0x10ec0663:
+		case 0x10ec0665:
+		case 0x10ec0668:
+			err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+			break;
+		case 0x10ec0273:
+			err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+			break;
+		}
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc662[] = {
+	HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
+	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
+	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
+	HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc662);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC662 and compatible HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc662_driver = {
+	.id = snd_hda_id_alc662,
+};
+
+module_hda_codec_driver(alc662_driver);
diff --git a/sound/hda/codecs/realtek/alc680.c b/sound/hda/codecs/realtek/alc680.c
new file mode 100644
index 000000000000..baf19ee3bc2f
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc680.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC680 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc680_parse_auto_config(struct hda_codec *codec)
+{
+	return alc_parse_auto_config(codec, NULL, NULL);
+}
+
+/*
+ */
+static int patch_alc680(struct hda_codec *codec)
+{
+	int err;
+
+	/* ALC680 has no aa-loopback mixer */
+	err = alc_alloc_spec(codec, 0);
+	if (err < 0)
+		return err;
+
+	/* automatic parse from the BIOS config */
+	err = alc680_parse_auto_config(codec);
+	if (err < 0) {
+		alc_free(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc680[] = {
+	HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc680);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC680 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc680_driver = {
+	.id = snd_hda_id_alc680,
+};
+
+module_hda_codec_driver(alc680_driver);
diff --git a/sound/hda/codecs/realtek/alc861.c b/sound/hda/codecs/realtek/alc861.c
new file mode 100644
index 000000000000..0eb70b44dc05
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc861.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC861 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc861_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
+	return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
+}
+
+/* Pin config fixes */
+enum {
+	ALC861_FIXUP_FSC_AMILO_PI1505,
+	ALC861_FIXUP_AMP_VREF_0F,
+	ALC861_FIXUP_NO_JACK_DETECT,
+	ALC861_FIXUP_ASUS_A6RP,
+	ALC660_FIXUP_ASUS_W7J,
+};
+
+/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
+static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
+			const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int val;
+
+	if (action != HDA_FIXUP_ACT_INIT)
+		return;
+	val = snd_hda_codec_get_pin_target(codec, 0x0f);
+	if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
+		val |= AC_PINCTL_IN_EN;
+	val |= AC_PINCTL_VREF_50;
+	snd_hda_set_pin_ctl(codec, 0x0f, val);
+	spec->gen.keep_vref_in_automute = 1;
+}
+
+static const struct hda_fixup alc861_fixups[] = {
+	[ALC861_FIXUP_FSC_AMILO_PI1505] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x0b, 0x0221101f }, /* HP */
+			{ 0x0f, 0x90170310 }, /* speaker */
+			{ }
+		}
+	},
+	[ALC861_FIXUP_AMP_VREF_0F] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc861_fixup_asus_amp_vref_0f,
+	},
+	[ALC861_FIXUP_NO_JACK_DETECT] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_no_jack_detect,
+	},
+	[ALC861_FIXUP_ASUS_A6RP] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc861_fixup_asus_amp_vref_0f,
+		.chained = true,
+		.chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+	},
+	[ALC660_FIXUP_ASUS_W7J] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* ASUS W7J needs a magic pin setup on unused NID 0x10
+			 * for enabling outputs
+			 */
+			{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+			{ }
+		},
+	}
+};
+
+static const struct hda_quirk alc861_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
+	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
+	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
+	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
+	SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
+	SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
+	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
+	{}
+};
+
+/*
+ */
+static int patch_alc861(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x15);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x23;
+
+	spec->power_hook = alc_power_eapd;
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	/* automatic parse from the BIOS config */
+	err = alc861_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog) {
+		err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc861[] = {
+	HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
+	HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC861 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc861_driver = {
+	.id = snd_hda_id_alc861,
+};
+
+module_hda_codec_driver(alc861_driver);
diff --git a/sound/hda/codecs/realtek/alc861vd.c b/sound/hda/codecs/realtek/alc861vd.c
new file mode 100644
index 000000000000..ebf274ad730b
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc861vd.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC861-VD codec
+// Based on ALC882
+// In addition, an independent DAC
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+	return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
+}
+
+enum {
+	ALC660VD_FIX_ASUS_GPIO1,
+	ALC861VD_FIX_DALLAS,
+};
+
+/* exclude VREF80 */
+static void alc861vd_fixup_dallas(struct hda_codec *codec,
+				  const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
+		snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
+	}
+}
+
+/* reset GPIO1 */
+static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
+				      const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		spec->gpio_mask |= 0x02;
+	alc_fixup_gpio(codec, action, 0x01);
+}
+
+static const struct hda_fixup alc861vd_fixups[] = {
+	[ALC660VD_FIX_ASUS_GPIO1] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc660vd_fixup_asus_gpio1,
+	},
+	[ALC861VD_FIX_DALLAS] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc861vd_fixup_dallas,
+	},
+};
+
+static const struct hda_quirk alc861vd_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
+	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
+	{}
+};
+
+/*
+ */
+static int patch_alc861vd(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x23;
+
+	spec->shutup = alc_eapd_shutup;
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	/* automatic parse from the BIOS config */
+	err = alc861vd_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog) {
+		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc861vd[] = {
+	HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
+	HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861vd);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC861-VD HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc861vd_driver = {
+	.id = snd_hda_id_alc861vd,
+};
+
+module_hda_codec_driver(alc861vd_driver);
diff --git a/sound/hda/codecs/realtek/alc880.c b/sound/hda/codecs/realtek/alc880.c
new file mode 100644
index 000000000000..2e828ab96dc5
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc880.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC880 codec
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	/* For some reason, the res given from ALC880 is broken.
+	   Here we adjust it properly. */
+	snd_hda_jack_unsol_event(codec, res >> 2);
+}
+
+static int alc880_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+	return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
+}
+
+/*
+ * ALC880 fix-ups
+ */
+enum {
+	ALC880_FIXUP_GPIO1,
+	ALC880_FIXUP_GPIO2,
+	ALC880_FIXUP_MEDION_RIM,
+	ALC880_FIXUP_LG,
+	ALC880_FIXUP_LG_LW25,
+	ALC880_FIXUP_W810,
+	ALC880_FIXUP_EAPD_COEF,
+	ALC880_FIXUP_TCL_S700,
+	ALC880_FIXUP_VOL_KNOB,
+	ALC880_FIXUP_FUJITSU,
+	ALC880_FIXUP_F1734,
+	ALC880_FIXUP_UNIWILL,
+	ALC880_FIXUP_UNIWILL_DIG,
+	ALC880_FIXUP_Z71V,
+	ALC880_FIXUP_ASUS_W5A,
+	ALC880_FIXUP_3ST_BASE,
+	ALC880_FIXUP_3ST,
+	ALC880_FIXUP_3ST_DIG,
+	ALC880_FIXUP_5ST_BASE,
+	ALC880_FIXUP_5ST,
+	ALC880_FIXUP_5ST_DIG,
+	ALC880_FIXUP_6ST_BASE,
+	ALC880_FIXUP_6ST,
+	ALC880_FIXUP_6ST_DIG,
+	ALC880_FIXUP_6ST_AUTOMUTE,
+};
+
+/* enable the volume-knob widget support on NID 0x21 */
+static void alc880_fixup_vol_knob(struct hda_codec *codec,
+				  const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PROBE)
+		snd_hda_jack_detect_enable_callback(codec, 0x21,
+						    alc_update_knob_master);
+}
+
+static const struct hda_fixup alc880_fixups[] = {
+	[ALC880_FIXUP_GPIO1] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio1,
+	},
+	[ALC880_FIXUP_GPIO2] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio2,
+	},
+	[ALC880_FIXUP_MEDION_RIM] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_GPIO2,
+	},
+	[ALC880_FIXUP_LG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* disable bogus unused pins */
+			{ 0x16, 0x411111f0 },
+			{ 0x18, 0x411111f0 },
+			{ 0x1a, 0x411111f0 },
+			{ }
+		}
+	},
+	[ALC880_FIXUP_LG_LW25] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x0181344f }, /* line-in */
+			{ 0x1b, 0x0321403f }, /* headphone */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_W810] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* disable bogus unused pins */
+			{ 0x17, 0x411111f0 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_GPIO2,
+	},
+	[ALC880_FIXUP_EAPD_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+			{}
+		},
+	},
+	[ALC880_FIXUP_TCL_S700] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_GPIO2,
+	},
+	[ALC880_FIXUP_VOL_KNOB] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc880_fixup_vol_knob,
+	},
+	[ALC880_FIXUP_FUJITSU] = {
+		/* override all pins as BIOS on old Amilo is broken */
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x0121401f }, /* HP */
+			{ 0x15, 0x99030120 }, /* speaker */
+			{ 0x16, 0x99030130 }, /* bass speaker */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x411111f0 }, /* N/A */
+			{ 0x19, 0x01a19950 }, /* mic-in */
+			{ 0x1a, 0x411111f0 }, /* N/A */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x01454140 }, /* SPDIF out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_VOL_KNOB,
+	},
+	[ALC880_FIXUP_F1734] = {
+		/* almost compatible with FUJITSU, but no bass and SPDIF */
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x0121401f }, /* HP */
+			{ 0x15, 0x99030120 }, /* speaker */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x411111f0 }, /* N/A */
+			{ 0x19, 0x01a19950 }, /* mic-in */
+			{ 0x1a, 0x411111f0 }, /* N/A */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_VOL_KNOB,
+	},
+	[ALC880_FIXUP_UNIWILL] = {
+		/* need to fix HP and speaker pins to be parsed correctly */
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x0121411f }, /* HP */
+			{ 0x15, 0x99030120 }, /* speaker */
+			{ 0x16, 0x99030130 }, /* bass speaker */
+			{ }
+		},
+	},
+	[ALC880_FIXUP_UNIWILL_DIG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* disable bogus unused pins */
+			{ 0x17, 0x411111f0 },
+			{ 0x19, 0x411111f0 },
+			{ 0x1b, 0x411111f0 },
+			{ 0x1f, 0x411111f0 },
+			{ }
+		}
+	},
+	[ALC880_FIXUP_Z71V] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* set up the whole pins as BIOS is utterly broken */
+			{ 0x14, 0x99030120 }, /* speaker */
+			{ 0x15, 0x0121411f }, /* HP */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x01a19950 }, /* mic-in */
+			{ 0x19, 0x411111f0 }, /* N/A */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_ASUS_W5A] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* set up the whole pins as BIOS is utterly broken */
+			{ 0x14, 0x0121411f }, /* HP */
+			{ 0x15, 0x411111f0 }, /* N/A */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x90a60160 }, /* mic */
+			{ 0x19, 0x411111f0 }, /* N/A */
+			{ 0x1a, 0x411111f0 }, /* N/A */
+			{ 0x1b, 0x411111f0 }, /* N/A */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0xb743111e }, /* SPDIF out */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_GPIO1,
+	},
+	[ALC880_FIXUP_3ST_BASE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x01014010 }, /* line-out */
+			{ 0x15, 0x411111f0 }, /* N/A */
+			{ 0x16, 0x411111f0 }, /* N/A */
+			{ 0x17, 0x411111f0 }, /* N/A */
+			{ 0x18, 0x01a19c30 }, /* mic-in */
+			{ 0x19, 0x0121411f }, /* HP */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x02a19c40 }, /* front-mic */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			/* 0x1e is filled in below */
+			{ 0x1f, 0x411111f0 }, /* N/A */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_3ST] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_3ST_BASE,
+	},
+	[ALC880_FIXUP_3ST_DIG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_3ST_BASE,
+	},
+	[ALC880_FIXUP_5ST_BASE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x01014010 }, /* front */
+			{ 0x15, 0x411111f0 }, /* N/A */
+			{ 0x16, 0x01011411 }, /* CLFE */
+			{ 0x17, 0x01016412 }, /* surr */
+			{ 0x18, 0x01a19c30 }, /* mic-in */
+			{ 0x19, 0x0121411f }, /* HP */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x02a19c40 }, /* front-mic */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			/* 0x1e is filled in below */
+			{ 0x1f, 0x411111f0 }, /* N/A */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_5ST] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_5ST_BASE,
+	},
+	[ALC880_FIXUP_5ST_DIG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_5ST_BASE,
+	},
+	[ALC880_FIXUP_6ST_BASE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x14, 0x01014010 }, /* front */
+			{ 0x15, 0x01016412 }, /* surr */
+			{ 0x16, 0x01011411 }, /* CLFE */
+			{ 0x17, 0x01012414 }, /* side */
+			{ 0x18, 0x01a19c30 }, /* mic-in */
+			{ 0x19, 0x02a19c40 }, /* front-mic */
+			{ 0x1a, 0x01813031 }, /* line-in */
+			{ 0x1b, 0x0121411f }, /* HP */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			/* 0x1e is filled in below */
+			{ 0x1f, 0x411111f0 }, /* N/A */
+			{ }
+		}
+	},
+	[ALC880_FIXUP_6ST] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_6ST_BASE,
+	},
+	[ALC880_FIXUP_6ST_DIG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1e, 0x0144111e }, /* SPDIF */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC880_FIXUP_6ST_BASE,
+	},
+	[ALC880_FIXUP_6ST_AUTOMUTE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x0121401f }, /* HP with jack detect */
+			{ }
+		},
+		.chained_before = true,
+		.chain_id = ALC880_FIXUP_6ST_BASE,
+	},
+};
+
+static const struct hda_quirk alc880_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
+	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
+	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
+	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
+	SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
+	SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
+	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
+	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
+	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
+	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
+	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
+	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
+	SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+	SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
+	SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
+	SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
+	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
+	SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
+	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
+	SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
+	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
+	SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
+	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
+
+	/* Below is the copied entries from alc880_quirks.c.
+	 * It's not quite sure whether BIOS sets the correct pin-config table
+	 * on these machines, thus they are kept to be compatible with
+	 * the old static quirks.  Once when it's confirmed to work without
+	 * these overrides, it'd be better to remove.
+	 */
+	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
+	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
+	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
+	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
+	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
+	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+	/* default Intel */
+	SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
+	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
+	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
+	{}
+};
+
+static const struct hda_model_fixup alc880_fixup_models[] = {
+	{.id = ALC880_FIXUP_3ST, .name = "3stack"},
+	{.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
+	{.id = ALC880_FIXUP_5ST, .name = "5stack"},
+	{.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
+	{.id = ALC880_FIXUP_6ST, .name = "6stack"},
+	{.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
+	{.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
+	{}
+};
+
+
+/*
+ * OK, here we have finally the patch for ALC880
+ */
+static int patch_alc880(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+	spec->gen.need_dac_fix = 1;
+	spec->gen.beep_nid = 0x01;
+
+	codec->patch_ops.unsol_event = alc880_unsol_event;
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
+		       alc880_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	/* automatic parse from the BIOS config */
+	err = alc880_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog) {
+		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc880[] = {
+	HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC880 HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc880_driver = {
+	.id = snd_hda_id_alc880,
+};
+
+module_hda_codec_driver(alc880_driver);
diff --git a/sound/hda/codecs/realtek/alc882.c b/sound/hda/codecs/realtek/alc882.c
new file mode 100644
index 000000000000..6af2f7fcc6bb
--- /dev/null
+++ b/sound/hda/codecs/realtek/alc882.c
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek ALC882/883/885/888/889 codec support
+//
+// ALC882 is almost identical with ALC880 but has cleaner and more flexible
+// configuration.  Each pin widget can choose any input DACs and a mixer.
+// Each ADC is connected from a mixer of all inputs.  This makes possible
+// 6-channel independent captures.
+//
+// In addition, an independent DAC for the multi-playback (not used in this
+// driver yet).
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/*
+ * Pin config fixes
+ */
+enum {
+	ALC882_FIXUP_ABIT_AW9D_MAX,
+	ALC882_FIXUP_LENOVO_Y530,
+	ALC882_FIXUP_PB_M5210,
+	ALC882_FIXUP_ACER_ASPIRE_7736,
+	ALC882_FIXUP_ASUS_W90V,
+	ALC889_FIXUP_CD,
+	ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
+	ALC889_FIXUP_VAIO_TT,
+	ALC888_FIXUP_EEE1601,
+	ALC886_FIXUP_EAPD,
+	ALC882_FIXUP_EAPD,
+	ALC883_FIXUP_EAPD,
+	ALC883_FIXUP_ACER_EAPD,
+	ALC882_FIXUP_GPIO1,
+	ALC882_FIXUP_GPIO2,
+	ALC882_FIXUP_GPIO3,
+	ALC889_FIXUP_COEF,
+	ALC882_FIXUP_ASUS_W2JC,
+	ALC882_FIXUP_ACER_ASPIRE_4930G,
+	ALC882_FIXUP_ACER_ASPIRE_8930G,
+	ALC882_FIXUP_ASPIRE_8930G_VERBS,
+	ALC885_FIXUP_MACPRO_GPIO,
+	ALC889_FIXUP_DAC_ROUTE,
+	ALC889_FIXUP_MBP_VREF,
+	ALC889_FIXUP_IMAC91_VREF,
+	ALC889_FIXUP_MBA11_VREF,
+	ALC889_FIXUP_MBA21_VREF,
+	ALC889_FIXUP_MP11_VREF,
+	ALC889_FIXUP_MP41_VREF,
+	ALC882_FIXUP_INV_DMIC,
+	ALC882_FIXUP_NO_PRIMARY_HP,
+	ALC887_FIXUP_ASUS_BASS,
+	ALC887_FIXUP_BASS_CHMAP,
+	ALC1220_FIXUP_GB_DUAL_CODECS,
+	ALC1220_FIXUP_GB_X570,
+	ALC1220_FIXUP_CLEVO_P950,
+	ALC1220_FIXUP_CLEVO_PB51ED,
+	ALC1220_FIXUP_CLEVO_PB51ED_PINS,
+	ALC887_FIXUP_ASUS_AUDIO,
+	ALC887_FIXUP_ASUS_HMIC,
+	ALCS1200A_FIXUP_MIC_VREF,
+	ALC888VD_FIXUP_MIC_100VREF,
+};
+
+static void alc889_fixup_coef(struct hda_codec *codec,
+			      const struct hda_fixup *fix, int action)
+{
+	if (action != HDA_FIXUP_ACT_INIT)
+		return;
+	alc_update_coef_idx(codec, 7, 0, 0x2030);
+}
+
+/* set up GPIO at initialization */
+static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->gpio_write_delay = true;
+	alc_fixup_gpio3(codec, fix, action);
+}
+
+/* Fix the connection of some pins for ALC889:
+ * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
+ * work correctly (bko#42740)
+ */
+static void alc889_fixup_dac_route(struct hda_codec *codec,
+				   const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		/* fake the connections during parsing the tree */
+		static const hda_nid_t conn1[] = { 0x0c, 0x0d };
+		static const hda_nid_t conn2[] = { 0x0e, 0x0f };
+		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
+		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
+		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
+	} else if (action == HDA_FIXUP_ACT_PROBE) {
+		/* restore the connections */
+		static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
+		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
+		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
+		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
+	}
+}
+
+/* Set VREF on HP pin */
+static void alc889_fixup_mbp_vref(struct hda_codec *codec,
+				  const struct hda_fixup *fix, int action)
+{
+	static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	if (action != HDA_FIXUP_ACT_INIT)
+		return;
+	for (i = 0; i < ARRAY_SIZE(nids); i++) {
+		unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
+		if (get_defcfg_device(val) != AC_JACK_HP_OUT)
+			continue;
+		val = snd_hda_codec_get_pin_target(codec, nids[i]);
+		val |= AC_PINCTL_VREF_80;
+		snd_hda_set_pin_ctl(codec, nids[i], val);
+		spec->gen.keep_vref_in_automute = 1;
+		break;
+	}
+}
+
+static void alc889_fixup_mac_pins(struct hda_codec *codec,
+				  const hda_nid_t *nids, int num_nids)
+{
+	struct alc_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < num_nids; i++) {
+		unsigned int val;
+		val = snd_hda_codec_get_pin_target(codec, nids[i]);
+		val |= AC_PINCTL_VREF_50;
+		snd_hda_set_pin_ctl(codec, nids[i], val);
+	}
+	spec->gen.keep_vref_in_automute = 1;
+}
+
+/* Set VREF on speaker pins on imac91 */
+static void alc889_fixup_imac91_vref(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	static const hda_nid_t nids[] = { 0x18, 0x1a };
+
+	if (action == HDA_FIXUP_ACT_INIT)
+		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba11 */
+static void alc889_fixup_mba11_vref(struct hda_codec *codec,
+				    const struct hda_fixup *fix, int action)
+{
+	static const hda_nid_t nids[] = { 0x18 };
+
+	if (action == HDA_FIXUP_ACT_INIT)
+		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba21 */
+static void alc889_fixup_mba21_vref(struct hda_codec *codec,
+				    const struct hda_fixup *fix, int action)
+{
+	static const hda_nid_t nids[] = { 0x18, 0x19 };
+
+	if (action == HDA_FIXUP_ACT_INIT)
+		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Don't take HP output as primary
+ * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
+ * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
+ */
+static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
+				       const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.no_primary_hp = 1;
+		spec->gen.no_multi_io = 1;
+	}
+}
+
+static void alc1220_fixup_gb_x570(struct hda_codec *codec,
+				     const struct hda_fixup *fix,
+				     int action)
+{
+	static const hda_nid_t conn1[] = { 0x0c };
+	static const struct coef_fw gb_x570_coefs[] = {
+		WRITE_COEF(0x07, 0x03c0),
+		WRITE_COEF(0x1a, 0x01c1),
+		WRITE_COEF(0x1b, 0x0202),
+		WRITE_COEF(0x43, 0x3005),
+		{}
+	};
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+		snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		alc_process_coef_fw(codec, gb_x570_coefs);
+		break;
+	}
+}
+
+static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
+				     const struct hda_fixup *fix,
+				     int action)
+{
+	static const hda_nid_t conn1[] = { 0x0c };
+
+	if (action != HDA_FIXUP_ACT_PRE_PROBE)
+		return;
+
+	alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
+	/* We therefore want to make sure 0x14 (front headphone) and
+	 * 0x1b (speakers) use the stereo DAC 0x02
+	 */
+	snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+	snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
+}
+
+static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
+				     const struct hda_fixup *fix,
+				     int action)
+{
+	alc1220_fixup_clevo_p950(codec, fix, action);
+	alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
+}
+
+static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
+					 struct hda_jack_callback *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int vref;
+
+	snd_hda_gen_hp_automute(codec, jack);
+
+	if (spec->gen.hp_jack_present)
+		vref = AC_PINCTL_VREF_80;
+	else
+		vref = AC_PINCTL_VREF_HIZ;
+	snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
+}
+
+static void alc887_fixup_asus_jack(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action != HDA_FIXUP_ACT_PROBE)
+		return;
+	snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
+	spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
+}
+
+static const struct hda_fixup alc882_fixups[] = {
+	[ALC882_FIXUP_ABIT_AW9D_MAX] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x01080104 }, /* side */
+			{ 0x16, 0x01011012 }, /* rear */
+			{ 0x17, 0x01016011 }, /* clfe */
+			{ }
+		}
+	},
+	[ALC882_FIXUP_LENOVO_Y530] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x99130112 }, /* rear int speakers */
+			{ 0x16, 0x99130111 }, /* subwoofer */
+			{ }
+		}
+	},
+	[ALC882_FIXUP_PB_M5210] = {
+		.type = HDA_FIXUP_PINCTLS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, PIN_VREF50 },
+			{}
+		}
+	},
+	[ALC882_FIXUP_ACER_ASPIRE_7736] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_sku_ignore,
+	},
+	[ALC882_FIXUP_ASUS_W90V] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x99130110 }, /* fix sequence for CLFE */
+			{ }
+		}
+	},
+	[ALC889_FIXUP_CD] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1c, 0x993301f0 }, /* CD */
+			{ }
+		}
+	},
+	[ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC889_FIXUP_CD,
+	},
+	[ALC889_FIXUP_VAIO_TT] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x17, 0x90170111 }, /* hidden surround speaker */
+			{ }
+		}
+	},
+	[ALC888_FIXUP_EEE1601] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+			{ 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
+			{ }
+		}
+	},
+	[ALC886_FIXUP_EAPD] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
+			{ }
+		}
+	},
+	[ALC882_FIXUP_EAPD] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
+			{ }
+		}
+	},
+	[ALC883_FIXUP_EAPD] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* change to EAPD mode */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+			{ }
+		}
+	},
+	[ALC883_FIXUP_ACER_EAPD] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* eanable EAPD on Acer laptops */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+			{ }
+		}
+	},
+	[ALC882_FIXUP_GPIO1] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio1,
+	},
+	[ALC882_FIXUP_GPIO2] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio2,
+	},
+	[ALC882_FIXUP_GPIO3] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio3,
+	},
+	[ALC882_FIXUP_ASUS_W2JC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_gpio1,
+		.chained = true,
+		.chain_id = ALC882_FIXUP_EAPD,
+	},
+	[ALC889_FIXUP_COEF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_coef,
+	},
+	[ALC882_FIXUP_ACER_ASPIRE_4930G] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x99130111 }, /* CLFE speaker */
+			{ 0x17, 0x99130112 }, /* surround speaker */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC882_FIXUP_GPIO1,
+	},
+	[ALC882_FIXUP_ACER_ASPIRE_8930G] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x99130111 }, /* CLFE speaker */
+			{ 0x1b, 0x99130112 }, /* surround speaker */
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
+	},
+	[ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
+		/* additional init verbs for Acer Aspire 8930G */
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			/* Enable all DACs */
+			/* DAC DISABLE/MUTE 1? */
+			/*  setting bits 1-5 disables DAC nids 0x02-0x06
+			 *  apparently. Init=0x38 */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+			/* DAC DISABLE/MUTE 2? */
+			/*  some bit here disables the other DACs.
+			 *  Init=0x4900 */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+			/* DMIC fix
+			 * This laptop has a stereo digital microphone.
+			 * The mics are only 1cm apart which makes the stereo
+			 * useless. However, either the mic or the ALC889
+			 * makes the signal become a difference/sum signal
+			 * instead of standard stereo, which is annoying.
+			 * So instead we flip this bit which makes the
+			 * codec replicate the sum signal to both channels,
+			 * turning it into a normal mono mic.
+			 */
+			/* DMIC_CONTROL? Init value = 0x0001 */
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+			{ }
+		},
+		.chained = true,
+		.chain_id = ALC882_FIXUP_GPIO1,
+	},
+	[ALC885_FIXUP_MACPRO_GPIO] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc885_fixup_macpro_gpio,
+	},
+	[ALC889_FIXUP_DAC_ROUTE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_dac_route,
+	},
+	[ALC889_FIXUP_MBP_VREF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_mbp_vref,
+		.chained = true,
+		.chain_id = ALC882_FIXUP_GPIO1,
+	},
+	[ALC889_FIXUP_IMAC91_VREF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_imac91_vref,
+		.chained = true,
+		.chain_id = ALC882_FIXUP_GPIO1,
+	},
+	[ALC889_FIXUP_MBA11_VREF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_mba11_vref,
+		.chained = true,
+		.chain_id = ALC889_FIXUP_MBP_VREF,
+	},
+	[ALC889_FIXUP_MBA21_VREF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_mba21_vref,
+		.chained = true,
+		.chain_id = ALC889_FIXUP_MBP_VREF,
+	},
+	[ALC889_FIXUP_MP11_VREF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_mba11_vref,
+		.chained = true,
+		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
+	},
+	[ALC889_FIXUP_MP41_VREF] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc889_fixup_mbp_vref,
+		.chained = true,
+		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
+	},
+	[ALC882_FIXUP_INV_DMIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_inv_dmic,
+	},
+	[ALC882_FIXUP_NO_PRIMARY_HP] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc882_fixup_no_primary_hp,
+	},
+	[ALC887_FIXUP_ASUS_BASS] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{0x16, 0x99130130}, /* bass speaker */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC887_FIXUP_BASS_CHMAP,
+	},
+	[ALC887_FIXUP_BASS_CHMAP] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_bass_chmap,
+	},
+	[ALC1220_FIXUP_GB_DUAL_CODECS] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc1220_fixup_gb_dual_codecs,
+	},
+	[ALC1220_FIXUP_GB_X570] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc1220_fixup_gb_x570,
+	},
+	[ALC1220_FIXUP_CLEVO_P950] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc1220_fixup_clevo_p950,
+	},
+	[ALC1220_FIXUP_CLEVO_PB51ED] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc1220_fixup_clevo_pb51ed,
+	},
+	[ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
+	},
+	[ALC887_FIXUP_ASUS_AUDIO] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
+			{ 0x19, 0x22219420 },
+			{}
+		},
+	},
+	[ALC887_FIXUP_ASUS_HMIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc887_fixup_asus_jack,
+		.chained = true,
+		.chain_id = ALC887_FIXUP_ASUS_AUDIO,
+	},
+	[ALCS1200A_FIXUP_MIC_VREF] = {
+		.type = HDA_FIXUP_PINCTLS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x18, PIN_VREF50 }, /* rear mic */
+			{ 0x19, PIN_VREF50 }, /* front mic */
+			{}
+		}
+	},
+	[ALC888VD_FIXUP_MIC_100VREF] = {
+		.type = HDA_FIXUP_PINCTLS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x18, PIN_VREF100 }, /* headset mic */
+			{}
+		}
+	},
+};
+
+static const struct hda_quirk alc882_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
+	SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+		      ALC882_FIXUP_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
+		      ALC882_FIXUP_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+		      ALC882_FIXUP_ACER_ASPIRE_8930G),
+	SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+		      ALC882_FIXUP_ACER_ASPIRE_8930G),
+	SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+		      ALC882_FIXUP_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
+	SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+		      ALC882_FIXUP_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+		      ALC882_FIXUP_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
+		      ALC882_FIXUP_ACER_ASPIRE_4930G),
+	SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
+	SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
+	SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
+	SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
+	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
+	SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
+	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
+	SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
+	SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
+	SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
+	SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
+	SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
+	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
+	SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+	SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
+
+	/* All Apple entries are in codec SSIDs */
+	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
+	SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
+	SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
+	SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
+	SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
+	SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
+	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
+
+	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
+	SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+	SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+	SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
+	SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
+	SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
+	SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
+	SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
+	SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
+	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
+	SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
+	SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
+	SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
+	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
+	SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
+	{}
+};
+
+static const struct hda_model_fixup alc882_fixup_models[] = {
+	{.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
+	{.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
+	{.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
+	{.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
+	{.id = ALC889_FIXUP_CD, .name = "cd"},
+	{.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
+	{.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
+	{.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
+	{.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
+	{.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
+	{.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
+	{.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
+	{.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
+	{.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
+	{.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
+	{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
+	{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
+	{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
+	{.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
+	{.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
+	{.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
+	{.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
+	{.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
+	{.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
+	{.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
+	{.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
+	{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
+	{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+	{.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
+	{.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+	{.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
+	{.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
+	{}
+};
+
+static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
+	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
+		{0x14, 0x01014010},
+		{0x15, 0x01011012},
+		{0x16, 0x01016011},
+		{0x18, 0x01a19040},
+		{0x19, 0x02a19050},
+		{0x1a, 0x0181304f},
+		{0x1b, 0x0221401f},
+		{0x1e, 0x01456130}),
+	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
+		{0x14, 0x01015010},
+		{0x15, 0x01011012},
+		{0x16, 0x01011011},
+		{0x18, 0x01a11040},
+		{0x19, 0x02a19050},
+		{0x1a, 0x0181104f},
+		{0x1b, 0x0221401f},
+		{0x1e, 0x01451130}),
+	{}
+};
+
+/*
+ * BIOS auto configuration
+ */
+/* almost identical with ALC880 parser... */
+static int alc882_parse_auto_config(struct hda_codec *codec)
+{
+	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+	static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+	return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
+}
+
+/*
+ */
+static int patch_alc882(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int err;
+
+	err = alc_alloc_spec(codec, 0x0b);
+	if (err < 0)
+		return err;
+
+	spec = codec->spec;
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0882:
+	case 0x10ec0885:
+	case 0x10ec0900:
+	case 0x10ec0b00:
+	case 0x10ec1220:
+		break;
+	default:
+		/* ALC883 and variants */
+		alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+		break;
+	}
+
+	alc_pre_init(codec);
+
+	snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
+		       alc882_fixups);
+	snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+	alc_auto_parse_customize_define(codec);
+
+	if (has_cdefine_beep(codec))
+		spec->gen.beep_nid = 0x01;
+
+	/* automatic parse from the BIOS config */
+	err = alc882_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	if (!spec->gen.no_analog && spec->gen.beep_nid) {
+		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+		if (err < 0)
+			goto error;
+	}
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	alc_free(codec);
+	return err;
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_alc882[] = {
+	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
+	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
+	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
+	HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
+	HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc882);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek ALC882 and compatible HD-audio codecs");
+MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
+
+static struct hda_codec_driver alc882_driver = {
+	.id = snd_hda_id_alc882,
+};
+
+module_hda_codec_driver(alc882_driver);
diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c
new file mode 100644
index 000000000000..4ab49e76c304
--- /dev/null
+++ b/sound/hda/codecs/realtek/realtek.c
@@ -0,0 +1,2314 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek HD-audio codec support code
+//
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include "realtek.h"
+
+/*
+ * COEF access helper functions
+ */
+
+static void coef_mutex_lock(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_power_up_pm(codec);
+	mutex_lock(&spec->coef_mutex);
+}
+
+static void coef_mutex_unlock(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	mutex_unlock(&spec->coef_mutex);
+	snd_hda_power_down_pm(codec);
+}
+
+static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+				 unsigned int coef_idx)
+{
+	unsigned int val;
+
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+	return val;
+}
+
+int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			unsigned int coef_idx)
+{
+	unsigned int val;
+
+	coef_mutex_lock(codec);
+	val = __alc_read_coefex_idx(codec, nid, coef_idx);
+	coef_mutex_unlock(codec);
+	return val;
+}
+EXPORT_SYMBOL_NS_GPL(alc_read_coefex_idx, "SND_HDA_CODEC_REALTEK");
+
+static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+				   unsigned int coef_idx, unsigned int coef_val)
+{
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
+}
+
+void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			  unsigned int coef_idx, unsigned int coef_val)
+{
+	coef_mutex_lock(codec);
+	__alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
+	coef_mutex_unlock(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_write_coefex_idx, "SND_HDA_CODEC_REALTEK");
+
+static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+				    unsigned int coef_idx, unsigned int mask,
+				    unsigned int bits_set)
+{
+	unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
+
+	if (val != -1)
+		__alc_write_coefex_idx(codec, nid, coef_idx,
+				       (val & ~mask) | bits_set);
+}
+
+void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			   unsigned int coef_idx, unsigned int mask,
+			   unsigned int bits_set)
+{
+	coef_mutex_lock(codec);
+	__alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
+	coef_mutex_unlock(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_coefex_idx, "SND_HDA_CODEC_REALTEK");
+
+/* a special bypass for COEF 0; read the cached value at the second time */
+unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->coef0)
+		spec->coef0 = alc_read_coef_idx(codec, 0);
+	return spec->coef0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_get_coef0, "SND_HDA_CODEC_REALTEK");
+
+void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw)
+{
+	coef_mutex_lock(codec);
+	for (; fw->nid; fw++) {
+		if (fw->mask == (unsigned short)-1)
+			__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+		else
+			__alc_update_coefex_idx(codec, fw->nid, fw->idx,
+						fw->mask, fw->val);
+	}
+	coef_mutex_unlock(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_process_coef_fw, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * GPIO setup tables, used in initialization
+ */
+
+/* Enable GPIO mask and set output */
+void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->gpio_mask |= mask;
+	spec->gpio_dir |= mask;
+	spec->gpio_data |= mask;
+}
+EXPORT_SYMBOL_NS_GPL(alc_setup_gpio, "SND_HDA_CODEC_REALTEK");
+
+void alc_write_gpio_data(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+			    spec->gpio_data);
+}
+EXPORT_SYMBOL_NS_GPL(alc_write_gpio_data, "SND_HDA_CODEC_REALTEK");
+
+void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+			  bool on)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int oldval = spec->gpio_data;
+
+	if (on)
+		spec->gpio_data |= mask;
+	else
+		spec->gpio_data &= ~mask;
+	if (oldval != spec->gpio_data)
+		alc_write_gpio_data(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_gpio_data, "SND_HDA_CODEC_REALTEK");
+
+void alc_write_gpio(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->gpio_mask)
+		return;
+
+	snd_hda_codec_write(codec, codec->core.afg, 0,
+			    AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
+	snd_hda_codec_write(codec, codec->core.afg, 0,
+			    AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
+	if (spec->gpio_write_delay)
+		msleep(1);
+	alc_write_gpio_data(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_write_gpio, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		alc_setup_gpio(codec, mask);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio1(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action)
+{
+	alc_fixup_gpio(codec, action, 0x01);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio1, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio2(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action)
+{
+	alc_fixup_gpio(codec, action, 0x02);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio2, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio3(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action)
+{
+	alc_fixup_gpio(codec, action, 0x03);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio3, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_gpio4(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action)
+{
+	alc_fixup_gpio(codec, action, 0x04);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio4, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_micmute_led(struct hda_codec *codec,
+			   const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_micmute_led, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * Fix hardware PLL issue
+ * On some codecs, the analog PLL gating control must be off while
+ * the default value is 1.
+ */
+void alc_fix_pll(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (spec->pll_nid)
+		alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
+				      1 << spec->pll_coef_bit, 0);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fix_pll, "SND_HDA_CODEC_REALTEK");
+
+void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+		      unsigned int coef_idx, unsigned int coef_bit)
+{
+	struct alc_spec *spec = codec->spec;
+	spec->pll_nid = nid;
+	spec->pll_coef_idx = coef_idx;
+	spec->pll_coef_bit = coef_bit;
+	alc_fix_pll(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fix_pll_init, "SND_HDA_CODEC_REALTEK");
+
+/* update the master volume per volume-knob's unsol event */
+void alc_update_knob_master(struct hda_codec *codec,
+			    struct hda_jack_callback *jack)
+{
+	unsigned int val;
+	struct snd_kcontrol *kctl;
+	struct snd_ctl_elem_value *uctl;
+
+	kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
+	if (!kctl)
+		return;
+	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
+	if (!uctl)
+		return;
+	val = snd_hda_codec_read(codec, jack->nid, 0,
+				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+	val &= HDA_AMP_VOLMASK;
+	uctl->value.integer.value[0] = val;
+	uctl->value.integer.value[1] = val;
+	kctl->put(kctl, uctl);
+	kfree(uctl);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_knob_master, "SND_HDA_CODEC_REALTEK");
+
+/* Change EAPD to verb control */
+void alc_fill_eapd_coef(struct hda_codec *codec)
+{
+	int coef;
+
+	coef = alc_get_coef0(codec);
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0262:
+		alc_update_coef_idx(codec, 0x7, 0, 1<<5);
+		break;
+	case 0x10ec0267:
+	case 0x10ec0268:
+		alc_update_coef_idx(codec, 0x7, 0, 1<<13);
+		break;
+	case 0x10ec0269:
+		if ((coef & 0x00f0) == 0x0010)
+			alc_update_coef_idx(codec, 0xd, 0, 1<<14);
+		if ((coef & 0x00f0) == 0x0020)
+			alc_update_coef_idx(codec, 0x4, 1<<15, 0);
+		if ((coef & 0x00f0) == 0x0030)
+			alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+		break;
+	case 0x10ec0280:
+	case 0x10ec0284:
+	case 0x10ec0290:
+	case 0x10ec0292:
+		alc_update_coef_idx(codec, 0x4, 1<<15, 0);
+		break;
+	case 0x10ec0225:
+	case 0x10ec0295:
+	case 0x10ec0299:
+		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+		fallthrough;
+	case 0x10ec0215:
+	case 0x10ec0236:
+	case 0x10ec0245:
+	case 0x10ec0256:
+	case 0x10ec0257:
+	case 0x10ec0285:
+	case 0x10ec0289:
+		alc_update_coef_idx(codec, 0x36, 1<<13, 0);
+		fallthrough;
+	case 0x10ec0230:
+	case 0x10ec0233:
+	case 0x10ec0235:
+	case 0x10ec0255:
+	case 0x19e58326:
+	case 0x10ec0282:
+	case 0x10ec0283:
+	case 0x10ec0286:
+	case 0x10ec0288:
+	case 0x10ec0298:
+	case 0x10ec0300:
+		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+		break;
+	case 0x10ec0275:
+		alc_update_coef_idx(codec, 0xe, 0, 1<<0);
+		break;
+	case 0x10ec0287:
+		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+		alc_write_coef_idx(codec, 0x8, 0x4ab7);
+		break;
+	case 0x10ec0293:
+		alc_update_coef_idx(codec, 0xa, 1<<13, 0);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+		alc_write_coef_idx(codec, 0x6e, 0x0c25);
+		fallthrough;
+	case 0x10ec0294:
+	case 0x10ec0700:
+	case 0x10ec0701:
+	case 0x10ec0703:
+	case 0x10ec0711:
+		alc_update_coef_idx(codec, 0x10, 1<<15, 0);
+		break;
+	case 0x10ec0662:
+		if ((coef & 0x00f0) == 0x0030)
+			alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
+		break;
+	case 0x10ec0272:
+	case 0x10ec0273:
+	case 0x10ec0663:
+	case 0x10ec0665:
+	case 0x10ec0670:
+	case 0x10ec0671:
+	case 0x10ec0672:
+		alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
+		break;
+	case 0x10ec0222:
+	case 0x10ec0623:
+		alc_update_coef_idx(codec, 0x19, 1<<13, 0);
+		break;
+	case 0x10ec0668:
+		alc_update_coef_idx(codec, 0x7, 3<<13, 0);
+		break;
+	case 0x10ec0867:
+		alc_update_coef_idx(codec, 0x4, 1<<10, 0);
+		break;
+	case 0x10ec0888:
+		if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
+			alc_update_coef_idx(codec, 0x7, 1<<5, 0);
+		break;
+	case 0x10ec0892:
+	case 0x10ec0897:
+		alc_update_coef_idx(codec, 0x7, 1<<5, 0);
+		break;
+	case 0x10ec0899:
+	case 0x10ec0900:
+	case 0x10ec0b00:
+	case 0x10ec1168:
+	case 0x10ec1220:
+		alc_update_coef_idx(codec, 0x7, 1<<1, 0);
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fill_eapd_coef, "SND_HDA_CODEC_REALTEK");
+
+/* turn on/off EAPD control (only if available) */
+static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
+{
+	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+		return;
+	if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+				    on ? 2 : 0);
+}
+
+/* turn on/off EAPD controls of the codec */
+void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
+{
+	/* We currently only handle front, HP */
+	static const hda_nid_t pins[] = {
+		0x0f, 0x10, 0x14, 0x15, 0x17, 0
+	};
+	const hda_nid_t *p;
+	for (p = pins; *p; p++)
+		set_eapd(codec, *p, on);
+}
+EXPORT_SYMBOL_NS_GPL(alc_auto_setup_eapd, "SND_HDA_CODEC_REALTEK");
+
+/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
+int alc_find_ext_mic_pin(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+	hda_nid_t nid;
+	unsigned int defcfg;
+	int i;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].type != AUTO_PIN_MIC)
+			continue;
+		nid = cfg->inputs[i].pin;
+		defcfg = snd_hda_codec_get_pincfg(codec, nid);
+		if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
+			continue;
+		return nid;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_find_ext_mic_pin, "SND_HDA_CODEC_REALTEK");
+
+void alc_headset_mic_no_shutup(struct hda_codec *codec)
+{
+	const struct hda_pincfg *pin;
+	int mic_pin = alc_find_ext_mic_pin(codec);
+	int i;
+
+	/* don't shut up pins when unloading the driver; otherwise it breaks
+	 * the default pin setup at the next load of the driver
+	 */
+	if (codec->bus->shutdown)
+		return;
+
+	snd_array_for_each(&codec->init_pins, i, pin) {
+		/* use read here for syncing after issuing each verb */
+		if (pin->nid != mic_pin)
+			snd_hda_codec_read(codec, pin->nid, 0,
+					AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+	}
+
+	codec->pins_shutup = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_headset_mic_no_shutup, "SND_HDA_CODEC_REALTEK");
+
+void alc_shutup_pins(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (spec->no_shutup_pins)
+		return;
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x10ec0257:
+	case 0x19e58326:
+	case 0x10ec0283:
+	case 0x10ec0285:
+	case 0x10ec0286:
+	case 0x10ec0287:
+	case 0x10ec0288:
+	case 0x10ec0295:
+	case 0x10ec0298:
+		alc_headset_mic_no_shutup(codec);
+		break;
+	default:
+		snd_hda_shutup_pins(codec);
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_shutup_pins, "SND_HDA_CODEC_REALTEK");
+
+/* generic shutup callback;
+ * just turning off EAPD and a little pause for avoiding pop-noise
+ */
+void alc_eapd_shutup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	alc_auto_setup_eapd(codec, false);
+	if (!spec->no_depop_delay)
+		msleep(200);
+	alc_shutup_pins(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_eapd_shutup, "SND_HDA_CODEC_REALTEK");
+
+/* additional initialization for ALC888 variants */
+static void alc888_coef_init(struct hda_codec *codec)
+{
+	switch (alc_get_coef0(codec) & 0x00f0) {
+	/* alc888-VA */
+	case 0x00:
+	/* alc888-VB */
+	case 0x10:
+		alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
+		break;
+	}
+}
+
+/* generic EAPD initialization */
+void alc_auto_init_amp(struct hda_codec *codec, int type)
+{
+	alc_auto_setup_eapd(codec, true);
+	alc_write_gpio(codec);
+	switch (type) {
+	case ALC_INIT_DEFAULT:
+		switch (codec->core.vendor_id) {
+		case 0x10ec0260:
+			alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
+			break;
+		case 0x10ec0880:
+		case 0x10ec0882:
+		case 0x10ec0883:
+		case 0x10ec0885:
+			alc_update_coef_idx(codec, 7, 0, 0x2030);
+			break;
+		case 0x10ec0888:
+			alc888_coef_init(codec);
+			break;
+		}
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_auto_init_amp, "SND_HDA_CODEC_REALTEK");
+
+/* get a primary headphone pin if available */
+hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
+{
+	if (spec->gen.autocfg.hp_pins[0])
+		return spec->gen.autocfg.hp_pins[0];
+	if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
+		return spec->gen.autocfg.line_out_pins[0];
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_get_hp_pin, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * Realtek SSID verification
+ */
+
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
+void alc_fixup_sku_ignore(struct hda_codec *codec,
+			  const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->cdefine.fixup = 1;
+		spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_sku_ignore, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_no_depop_delay(struct hda_codec *codec,
+			      const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PROBE) {
+		spec->no_depop_delay = 1;
+		codec->depop_delay = 0;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_no_depop_delay, "SND_HDA_CODEC_REALTEK");
+
+int alc_auto_parse_customize_define(struct hda_codec *codec)
+{
+	unsigned int ass, tmp, i;
+	unsigned nid = 0;
+	struct alc_spec *spec = codec->spec;
+
+	spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+
+	if (spec->cdefine.fixup) {
+		ass = spec->cdefine.sku_cfg;
+		if (ass == ALC_FIXUP_SKU_IGNORE)
+			return -1;
+		goto do_sku;
+	}
+
+	if (!codec->bus->pci)
+		return -1;
+	ass = codec->core.subsystem_id & 0xffff;
+	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
+		goto do_sku;
+
+	nid = 0x1d;
+	if (codec->core.vendor_id == 0x10ec0260)
+		nid = 0x17;
+	ass = snd_hda_codec_get_pincfg(codec, nid);
+
+	if (!(ass & 1)) {
+		codec_info(codec, "%s: SKU not ready 0x%08x\n",
+			   codec->core.chip_name, ass);
+		return -1;
+	}
+
+	/* check sum */
+	tmp = 0;
+	for (i = 1; i < 16; i++) {
+		if ((ass >> i) & 1)
+			tmp++;
+	}
+	if (((ass >> 16) & 0xf) != tmp)
+		return -1;
+
+	spec->cdefine.port_connectivity = ass >> 30;
+	spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
+	spec->cdefine.check_sum = (ass >> 16) & 0xf;
+	spec->cdefine.customization = ass >> 8;
+do_sku:
+	spec->cdefine.sku_cfg = ass;
+	spec->cdefine.external_amp = (ass & 0x38) >> 3;
+	spec->cdefine.platform_type = (ass & 0x4) >> 2;
+	spec->cdefine.swap = (ass & 0x2) >> 1;
+	spec->cdefine.override = ass & 0x1;
+
+	codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
+		   nid, spec->cdefine.sku_cfg);
+	codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
+		   spec->cdefine.port_connectivity);
+	codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
+	codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
+	codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
+	codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
+	codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
+	codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
+	codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_auto_parse_customize_define, "SND_HDA_CODEC_REALTEK");
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+	int i;
+	for (i = 0; i < nums; i++)
+		if (list[i] == nid)
+			return i;
+	return -1;
+}
+/* return true if the given NID is found in the list */
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+	return find_idx_in_nid_list(nid, list, nums) >= 0;
+}
+
+/* check subsystem ID and set up device-specific initialization;
+ * return 1 if initialized, 0 if invalid SSID
+ */
+/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
+ *	31 ~ 16 :	Manufacture ID
+ *	15 ~ 8	:	SKU ID
+ *	7  ~ 0	:	Assembly ID
+ *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
+ */
+int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
+{
+	unsigned int ass, tmp, i;
+	unsigned nid;
+	struct alc_spec *spec = codec->spec;
+
+	if (spec->cdefine.fixup) {
+		ass = spec->cdefine.sku_cfg;
+		if (ass == ALC_FIXUP_SKU_IGNORE)
+			return 0;
+		goto do_sku;
+	}
+
+	ass = codec->core.subsystem_id & 0xffff;
+	if (codec->bus->pci &&
+	    ass != codec->bus->pci->subsystem_device && (ass & 1))
+		goto do_sku;
+
+	/* invalid SSID, check the special NID pin defcfg instead */
+	/*
+	 * 31~30	: port connectivity
+	 * 29~21	: reserve
+	 * 20		: PCBEEP input
+	 * 19~16	: Check sum (15:1)
+	 * 15~1		: Custom
+	 * 0		: override
+	*/
+	nid = 0x1d;
+	if (codec->core.vendor_id == 0x10ec0260)
+		nid = 0x17;
+	ass = snd_hda_codec_get_pincfg(codec, nid);
+	codec_dbg(codec,
+		  "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
+		   ass, nid);
+	if (!(ass & 1))
+		return 0;
+	if ((ass >> 30) != 1)	/* no physical connection */
+		return 0;
+
+	/* check sum */
+	tmp = 0;
+	for (i = 1; i < 16; i++) {
+		if ((ass >> i) & 1)
+			tmp++;
+	}
+	if (((ass >> 16) & 0xf) != tmp)
+		return 0;
+do_sku:
+	codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+		   ass & 0xffff, codec->core.vendor_id);
+	/*
+	 * 0 : override
+	 * 1 :	Swap Jack
+	 * 2 : 0 --> Desktop, 1 --> Laptop
+	 * 3~5 : External Amplifier control
+	 * 7~6 : Reserved
+	*/
+	tmp = (ass & 0x38) >> 3;	/* external Amp control */
+	if (spec->init_amp == ALC_INIT_UNDEFINED) {
+		switch (tmp) {
+		case 1:
+			alc_setup_gpio(codec, 0x01);
+			break;
+		case 3:
+			alc_setup_gpio(codec, 0x02);
+			break;
+		case 7:
+			alc_setup_gpio(codec, 0x04);
+			break;
+		case 5:
+		default:
+			spec->init_amp = ALC_INIT_DEFAULT;
+			break;
+		}
+	}
+
+	/* is laptop or Desktop and enable the function "Mute internal speaker
+	 * when the external headphone out jack is plugged"
+	 */
+	if (!(ass & 0x8000))
+		return 1;
+	/*
+	 * 10~8 : Jack location
+	 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
+	 * 14~13: Resvered
+	 * 15   : 1 --> enable the function "Mute internal speaker
+	 *	        when the external headphone out jack is plugged"
+	 */
+	if (!alc_get_hp_pin(spec)) {
+		hda_nid_t nid;
+		tmp = (ass >> 11) & 0x3;	/* HP to chassis */
+		nid = ports[tmp];
+		if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
+				      spec->gen.autocfg.line_outs))
+			return 1;
+		spec->gen.autocfg.hp_pins[0] = nid;
+	}
+	return 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_subsystem_id, "SND_HDA_CODEC_REALTEK");
+
+/* Check the validity of ALC subsystem-id
+ * ports contains an array of 4 pin NIDs for port-A, E, D and I */
+void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
+{
+	if (!alc_subsystem_id(codec, ports)) {
+		struct alc_spec *spec = codec->spec;
+		if (spec->init_amp == ALC_INIT_UNDEFINED) {
+			codec_dbg(codec,
+				  "realtek: Enable default setup for auto mode as fallback\n");
+			spec->init_amp = ALC_INIT_DEFAULT;
+		}
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_ssid_check, "SND_HDA_CODEC_REALTEK");
+
+/* inverted digital-mic */
+void alc_fixup_inv_dmic(struct hda_codec *codec,
+			const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->gen.inv_dmic_split = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_inv_dmic, "SND_HDA_CODEC_REALTEK");
+
+int alc_build_controls(struct hda_codec *codec)
+{
+	int err;
+
+	err = snd_hda_gen_build_controls(codec);
+	if (err < 0)
+		return err;
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_build_controls, "SND_HDA_CODEC_REALTEK");
+
+int alc_init(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	/* hibernation resume needs the full chip initialization */
+	if (is_s4_resume(codec))
+		alc_pre_init(codec);
+
+	if (spec->init_hook)
+		spec->init_hook(codec);
+
+	spec->gen.skip_verbs = 1; /* applied in below */
+	snd_hda_gen_init(codec);
+	alc_fix_pll(codec);
+	alc_auto_init_amp(codec, spec->init_amp);
+	snd_hda_apply_verbs(codec); /* apply verbs here after own init */
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_init, "SND_HDA_CODEC_REALTEK");
+
+void alc_shutup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!snd_hda_get_bool_hint(codec, "shutup"))
+		return; /* disabled explicitly by hints */
+
+	if (spec && spec->shutup)
+		spec->shutup(codec);
+	else
+		alc_shutup_pins(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_shutup, "SND_HDA_CODEC_REALTEK");
+
+void alc_power_eapd(struct hda_codec *codec)
+{
+	alc_auto_setup_eapd(codec, false);
+}
+EXPORT_SYMBOL_NS_GPL(alc_power_eapd, "SND_HDA_CODEC_REALTEK");
+
+int alc_suspend(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	alc_shutup(codec);
+	if (spec && spec->power_hook)
+		spec->power_hook(codec);
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_suspend, "SND_HDA_CODEC_REALTEK");
+
+int alc_resume(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (!spec->no_depop_delay)
+		msleep(150); /* to avoid pop noise */
+	codec->patch_ops.init(codec);
+	snd_hda_regmap_sync(codec);
+	hda_call_check_power_status(codec, 0x01);
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_resume, "SND_HDA_CODEC_REALTEK");
+
+/*
+ */
+const struct hda_codec_ops alc_patch_ops = {
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.free = alc_free,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+};
+EXPORT_SYMBOL_NS_GPL(alc_patch_ops, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * Rename codecs appropriately from COEF value or subvendor id
+ */
+struct alc_codec_rename_table {
+	unsigned int vendor_id;
+	unsigned short coef_mask;
+	unsigned short coef_bits;
+	const char *name;
+};
+
+struct alc_codec_rename_pci_table {
+	unsigned int codec_vendor_id;
+	unsigned short pci_subvendor;
+	unsigned short pci_subdevice;
+	const char *name;
+};
+
+static const struct alc_codec_rename_table rename_tbl[] = {
+	{ 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
+	{ 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
+	{ 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
+	{ 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
+	{ 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
+	{ 0x10ec0269, 0xffff, 0xa023, "ALC259" },
+	{ 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
+	{ 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
+	{ 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
+	{ 0x10ec0662, 0xffff, 0x4020, "ALC656" },
+	{ 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
+	{ 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
+	{ 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
+	{ 0x10ec0899, 0x2000, 0x2000, "ALC899" },
+	{ 0x10ec0892, 0xffff, 0x8020, "ALC661" },
+	{ 0x10ec0892, 0xffff, 0x8011, "ALC661" },
+	{ 0x10ec0892, 0xffff, 0x4011, "ALC656" },
+	{ } /* terminator */
+};
+
+static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
+	{ 0x10ec0280, 0x1028, 0, "ALC3220" },
+	{ 0x10ec0282, 0x1028, 0, "ALC3221" },
+	{ 0x10ec0283, 0x1028, 0, "ALC3223" },
+	{ 0x10ec0288, 0x1028, 0, "ALC3263" },
+	{ 0x10ec0292, 0x1028, 0, "ALC3226" },
+	{ 0x10ec0293, 0x1028, 0, "ALC3235" },
+	{ 0x10ec0255, 0x1028, 0, "ALC3234" },
+	{ 0x10ec0668, 0x1028, 0, "ALC3661" },
+	{ 0x10ec0275, 0x1028, 0, "ALC3260" },
+	{ 0x10ec0899, 0x1028, 0, "ALC3861" },
+	{ 0x10ec0298, 0x1028, 0, "ALC3266" },
+	{ 0x10ec0236, 0x1028, 0, "ALC3204" },
+	{ 0x10ec0256, 0x1028, 0, "ALC3246" },
+	{ 0x10ec0225, 0x1028, 0, "ALC3253" },
+	{ 0x10ec0295, 0x1028, 0, "ALC3254" },
+	{ 0x10ec0299, 0x1028, 0, "ALC3271" },
+	{ 0x10ec0670, 0x1025, 0, "ALC669X" },
+	{ 0x10ec0676, 0x1025, 0, "ALC679X" },
+	{ 0x10ec0282, 0x1043, 0, "ALC3229" },
+	{ 0x10ec0233, 0x1043, 0, "ALC3236" },
+	{ 0x10ec0280, 0x103c, 0, "ALC3228" },
+	{ 0x10ec0282, 0x103c, 0, "ALC3227" },
+	{ 0x10ec0286, 0x103c, 0, "ALC3242" },
+	{ 0x10ec0290, 0x103c, 0, "ALC3241" },
+	{ 0x10ec0668, 0x103c, 0, "ALC3662" },
+	{ 0x10ec0283, 0x17aa, 0, "ALC3239" },
+	{ 0x10ec0292, 0x17aa, 0, "ALC3232" },
+	{ 0x10ec0257, 0x12f0, 0, "ALC3328" },
+	{ } /* terminator */
+};
+
+static int alc_codec_rename_from_preset(struct hda_codec *codec)
+{
+	const struct alc_codec_rename_table *p;
+	const struct alc_codec_rename_pci_table *q;
+
+	for (p = rename_tbl; p->vendor_id; p++) {
+		if (p->vendor_id != codec->core.vendor_id)
+			continue;
+		if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
+			return alc_codec_rename(codec, p->name);
+	}
+
+	if (!codec->bus->pci)
+		return 0;
+	for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
+		if (q->codec_vendor_id != codec->core.vendor_id)
+			continue;
+		if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
+			continue;
+		if (!q->pci_subdevice ||
+		    q->pci_subdevice == codec->bus->pci->subsystem_device)
+			return alc_codec_rename(codec, q->name);
+	}
+
+	return 0;
+}
+
+/*
+ * Digital-beep handlers
+ */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
+};
+
+/* set up and create beep controls */
+int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir)
+{
+	struct snd_kcontrol_new *knew;
+	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
+		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+					    &alc_beep_mixer[i]);
+		if (!knew)
+			return -ENOMEM;
+		knew->private_value = beep_amp;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_set_beep_amp, "SND_HDA_CODEC_REALTEK");
+
+static const struct snd_pci_quirk beep_allow_list[] = {
+	SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
+	SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
+	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+	SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
+	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
+	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+	SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
+	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
+	/* denylist -- no beep available */
+	SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
+	SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
+	{}
+};
+
+int alc_has_cdefine_beep(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	const struct snd_pci_quirk *q;
+	q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
+	if (q)
+		return q->value;
+	return spec->cdefine.enable_pcbeep;
+}
+EXPORT_SYMBOL_NS_GPL(alc_has_cdefine_beep, "SND_HDA_CODEC_REALTEK");
+
+#endif /* CONFIG_SND_HDA_INPUT_BEEP */
+
+/* parse the BIOS configuration and set up the alc_spec */
+/* return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ */
+int alc_parse_auto_config(struct hda_codec *codec,
+			  const hda_nid_t *ignore_nids,
+			  const hda_nid_t *ssid_nids)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+	int err;
+
+	err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
+				       spec->parse_flags);
+	if (err < 0)
+		return err;
+
+	if (ssid_nids)
+		alc_ssid_check(codec, ssid_nids);
+
+	err = snd_hda_gen_parse_auto_config(codec, cfg);
+	if (err < 0)
+		return err;
+
+	return 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_parse_auto_config, "SND_HDA_CODEC_REALTEK");
+
+/* common preparation job for alc_spec */
+int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
+{
+	struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	int err;
+
+	if (!spec)
+		return -ENOMEM;
+	codec->spec = spec;
+	snd_hda_gen_spec_init(&spec->gen);
+	spec->gen.mixer_nid = mixer_nid;
+	spec->gen.own_eapd_ctl = 1;
+	codec->single_adc_amp = 1;
+	/* FIXME: do we need this for all Realtek codec models? */
+	codec->spdif_status_reset = 1;
+	codec->forced_resume = 1;
+	codec->patch_ops = alc_patch_ops;
+	mutex_init(&spec->coef_mutex);
+
+	err = alc_codec_rename_from_preset(codec);
+	if (err < 0) {
+		kfree(spec);
+		return err;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(alc_alloc_spec, "SND_HDA_CODEC_REALTEK");
+
+/* For dual-codec configuration, we need to disable some features to avoid
+ * conflicts of kctls and PCM streams
+ */
+void alc_fixup_dual_codecs(struct hda_codec *codec,
+			   const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (action != HDA_FIXUP_ACT_PRE_PROBE)
+		return;
+	/* disable vmaster */
+	spec->gen.suppress_vmaster = 1;
+	/* auto-mute and auto-mic switch don't work with multiple codecs */
+	spec->gen.suppress_auto_mute = 1;
+	spec->gen.suppress_auto_mic = 1;
+	/* disable aamix as well */
+	spec->gen.mixer_nid = 0;
+	/* add location prefix to avoid conflicts */
+	codec->force_pin_prefix = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_dual_codecs, "SND_HDA_CODEC_REALTEK");
+
+static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
+	{ .channels = 2,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+	{ .channels = 4,
+	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+		   SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
+	{ }
+};
+
+/* override the 2.1 chmap */
+void alc_fixup_bass_chmap(struct hda_codec *codec,
+			  const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_BUILD) {
+		struct alc_spec *spec = codec->spec;
+		spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_bass_chmap, "SND_HDA_CODEC_REALTEK");
+
+/* exported as it's used by multiple codecs */
+void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+				  const struct hda_fixup *fix,
+				  int action)
+{
+	alc_fixup_dual_codecs(codec, fix, action);
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		/* override card longname to provide a unique UCM profile */
+		strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
+		break;
+	case HDA_FIXUP_ACT_BUILD:
+		/* rename Capture controls depending on the codec */
+		rename_ctl(codec, "Capture Volume",
+			   codec->addr == 0 ?
+			   "Rear-Panel Capture Volume" :
+			   "Front-Panel Capture Volume");
+		rename_ctl(codec, "Capture Switch",
+			   codec->addr == 0 ?
+			   "Rear-Panel Capture Switch" :
+			   "Front-Panel Capture Switch");
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc1220_fixup_gb_dual_codecs, "SND_HDA_CODEC_REALTEK");
+
+void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
+					    const struct hda_fixup *fix,
+					    int action)
+{
+	alc_fixup_dual_codecs(codec, fix, action);
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		/* override card longname to provide a unique UCM profile */
+		strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
+		break;
+	case HDA_FIXUP_ACT_BUILD:
+		/* rename Capture controls depending on the codec */
+		rename_ctl(codec, "Capture Volume",
+			   codec->addr == 0 ?
+			   "Rear-Panel Capture Volume" :
+			   "Front-Panel Capture Volume");
+		rename_ctl(codec, "Capture Switch",
+			   codec->addr == 0 ?
+			   "Rear-Panel Capture Switch" :
+			   "Front-Panel Capture Switch");
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc233_alc662_fixup_lenovo_dual_codecs, "SND_HDA_CODEC_REALTEK");
+
+static void alc_shutup_dell_xps13(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int hp_pin = alc_get_hp_pin(spec);
+
+	/* Prevent pop noises when headphones are plugged in */
+	snd_hda_codec_write(codec, hp_pin, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+	msleep(20);
+}
+
+void alc_fixup_dell_xps13(struct hda_codec *codec,
+			  const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	struct hda_input_mux *imux = &spec->gen.input_mux;
+	int i;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		/* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
+		 * it causes a click noise at start up
+		 */
+		snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+		spec->shutup = alc_shutup_dell_xps13;
+		break;
+	case HDA_FIXUP_ACT_PROBE:
+		/* Make the internal mic the default input source. */
+		for (i = 0; i < imux->num_items; i++) {
+			if (spec->gen.imux_pins[i] == 0x12) {
+				spec->gen.cur_mux[0] = i;
+				break;
+			}
+		}
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_dell_xps13, "SND_HDA_CODEC_REALTEK");
+
+/*
+ * headset handling
+ */
+
+static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
+{
+	if (delay <= 0)
+		delay = 75;
+	snd_hda_codec_write(codec, 0x21, 0,
+		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+	msleep(delay);
+	snd_hda_codec_write(codec, 0x21, 0,
+		    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+	msleep(delay);
+}
+
+static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
+{
+	if (delay <= 0)
+		delay = 75;
+	snd_hda_codec_write(codec, 0x21, 0,
+		    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+	msleep(delay);
+	snd_hda_codec_write(codec, 0x21, 0,
+		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	msleep(delay);
+}
+
+static const struct coef_fw alc225_pre_hsmode[] = {
+	UPDATE_COEF(0x4a, 1<<8, 0),
+	UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+	UPDATE_COEF(0x63, 3<<14, 3<<14),
+	UPDATE_COEF(0x4a, 3<<4, 2<<4),
+	UPDATE_COEF(0x4a, 3<<10, 3<<10),
+	UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+	UPDATE_COEF(0x4a, 3<<10, 0),
+	{}
+};
+
+static void alc_headset_mode_unplugged(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	static const struct coef_fw coef0255[] = {
+		WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+		WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+		{}
+	};
+	static const struct coef_fw coef0256[] = {
+		WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
+		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+		WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
+		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+		{}
+	};
+	static const struct coef_fw coef0233[] = {
+		WRITE_COEF(0x1b, 0x0c0b),
+		WRITE_COEF(0x45, 0xc429),
+		UPDATE_COEF(0x35, 0x4000, 0),
+		WRITE_COEF(0x06, 0x2104),
+		WRITE_COEF(0x1a, 0x0001),
+		WRITE_COEF(0x26, 0x0004),
+		WRITE_COEF(0x32, 0x42a3),
+		{}
+	};
+	static const struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
+	static const struct coef_fw coef0298[] = {
+		UPDATE_COEF(0x19, 0x1300, 0x0300),
+		{}
+	};
+	static const struct coef_fw coef0292[] = {
+		WRITE_COEF(0x76, 0x000e),
+		WRITE_COEF(0x6c, 0x2400),
+		WRITE_COEF(0x18, 0x7308),
+		WRITE_COEF(0x6b, 0xc429),
+		{}
+	};
+	static const struct coef_fw coef0293[] = {
+		UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
+		UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
+		UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
+		UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
+		WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
+		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+		{}
+	};
+	static const struct coef_fw coef0668[] = {
+		WRITE_COEF(0x15, 0x0d40),
+		WRITE_COEF(0xb7, 0x802b),
+		{}
+	};
+	static const struct coef_fw coef0225[] = {
+		UPDATE_COEF(0x63, 3<<14, 0),
+		{}
+	};
+	static const struct coef_fw coef0274[] = {
+		UPDATE_COEF(0x4a, 0x0100, 0),
+		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
+		UPDATE_COEF(0x6b, 0xf000, 0x5000),
+		UPDATE_COEF(0x4a, 0x0010, 0),
+		UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
+		WRITE_COEF(0x45, 0x5289),
+		UPDATE_COEF(0x4a, 0x0c00, 0),
+		{}
+	};
+
+	if (spec->no_internal_mic_pin) {
+		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+		return;
+	}
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0255:
+		alc_process_coef_fw(codec, coef0255);
+		break;
+	case 0x10ec0230:
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x19e58326:
+		alc_hp_mute_disable(codec, 75);
+		alc_process_coef_fw(codec, coef0256);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+	case 0x10ec0294:
+		alc_process_coef_fw(codec, coef0274);
+		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		alc_process_coef_fw(codec, coef0233);
+		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_process_coef_fw(codec, coef0288);
+		break;
+	case 0x10ec0298:
+		alc_process_coef_fw(codec, coef0298);
+		alc_process_coef_fw(codec, coef0288);
+		break;
+	case 0x10ec0292:
+		alc_process_coef_fw(codec, coef0292);
+		break;
+	case 0x10ec0293:
+		alc_process_coef_fw(codec, coef0293);
+		break;
+	case 0x10ec0668:
+		alc_process_coef_fw(codec, coef0668);
+		break;
+	case 0x10ec0215:
+	case 0x10ec0225:
+	case 0x10ec0285:
+	case 0x10ec0295:
+	case 0x10ec0289:
+	case 0x10ec0299:
+		alc_hp_mute_disable(codec, 75);
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
+		alc_process_coef_fw(codec, coef0225);
+		break;
+	case 0x10ec0867:
+		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+		break;
+	}
+	codec_dbg(codec, "Headset jack set to unplugged mode.\n");
+}
+
+
+static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+				    hda_nid_t mic_pin)
+{
+	static const struct coef_fw coef0255[] = {
+		WRITE_COEFEX(0x57, 0x03, 0x8aa6),
+		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+		{}
+	};
+	static const struct coef_fw coef0256[] = {
+		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
+		WRITE_COEFEX(0x57, 0x03, 0x09a3),
+		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+		{}
+	};
+	static const struct coef_fw coef0233[] = {
+		UPDATE_COEF(0x35, 0, 1<<14),
+		WRITE_COEF(0x06, 0x2100),
+		WRITE_COEF(0x1a, 0x0021),
+		WRITE_COEF(0x26, 0x008c),
+		{}
+	};
+	static const struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0x00c0, 0),
+		UPDATE_COEF(0x50, 0x2000, 0),
+		UPDATE_COEF(0x56, 0x0006, 0),
+		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+		UPDATE_COEF(0x66, 0x0008, 0x0008),
+		UPDATE_COEF(0x67, 0x2000, 0x2000),
+		{}
+	};
+	static const struct coef_fw coef0292[] = {
+		WRITE_COEF(0x19, 0xa208),
+		WRITE_COEF(0x2e, 0xacf0),
+		{}
+	};
+	static const struct coef_fw coef0293[] = {
+		UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
+		UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
+		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+		{}
+	};
+	static const struct coef_fw coef0688[] = {
+		WRITE_COEF(0xb7, 0x802b),
+		WRITE_COEF(0xb5, 0x1040),
+		UPDATE_COEF(0xc3, 0, 1<<12),
+		{}
+	};
+	static const struct coef_fw coef0225[] = {
+		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
+		UPDATE_COEF(0x4a, 3<<4, 2<<4),
+		UPDATE_COEF(0x63, 3<<14, 0),
+		{}
+	};
+	static const struct coef_fw coef0274[] = {
+		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
+		UPDATE_COEF(0x4a, 0x0010, 0),
+		UPDATE_COEF(0x6b, 0xf000, 0),
+		{}
+	};
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0255:
+		alc_write_coef_idx(codec, 0x45, 0xc489);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0255);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0230:
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x19e58326:
+		alc_write_coef_idx(codec, 0x45, 0xc489);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0256);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+	case 0x10ec0294:
+		alc_write_coef_idx(codec, 0x45, 0x4689);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0274);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x45, 0xc429);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0233);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+	case 0x10ec0298:
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0288);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0292:
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0292);
+		break;
+	case 0x10ec0293:
+		/* Set to TRS mode */
+		alc_write_coef_idx(codec, 0x45, 0xc429);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0293);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0867:
+		alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
+		fallthrough;
+	case 0x10ec0221:
+	case 0x10ec0662:
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0668:
+		alc_write_coef_idx(codec, 0x11, 0x0001);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0688);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	case 0x10ec0215:
+	case 0x10ec0225:
+	case 0x10ec0285:
+	case 0x10ec0295:
+	case 0x10ec0289:
+	case 0x10ec0299:
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
+		alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
+		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+		alc_process_coef_fw(codec, coef0225);
+		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+		break;
+	}
+	codec_dbg(codec, "Headset jack set to mic-in mode.\n");
+}
+
+static void alc_headset_mode_default(struct hda_codec *codec)
+{
+	static const struct coef_fw coef0225[] = {
+		UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+		UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+		UPDATE_COEF(0x49, 3<<8, 0<<8),
+		UPDATE_COEF(0x4a, 3<<4, 3<<4),
+		UPDATE_COEF(0x63, 3<<14, 0),
+		UPDATE_COEF(0x67, 0xf000, 0x3000),
+		{}
+	};
+	static const struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xc089),
+		WRITE_COEF(0x45, 0xc489),
+		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+		WRITE_COEF(0x49, 0x0049),
+		{}
+	};
+	static const struct coef_fw coef0256[] = {
+		WRITE_COEF(0x45, 0xc489),
+		WRITE_COEFEX(0x57, 0x03, 0x0da3),
+		WRITE_COEF(0x49, 0x0049),
+		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+		WRITE_COEF(0x06, 0x6100),
+		{}
+	};
+	static const struct coef_fw coef0233[] = {
+		WRITE_COEF(0x06, 0x2100),
+		WRITE_COEF(0x32, 0x4ea3),
+		{}
+	};
+	static const struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
+	static const struct coef_fw coef0292[] = {
+		WRITE_COEF(0x76, 0x000e),
+		WRITE_COEF(0x6c, 0x2400),
+		WRITE_COEF(0x6b, 0xc429),
+		WRITE_COEF(0x18, 0x7308),
+		{}
+	};
+	static const struct coef_fw coef0293[] = {
+		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+		WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
+		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+		{}
+	};
+	static const struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0041),
+		WRITE_COEF(0x15, 0x0d40),
+		WRITE_COEF(0xb7, 0x802b),
+		{}
+	};
+	static const struct coef_fw coef0274[] = {
+		WRITE_COEF(0x45, 0x4289),
+		UPDATE_COEF(0x4a, 0x0010, 0x0010),
+		UPDATE_COEF(0x6b, 0x0f00, 0),
+		UPDATE_COEF(0x49, 0x0300, 0x0300),
+		{}
+	};
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0215:
+	case 0x10ec0225:
+	case 0x10ec0285:
+	case 0x10ec0295:
+	case 0x10ec0289:
+	case 0x10ec0299:
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
+		alc_process_coef_fw(codec, coef0225);
+		alc_hp_enable_unmute(codec, 75);
+		break;
+	case 0x10ec0255:
+		alc_process_coef_fw(codec, coef0255);
+		break;
+	case 0x10ec0230:
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x19e58326:
+		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
+		alc_write_coef_idx(codec, 0x45, 0xc089);
+		msleep(50);
+		alc_process_coef_fw(codec, coef0256);
+		alc_hp_enable_unmute(codec, 75);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+	case 0x10ec0294:
+		alc_process_coef_fw(codec, coef0274);
+		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		alc_process_coef_fw(codec, coef0233);
+		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+	case 0x10ec0298:
+		alc_process_coef_fw(codec, coef0288);
+		break;
+	case 0x10ec0292:
+		alc_process_coef_fw(codec, coef0292);
+		break;
+	case 0x10ec0293:
+		alc_process_coef_fw(codec, coef0293);
+		break;
+	case 0x10ec0668:
+		alc_process_coef_fw(codec, coef0688);
+		break;
+	case 0x10ec0867:
+		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+		break;
+	}
+	codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
+}
+
+/* Iphone type */
+static void alc_headset_mode_ctia(struct hda_codec *codec)
+{
+	int val;
+
+	static const struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+		{}
+	};
+	static const struct coef_fw coef0256[] = {
+		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+		WRITE_COEF(0x1b, 0x0e6b),
+		{}
+	};
+	static const struct coef_fw coef0233[] = {
+		WRITE_COEF(0x45, 0xd429),
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEF(0x32, 0x4ea3),
+		{}
+	};
+	static const struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
+	static const struct coef_fw coef0292[] = {
+		WRITE_COEF(0x6b, 0xd429),
+		WRITE_COEF(0x76, 0x0008),
+		WRITE_COEF(0x18, 0x7388),
+		{}
+	};
+	static const struct coef_fw coef0293[] = {
+		WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
+		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+		{}
+	};
+	static const struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0001),
+		WRITE_COEF(0x15, 0x0d60),
+		WRITE_COEF(0xc3, 0x0000),
+		{}
+	};
+	static const struct coef_fw coef0225_1[] = {
+		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+		UPDATE_COEF(0x63, 3<<14, 2<<14),
+		{}
+	};
+	static const struct coef_fw coef0225_2[] = {
+		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+		UPDATE_COEF(0x63, 3<<14, 1<<14),
+		{}
+	};
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0255:
+		alc_process_coef_fw(codec, coef0255);
+		break;
+	case 0x10ec0230:
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x19e58326:
+		alc_process_coef_fw(codec, coef0256);
+		alc_hp_enable_unmute(codec, 75);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+	case 0x10ec0294:
+		alc_write_coef_idx(codec, 0x45, 0xd689);
+		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		alc_process_coef_fw(codec, coef0233);
+		break;
+	case 0x10ec0298:
+		val = alc_read_coef_idx(codec, 0x50);
+		if (val & (1 << 12)) {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+			msleep(300);
+		} else {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+			msleep(300);
+		}
+		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+		msleep(300);
+		alc_process_coef_fw(codec, coef0288);
+		break;
+	case 0x10ec0292:
+		alc_process_coef_fw(codec, coef0292);
+		break;
+	case 0x10ec0293:
+		alc_process_coef_fw(codec, coef0293);
+		break;
+	case 0x10ec0668:
+		alc_process_coef_fw(codec, coef0688);
+		break;
+	case 0x10ec0215:
+	case 0x10ec0225:
+	case 0x10ec0285:
+	case 0x10ec0295:
+	case 0x10ec0289:
+	case 0x10ec0299:
+		val = alc_read_coef_idx(codec, 0x45);
+		if (val & (1 << 9))
+			alc_process_coef_fw(codec, coef0225_2);
+		else
+			alc_process_coef_fw(codec, coef0225_1);
+		alc_hp_enable_unmute(codec, 75);
+		break;
+	case 0x10ec0867:
+		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+		break;
+	}
+	codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
+}
+
+/* Nokia type */
+static void alc_headset_mode_omtp(struct hda_codec *codec)
+{
+	static const struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+		{}
+	};
+	static const struct coef_fw coef0256[] = {
+		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+		WRITE_COEF(0x1b, 0x0e6b),
+		{}
+	};
+	static const struct coef_fw coef0233[] = {
+		WRITE_COEF(0x45, 0xe429),
+		WRITE_COEF(0x1b, 0x0c2b),
+		WRITE_COEF(0x32, 0x4ea3),
+		{}
+	};
+	static const struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		{}
+	};
+	static const struct coef_fw coef0292[] = {
+		WRITE_COEF(0x6b, 0xe429),
+		WRITE_COEF(0x76, 0x0008),
+		WRITE_COEF(0x18, 0x7388),
+		{}
+	};
+	static const struct coef_fw coef0293[] = {
+		WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
+		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+		{}
+	};
+	static const struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0001),
+		WRITE_COEF(0x15, 0x0d50),
+		WRITE_COEF(0xc3, 0x0000),
+		{}
+	};
+	static const struct coef_fw coef0225[] = {
+		UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
+		UPDATE_COEF(0x63, 3<<14, 2<<14),
+		{}
+	};
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0255:
+		alc_process_coef_fw(codec, coef0255);
+		break;
+	case 0x10ec0230:
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x19e58326:
+		alc_process_coef_fw(codec, coef0256);
+		alc_hp_enable_unmute(codec, 75);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+	case 0x10ec0294:
+		alc_write_coef_idx(codec, 0x45, 0xe689);
+		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		alc_process_coef_fw(codec, coef0233);
+		break;
+	case 0x10ec0298:
+		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
+		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+		msleep(300);
+		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+		msleep(300);
+		alc_process_coef_fw(codec, coef0288);
+		break;
+	case 0x10ec0292:
+		alc_process_coef_fw(codec, coef0292);
+		break;
+	case 0x10ec0293:
+		alc_process_coef_fw(codec, coef0293);
+		break;
+	case 0x10ec0668:
+		alc_process_coef_fw(codec, coef0688);
+		break;
+	case 0x10ec0215:
+	case 0x10ec0225:
+	case 0x10ec0285:
+	case 0x10ec0295:
+	case 0x10ec0289:
+	case 0x10ec0299:
+		alc_process_coef_fw(codec, coef0225);
+		alc_hp_enable_unmute(codec, 75);
+		break;
+	}
+	codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
+}
+
+static void alc_determine_headset_type(struct hda_codec *codec)
+{
+	int val;
+	bool is_ctia = false;
+	struct alc_spec *spec = codec->spec;
+	static const struct coef_fw coef0255[] = {
+		WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
+		WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
+ conteol) */
+		{}
+	};
+	static const struct coef_fw coef0288[] = {
+		UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
+		{}
+	};
+	static const struct coef_fw coef0298[] = {
+		UPDATE_COEF(0x50, 0x2000, 0x2000),
+		UPDATE_COEF(0x56, 0x0006, 0x0006),
+		UPDATE_COEF(0x66, 0x0008, 0),
+		UPDATE_COEF(0x67, 0x2000, 0),
+		UPDATE_COEF(0x19, 0x1300, 0x1300),
+		{}
+	};
+	static const struct coef_fw coef0293[] = {
+		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
+		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
+		{}
+	};
+	static const struct coef_fw coef0688[] = {
+		WRITE_COEF(0x11, 0x0001),
+		WRITE_COEF(0xb7, 0x802b),
+		WRITE_COEF(0x15, 0x0d60),
+		WRITE_COEF(0xc3, 0x0c00),
+		{}
+	};
+	static const struct coef_fw coef0274[] = {
+		UPDATE_COEF(0x4a, 0x0010, 0),
+		UPDATE_COEF(0x4a, 0x8000, 0),
+		WRITE_COEF(0x45, 0xd289),
+		UPDATE_COEF(0x49, 0x0300, 0x0300),
+		{}
+	};
+
+	if (spec->no_internal_mic_pin) {
+		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+		return;
+	}
+
+	switch (codec->core.vendor_id) {
+	case 0x10ec0255:
+		alc_process_coef_fw(codec, coef0255);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x46);
+		is_ctia = (val & 0x0070) == 0x0070;
+		break;
+	case 0x10ec0230:
+	case 0x10ec0236:
+	case 0x10ec0256:
+	case 0x19e58326:
+		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
+		alc_write_coef_idx(codec, 0x06, 0x6104);
+		alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
+
+		alc_process_coef_fw(codec, coef0255);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x46);
+		is_ctia = (val & 0x0070) == 0x0070;
+		if (!is_ctia) {
+			alc_write_coef_idx(codec, 0x45, 0xe089);
+			msleep(100);
+			val = alc_read_coef_idx(codec, 0x46);
+			if ((val & 0x0070) == 0x0070)
+				is_ctia = false;
+			else
+				is_ctia = true;
+		}
+		alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
+		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+		break;
+	case 0x10ec0234:
+	case 0x10ec0274:
+	case 0x10ec0294:
+		alc_process_coef_fw(codec, coef0274);
+		msleep(850);
+		val = alc_read_coef_idx(codec, 0x46);
+		is_ctia = (val & 0x00f0) == 0x00f0;
+		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		alc_write_coef_idx(codec, 0x45, 0xd029);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x46);
+		is_ctia = (val & 0x0070) == 0x0070;
+		break;
+	case 0x10ec0298:
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+		msleep(100);
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+		msleep(200);
+
+		val = alc_read_coef_idx(codec, 0x50);
+		if (val & (1 << 12)) {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+			alc_process_coef_fw(codec, coef0288);
+			msleep(350);
+			val = alc_read_coef_idx(codec, 0x50);
+			is_ctia = (val & 0x0070) == 0x0070;
+		} else {
+			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+			alc_process_coef_fw(codec, coef0288);
+			msleep(350);
+			val = alc_read_coef_idx(codec, 0x50);
+			is_ctia = (val & 0x0070) == 0x0070;
+		}
+		alc_process_coef_fw(codec, coef0298);
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+		msleep(75);
+		snd_hda_codec_write(codec, 0x21, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+		break;
+	case 0x10ec0286:
+	case 0x10ec0288:
+		alc_process_coef_fw(codec, coef0288);
+		msleep(350);
+		val = alc_read_coef_idx(codec, 0x50);
+		is_ctia = (val & 0x0070) == 0x0070;
+		break;
+	case 0x10ec0292:
+		alc_write_coef_idx(codec, 0x6b, 0xd429);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x6c);
+		is_ctia = (val & 0x001c) == 0x001c;
+		break;
+	case 0x10ec0293:
+		alc_process_coef_fw(codec, coef0293);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0x46);
+		is_ctia = (val & 0x0070) == 0x0070;
+		break;
+	case 0x10ec0668:
+		alc_process_coef_fw(codec, coef0688);
+		msleep(300);
+		val = alc_read_coef_idx(codec, 0xbe);
+		is_ctia = (val & 0x1c02) == 0x1c02;
+		break;
+	case 0x10ec0215:
+	case 0x10ec0225:
+	case 0x10ec0285:
+	case 0x10ec0295:
+	case 0x10ec0289:
+	case 0x10ec0299:
+		alc_process_coef_fw(codec, alc225_pre_hsmode);
+		alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
+		val = alc_read_coef_idx(codec, 0x45);
+		if (val & (1 << 9)) {
+			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+			alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
+			msleep(800);
+			val = alc_read_coef_idx(codec, 0x46);
+			is_ctia = (val & 0x00f0) == 0x00f0;
+		} else {
+			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+			msleep(800);
+			val = alc_read_coef_idx(codec, 0x46);
+			is_ctia = (val & 0x00f0) == 0x00f0;
+		}
+		if (!is_ctia) {
+			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
+			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+			msleep(100);
+			val = alc_read_coef_idx(codec, 0x46);
+			if ((val & 0x00f0) == 0x00f0)
+				is_ctia = false;
+			else
+				is_ctia = true;
+		}
+		alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
+		alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
+		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+		break;
+	case 0x10ec0867:
+		is_ctia = true;
+		break;
+	}
+
+	codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
+		  str_yes_no(is_ctia));
+	spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
+}
+
+static void alc_update_headset_mode(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+	hda_nid_t hp_pin = alc_get_hp_pin(spec);
+
+	int new_headset_mode;
+
+	if (!snd_hda_jack_detect(codec, hp_pin))
+		new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
+	else if (mux_pin == spec->headset_mic_pin)
+		new_headset_mode = ALC_HEADSET_MODE_HEADSET;
+	else if (mux_pin == spec->headphone_mic_pin)
+		new_headset_mode = ALC_HEADSET_MODE_MIC;
+	else
+		new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
+
+	if (new_headset_mode == spec->current_headset_mode) {
+		snd_hda_gen_update_outputs(codec);
+		return;
+	}
+
+	switch (new_headset_mode) {
+	case ALC_HEADSET_MODE_UNPLUGGED:
+		alc_headset_mode_unplugged(codec);
+		spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
+		spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
+		spec->gen.hp_jack_present = false;
+		break;
+	case ALC_HEADSET_MODE_HEADSET:
+		if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
+			alc_determine_headset_type(codec);
+		if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
+			alc_headset_mode_ctia(codec);
+		else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
+			alc_headset_mode_omtp(codec);
+		spec->gen.hp_jack_present = true;
+		break;
+	case ALC_HEADSET_MODE_MIC:
+		alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
+		spec->gen.hp_jack_present = false;
+		break;
+	case ALC_HEADSET_MODE_HEADPHONE:
+		alc_headset_mode_default(codec);
+		spec->gen.hp_jack_present = true;
+		break;
+	}
+	if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
+		snd_hda_set_pin_ctl_cache(codec, hp_pin,
+					  AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+		if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
+			snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
+						  PIN_VREFHIZ);
+	}
+	spec->current_headset_mode = new_headset_mode;
+
+	snd_hda_gen_update_outputs(codec);
+}
+
+static void alc_update_headset_mode_hook(struct hda_codec *codec,
+					 struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	alc_update_headset_mode(codec);
+}
+
+void alc_update_headset_jack_cb(struct hda_codec *codec,
+				struct hda_jack_callback *jack)
+{
+	snd_hda_gen_hp_automute(codec, jack);
+	alc_update_headset_mode(codec);
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_headset_jack_cb, "SND_HDA_CODEC_REALTEK");
+
+static void alc_probe_headset_mode(struct hda_codec *codec)
+{
+	int i;
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+	/* Find mic pins */
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
+			spec->headset_mic_pin = cfg->inputs[i].pin;
+		if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
+			spec->headphone_mic_pin = cfg->inputs[i].pin;
+	}
+
+	WARN_ON(spec->gen.cap_sync_hook);
+	spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
+	spec->gen.automute_hook = alc_update_headset_mode;
+	spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
+}
+
+void alc_fixup_headset_mode(struct hda_codec *codec,
+			    const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
+		break;
+	case HDA_FIXUP_ACT_PROBE:
+		alc_probe_headset_mode(codec);
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		if (is_s3_resume(codec) || is_s4_resume(codec)) {
+			spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
+			spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
+		}
+		alc_update_headset_mode(codec);
+		break;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+				      const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		struct alc_spec *spec = codec->spec;
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+	}
+	else
+		alc_fixup_headset_mode(codec, fix, action);
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode_no_hp_mic, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_headset_mic(struct hda_codec *codec,
+			   const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mic, "SND_HDA_CODEC_REALTEK");
+
+/* update LED status via GPIO */
+void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+			 int polarity, bool enabled)
+{
+	if (polarity)
+		enabled = !enabled;
+	alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
+}
+EXPORT_SYMBOL_NS_GPL(alc_update_gpio_led, "SND_HDA_CODEC_REALTEK");
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static int micmute_led_set(struct led_classdev *led_cdev,
+			   enum led_brightness brightness)
+{
+	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+	struct alc_spec *spec = codec->spec;
+
+	alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+			    spec->micmute_led_polarity, !brightness);
+	return 0;
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static int gpio_mute_led_set(struct led_classdev *led_cdev,
+			     enum led_brightness brightness)
+{
+	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+	struct alc_spec *spec = codec->spec;
+
+	alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
+			    spec->mute_led_polarity, !brightness);
+	return 0;
+}
+
+/* setup mute and mic-mute GPIO bits, add hooks appropriately */
+void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+			   int action,
+			   unsigned int mute_mask,
+			   unsigned int micmute_mask)
+{
+	struct alc_spec *spec = codec->spec;
+
+	alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
+
+	if (action != HDA_FIXUP_ACT_PRE_PROBE)
+		return;
+	if (mute_mask) {
+		spec->gpio_mute_led_mask = mute_mask;
+		snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
+	}
+	if (micmute_mask) {
+		spec->gpio_mic_led_mask = micmute_mask;
+		snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_hp_gpio_led, "SND_HDA_CODEC_REALTEK");
+
+/* suppress the jack-detection */
+void alc_fixup_no_jack_detect(struct hda_codec *codec,
+			      const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		codec->no_jack_detect = 1;
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_no_jack_detect, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_disable_aamix(struct hda_codec *codec,
+			     const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		struct alc_spec *spec = codec->spec;
+		/* Disable AA-loopback as it causes white noise */
+		spec->gen.mixer_nid = 0;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_disable_aamix, "SND_HDA_CODEC_REALTEK");
+
+void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action)
+{
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		struct alc_spec *spec = codec->spec;
+		spec->gen.auto_mute_via_amp = 1;
+	}
+}
+EXPORT_SYMBOL_NS_GPL(alc_fixup_auto_mute_via_amp, "SND_HDA_CODEC_REALTEK");
+
+MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek HD-audio codec helper");
diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h
new file mode 100644
index 000000000000..ac142f2540e3
--- /dev/null
+++ b/sound/hda/codecs/realtek/realtek.h
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Realtek HD-audio codec support code
+//
+
+#ifndef __HDA_REALTEK_H
+#define __HDA_REALTEK_H
+
+#include <linux/acpi.h>
+#include <linux/cleanup.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "../side-codecs/hda_component.h"
+
+/* extra amp-initialization sequence types */
+enum {
+	ALC_INIT_UNDEFINED,
+	ALC_INIT_NONE,
+	ALC_INIT_DEFAULT,
+};
+
+enum {
+	ALC_HEADSET_MODE_UNKNOWN,
+	ALC_HEADSET_MODE_UNPLUGGED,
+	ALC_HEADSET_MODE_HEADSET,
+	ALC_HEADSET_MODE_MIC,
+	ALC_HEADSET_MODE_HEADPHONE,
+};
+
+enum {
+	ALC_HEADSET_TYPE_UNKNOWN,
+	ALC_HEADSET_TYPE_CTIA,
+	ALC_HEADSET_TYPE_OMTP,
+};
+
+enum {
+	ALC_KEY_MICMUTE_INDEX,
+};
+
+struct alc_customize_define {
+	unsigned int  sku_cfg;
+	unsigned char port_connectivity;
+	unsigned char check_sum;
+	unsigned char customization;
+	unsigned char external_amp;
+	unsigned int  enable_pcbeep:1;
+	unsigned int  platform_type:1;
+	unsigned int  swap:1;
+	unsigned int  override:1;
+	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
+};
+
+struct alc_coef_led {
+	unsigned int idx;
+	unsigned int mask;
+	unsigned int on;
+	unsigned int off;
+};
+
+struct alc_spec {
+	struct hda_gen_spec gen; /* must be at head */
+
+	/* codec parameterization */
+	struct alc_customize_define cdefine;
+	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+	/* GPIO bits */
+	unsigned int gpio_mask;
+	unsigned int gpio_dir;
+	unsigned int gpio_data;
+	bool gpio_write_delay;	/* add a delay before writing gpio_data */
+
+	/* mute LED for HP laptops, see vref_mute_led_set() */
+	int mute_led_polarity;
+	int micmute_led_polarity;
+	hda_nid_t mute_led_nid;
+	hda_nid_t cap_mute_led_nid;
+
+	unsigned int gpio_mute_led_mask;
+	unsigned int gpio_mic_led_mask;
+	struct alc_coef_led mute_led_coef;
+	struct alc_coef_led mic_led_coef;
+	struct mutex coef_mutex;
+
+	hda_nid_t headset_mic_pin;
+	hda_nid_t headphone_mic_pin;
+	int current_headset_mode;
+	int current_headset_type;
+
+	/* hooks */
+	void (*init_hook)(struct hda_codec *codec);
+	void (*power_hook)(struct hda_codec *codec);
+	void (*shutup)(struct hda_codec *codec);
+
+	int init_amp;
+	int codec_variant;	/* flag for other variants */
+	unsigned int has_alc5505_dsp:1;
+	unsigned int no_depop_delay:1;
+	unsigned int done_hp_init:1;
+	unsigned int no_shutup_pins:1;
+	unsigned int ultra_low_power:1;
+	unsigned int has_hs_key:1;
+	unsigned int no_internal_mic_pin:1;
+	unsigned int en_3kpull_low:1;
+	int num_speaker_amps;
+
+	/* for PLL fix */
+	hda_nid_t pll_nid;
+	unsigned int pll_coef_idx, pll_coef_bit;
+	unsigned int coef0;
+	struct input_dev *kb_dev;
+	u8 alc_mute_keycode_map[1];
+
+	/* component binding */
+	struct hda_component_parent comps;
+};
+
+int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			unsigned int coef_idx);
+void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			  unsigned int coef_idx, unsigned int coef_val);
+void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+			   unsigned int coef_idx, unsigned int mask,
+			   unsigned int bits_set);
+#define alc_read_coef_idx(codec, coef_idx) \
+	alc_read_coefex_idx(codec, 0x20, coef_idx)
+#define alc_write_coef_idx(codec, coef_idx, coef_val) \
+	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
+#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)	\
+	alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
+
+unsigned int alc_get_coef0(struct hda_codec *codec);
+
+/* coef writes/updates batch */
+struct coef_fw {
+	unsigned char nid;
+	unsigned char idx;
+	unsigned short mask;
+	unsigned short val;
+};
+
+#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
+	{ .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
+#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
+#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
+#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
+
+void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw);
+
+/*
+ * GPIO helpers
+ */
+void alc_setup_gpio(struct hda_codec *codec, unsigned int mask);
+void alc_write_gpio_data(struct hda_codec *codec);
+void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+			  bool on);
+void alc_write_gpio(struct hda_codec *codec);
+
+/* common GPIO fixups */
+void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask);
+void alc_fixup_gpio1(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action);
+void alc_fixup_gpio2(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action);
+void alc_fixup_gpio3(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action);
+void alc_fixup_gpio4(struct hda_codec *codec,
+		     const struct hda_fixup *fix, int action);
+void alc_fixup_micmute_led(struct hda_codec *codec,
+			   const struct hda_fixup *fix, int action);
+
+/*
+ * Common init code, callbacks and helpers
+ */
+void alc_fix_pll(struct hda_codec *codec);
+void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+		      unsigned int coef_idx, unsigned int coef_bit);
+void alc_fill_eapd_coef(struct hda_codec *codec);
+void alc_auto_setup_eapd(struct hda_codec *codec, bool on);
+
+int alc_find_ext_mic_pin(struct hda_codec *codec);
+void alc_headset_mic_no_shutup(struct hda_codec *codec);
+void alc_shutup_pins(struct hda_codec *codec);
+void alc_eapd_shutup(struct hda_codec *codec);
+void alc_auto_init_amp(struct hda_codec *codec, int type);
+hda_nid_t alc_get_hp_pin(struct alc_spec *spec);
+int alc_auto_parse_customize_define(struct hda_codec *codec);
+int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports);
+void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports);
+int alc_build_controls(struct hda_codec *codec);
+void alc_update_knob_master(struct hda_codec *codec,
+			    struct hda_jack_callback *jack);
+
+static inline void alc_pre_init(struct hda_codec *codec)
+{
+	alc_fill_eapd_coef(codec);
+}
+
+#define is_s3_resume(codec) \
+	((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
+#define is_s4_resume(codec) \
+	((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
+#define is_s4_suspend(codec) \
+	((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
+
+int alc_init(struct hda_codec *codec);
+void alc_shutup(struct hda_codec *codec);
+void alc_power_eapd(struct hda_codec *codec);
+int alc_suspend(struct hda_codec *codec);
+int alc_resume(struct hda_codec *codec);
+
+#define alc_free	snd_hda_gen_free
+
+int alc_parse_auto_config(struct hda_codec *codec,
+			  const hda_nid_t *ignore_nids,
+			  const hda_nid_t *ssid_nids);
+int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid);
+
+extern const struct hda_codec_ops alc_patch_ops;
+
+#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir);
+int alc_has_cdefine_beep(struct hda_codec *codec);
+#define set_beep_amp		alc_set_beep_amp
+#define has_cdefine_beep	alc_has_cdefine_beep
+#else
+#define set_beep_amp(spec, nid, idx, dir)	0
+#define has_cdefine_beep(codec)		0
+#endif
+
+static inline void rename_ctl(struct hda_codec *codec, const char *oldname,
+			      const char *newname)
+{
+	struct snd_kcontrol *kctl;
+
+	kctl = snd_hda_find_mixer_ctl(codec, oldname);
+	if (kctl)
+		snd_ctl_rename(codec->card, kctl, newname);
+}
+
+/* Common fixups */
+void alc_fixup_sku_ignore(struct hda_codec *codec,
+			  const struct hda_fixup *fix, int action);
+void alc_fixup_no_depop_delay(struct hda_codec *codec,
+			      const struct hda_fixup *fix, int action);
+void alc_fixup_inv_dmic(struct hda_codec *codec,
+			const struct hda_fixup *fix, int action);
+void alc_fixup_dual_codecs(struct hda_codec *codec,
+			   const struct hda_fixup *fix, int action);
+void alc_fixup_bass_chmap(struct hda_codec *codec,
+			  const struct hda_fixup *fix, int action);
+void alc_fixup_headset_mode(struct hda_codec *codec,
+			    const struct hda_fixup *fix, int action);
+void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+				      const struct hda_fixup *fix, int action);
+void alc_fixup_headset_mic(struct hda_codec *codec,
+			   const struct hda_fixup *fix, int action);
+void alc_update_headset_jack_cb(struct hda_codec *codec,
+				struct hda_jack_callback *jack);
+void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+			 int polarity, bool enabled);
+void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+			   int action,
+			   unsigned int mute_mask,
+			   unsigned int micmute_mask);
+void alc_fixup_no_jack_detect(struct hda_codec *codec,
+			      const struct hda_fixup *fix, int action);
+void alc_fixup_disable_aamix(struct hda_codec *codec,
+			     const struct hda_fixup *fix, int action);
+void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action);
+
+/* device-specific, but used by multiple codec drivers */
+void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+				  const struct hda_fixup *fix,
+				  int action);
+void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
+					    const struct hda_fixup *fix,
+					    int action);
+void alc_fixup_dell_xps13(struct hda_codec *codec,
+			  const struct hda_fixup *fix, int action);
+
+#endif /* __HDA_REALTEK_H */
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 08/27] ALSA: hda/hdmi: Split vendor codec drivers
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (6 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 07/27] ALSA: hda: Split Realtek HD-audio codec driver Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 09/27] ALSA: hda: Introduce hda_codec_driver ops Takashi Iwai
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

In the past, we unified HD-audio HDMI codec driver once with a slight
hope that more vendors will follow the standard, but in reality, the
driver received more and more vendor-specific code.  In order to make
the messy code a bit more understandable, this patch splits the HDMI
codec driver into multiple drivers again.

Namely, the vendor-specific code for Intel, AMD and Nvidia are moved
into the own drivers, while we split the common HDMI code to two
drivers, the generic HDMI driver and the simple HDMI driver.
So, now we have:

- The generic HDMI driver (snd-hda-codec-hdmi):
  providing the common helpers, also supports Glenfly HDMI codecs and
  some other codecs that don't need vendor-specific stuff

- The simple HDMI driver (snd-hda-codec-simplehdmi):
  devices with no dynamic PCM assignment and with fixed channels,
  mostly used by some other drivers, but this driver alone suffices
  for VIA HDMI codec support, too

- Intel HDMI driver (snd-hda-codec-intelhdmi):
  bound with i915 / Xe DRM, based on the generic HDMI driver

- AMD/ATI HDMI driver (snd-hda-codec-atihdmi):
  optionally bound with radeon / amdgpu DRM, based on the generic HDMI
  driver

- Nvidia HDMI driver (snd-hda-codec-nvhdmi);
  optionally bound with nouveau DRM, based on the generic HDMI driver

- Legacy Nvidia HDMI driver (snd-hda-codec-nvhdmi-mcp):
  for 2ch or 8ch outputs, based on the simple HDMI driver

- Nvidia Tegra HDMI driver (snd-hda-codec-tegrahdmi):
  based on the generic HDMI driver

Along with the driver split, the enable_silent_stream module option is
moved to snd-hda-codec-intelhdmi, too, as it's an Intel-specific
feature.

Most of the changes here are just to split and move the code to
different files, as well as to rename/expose the functions that are
commonly used by drivers.

The silent stream handling code is slightly modified for putting the
stuff into Intel driver; now a new callback "silent_stream" is defined
in hdmi_ops, and it's called in silent_stream_enable() and *_disable()
functions.  The runtime-PM handling in silent_stream_enable() was
cleaned up, and rather taking the runtime PM refcount in the
silent_stream() callback appropriately, instead.

Other than that, there should be no functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/Kconfig           |   31 +-
 sound/hda/codecs/hdmi/Kconfig      |   68 +
 sound/hda/codecs/hdmi/Makefile     |   12 +
 sound/hda/codecs/hdmi/atihdmi.c    |  606 +++++++
 sound/hda/codecs/hdmi/eld.c        |  172 --
 sound/hda/codecs/hdmi/hdmi.c       | 2465 +---------------------------
 sound/hda/codecs/hdmi/hdmi_local.h |  302 ++++
 sound/hda/codecs/hdmi/intelhdmi.c  |  760 +++++++++
 sound/hda/codecs/hdmi/nvhdmi-mcp.c |  382 +++++
 sound/hda/codecs/hdmi/nvhdmi.c     |  218 +++
 sound/hda/codecs/hdmi/simplehdmi.c |  241 +++
 sound/hda/codecs/hdmi/tegrahdmi.c  |  313 ++++
 sound/hda/common/hda_local.h       |    4 -
 13 files changed, 2993 insertions(+), 2581 deletions(-)
 create mode 100644 sound/hda/codecs/hdmi/Kconfig
 create mode 100644 sound/hda/codecs/hdmi/atihdmi.c
 create mode 100644 sound/hda/codecs/hdmi/hdmi_local.h
 create mode 100644 sound/hda/codecs/hdmi/intelhdmi.c
 create mode 100644 sound/hda/codecs/hdmi/nvhdmi-mcp.c
 create mode 100644 sound/hda/codecs/hdmi/nvhdmi.c
 create mode 100644 sound/hda/codecs/hdmi/simplehdmi.c
 create mode 100644 sound/hda/codecs/hdmi/tegrahdmi.c

diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
index 0bb675ab84fe..e8c2efd2efb6 100644
--- a/sound/hda/codecs/Kconfig
+++ b/sound/hda/codecs/Kconfig
@@ -35,21 +35,6 @@ config SND_HDA_CODEC_VIA
 comment "Set to Y if you want auto-loading the codec driver"
 	depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
 
-config SND_HDA_CODEC_HDMI
-	tristate "Build HDMI/DisplayPort HD-audio codec support"
-	select SND_DYNAMIC_MINORS
-	select SND_PCM_ELD
-	help
-	  Say Y or M here to include HDMI and DisplayPort HD-audio codec
-	  support in snd-hda-intel driver.  This includes all AMD/ATI,
-	  Intel and Nvidia HDMI/DisplayPort codecs.
-
-	  Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS
-	  to assure the multiple streams for DP-MST support.
-
-comment "Set to Y if you want auto-loading the codec driver"
-	depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
-
 config SND_HDA_CODEC_CONEXANT
 	tristate "Build Conexant HD-audio codec support"
 	select SND_HDA_GENERIC
@@ -134,23 +119,9 @@ config SND_HDA_GENERIC
 comment "Set to Y if you want auto-loading the codec driver"
 	depends on SND_HDA=y && SND_HDA_GENERIC=m
 
-config SND_HDA_INTEL_HDMI_SILENT_STREAM
-	bool "Enable Silent Stream always for HDMI"
-	depends on SND_HDA_INTEL
-	help
-	  Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
-	  for HDMI on hardware that supports the feature.
-
-	  When enabled, the HDMI/DisplayPort codec will continue to provide
-	  a continuous clock and a valid but silent data stream to
-	  any connected external receiver. This allows to avoid gaps
-	  at start of playback. Many receivers require multiple seconds
-	  to start playing audio after the clock has been stopped.
-	  This feature can impact power consumption as resources
-	  are kept reserved both at transmitter and receiver.
-
 source "sound/hda/codecs/realtek/Kconfig"
 source "sound/hda/codecs/cirrus/Kconfig"
+source "sound/hda/codecs/hdmi/Kconfig"
 source "sound/hda/codecs/side-codecs/Kconfig"
 
 endif # SND_HDA
diff --git a/sound/hda/codecs/hdmi/Kconfig b/sound/hda/codecs/hdmi/Kconfig
new file mode 100644
index 000000000000..498000d2c6ae
--- /dev/null
+++ b/sound/hda/codecs/hdmi/Kconfig
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SND_HDA_CODEC_HDMI
+	tristate "Generic HDMI/DisplayPort HD-audio codec support"
+	select SND_DYNAMIC_MINORS
+	select SND_PCM_ELD
+	help
+	  Say Y or M here to include Generic HDMI and DisplayPort HD-audio
+	  codec support.
+
+	  Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS
+	  to assure the multiple streams for DP-MST support.
+
+config SND_HDA_CODEC_HDMI_SIMPLE
+	tristate "Simple HDMI/DisplayPort HD-audio codec support"
+	help
+	  Say Y or M here to include Simple HDMI and DisplayPort HD-audio
+	  codec support for VIA and other codecs.
+
+config SND_HDA_CODEC_HDMI_INTEL
+	tristate "Intel HDMI/DisplayPort HD-audio codec support"
+	select SND_HDA_CODEC_HDMI
+	help
+	  Say Y or M here to include Intel graphics HDMI and DisplayPort
+	  HD-audio codec support.
+
+config SND_HDA_INTEL_HDMI_SILENT_STREAM
+	bool "Enable Silent Stream always for HDMI"
+	depends on SND_HDA_CODEC_HDMI_INTEL
+	help
+	  Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
+	  for HDMI on hardware that supports the feature.
+
+	  When enabled, the HDMI/DisplayPort codec will continue to provide
+	  a continuous clock and a valid but silent data stream to
+	  any connected external receiver. This allows to avoid gaps
+	  at start of playback. Many receivers require multiple seconds
+	  to start playing audio after the clock has been stopped.
+	  This feature can impact power consumption as resources
+	  are kept reserved both at transmitter and receiver.
+
+config SND_HDA_CODEC_HDMI_ATI
+	tristate "AMD/ATI HDMI/DisplayPort HD-audio codec support"
+	select SND_HDA_CODEC_HDMI
+	help
+	  Say Y or M here to include AMD/ATI graphics HDMI and DisplayPort
+	  HD-audio codec support.
+
+config SND_HDA_CODEC_HDMI_NVIDIA
+	tristate "Nvidia HDMI/DisplayPort HD-audio codec support"
+	select SND_HDA_CODEC_HDMI
+	help
+	  Say Y or M here to include HDMI and DisplayPort HD-audio codec
+	  support for the recent Nvidia graphics cards.
+
+config SND_HDA_CODEC_HDMI_NVIDIA_MCP
+	tristate "Legacy Nvidia HDMI/DisplayPort HD-audio codec support"
+	select SND_HDA_CODEC_HDMI_SIMPLE
+	help
+	  Say Y or M here to include HDMI and DisplayPort HD-audio codec
+	  support for the legacy Nvidia graphics like MCP73, MCP67, MCP77/78.
+
+config SND_HDA_CODEC_HDMI_TEGRA
+	tristate "Nvidia Tegra HDMI/DisplayPort HD-audio codec support"
+	select SND_HDA_CODEC_HDMI
+	help
+	  Say Y or M here to include HDMI and DisplayPort HD-audio codec
+	  support for Nvidia Tegra.
diff --git a/sound/hda/codecs/hdmi/Makefile b/sound/hda/codecs/hdmi/Makefile
index 371818d4e9b2..c07a0a71b64f 100644
--- a/sound/hda/codecs/hdmi/Makefile
+++ b/sound/hda/codecs/hdmi/Makefile
@@ -2,5 +2,17 @@
 subdir-ccflags-y += -I$(src)/../../common
 
 snd-hda-codec-hdmi-y :=		hdmi.o eld.o
+snd-hda-codec-simplehdmi-y :=	simplehdmi.o
+snd-hda-codec-intelhdmi-y :=	intelhdmi.o
+snd-hda-codec-atihdmi-y :=	atihdmi.o
+snd-hda-codec-nvhdmi-y :=	nvhdmi.o
+snd-hda-codec-nvhdmi-mcp-y :=	nvhdmi-mcp.o
+snd-hda-codec-tegrahdmi-y :=	tegrahdmi.o
 
 obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_SIMPLE) += snd-hda-codec-simplehdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_INTEL) += snd-hda-codec-intelhdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_ATI) += snd-hda-codec-atihdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_NVIDIA) += snd-hda-codec-nvhdmi.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP) += snd-hda-codec-nvhdmi-mcp.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI_TEGRA) += snd-hda-codec-tegrahdmi.o
diff --git a/sound/hda/codecs/hdmi/atihdmi.c b/sound/hda/codecs/hdmi/atihdmi.c
new file mode 100644
index 000000000000..e23995cc1b8c
--- /dev/null
+++ b/sound/hda/codecs/hdmi/atihdmi.c
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ATI/AMD codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/unaligned.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+#define is_amdhdmi_rev3_or_later(codec) \
+	((codec)->core.vendor_id == 0x1002aa01 && \
+	 ((codec)->core.revision_id & 0xff00) >= 0x0300)
+#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
+
+/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
+#define ATI_VERB_SET_CHANNEL_ALLOCATION	0x771
+#define ATI_VERB_SET_DOWNMIX_INFO	0x772
+#define ATI_VERB_SET_MULTICHANNEL_01	0x777
+#define ATI_VERB_SET_MULTICHANNEL_23	0x778
+#define ATI_VERB_SET_MULTICHANNEL_45	0x779
+#define ATI_VERB_SET_MULTICHANNEL_67	0x77a
+#define ATI_VERB_SET_HBR_CONTROL	0x77c
+#define ATI_VERB_SET_MULTICHANNEL_1	0x785
+#define ATI_VERB_SET_MULTICHANNEL_3	0x786
+#define ATI_VERB_SET_MULTICHANNEL_5	0x787
+#define ATI_VERB_SET_MULTICHANNEL_7	0x788
+#define ATI_VERB_SET_MULTICHANNEL_MODE	0x789
+#define ATI_VERB_GET_CHANNEL_ALLOCATION	0xf71
+#define ATI_VERB_GET_DOWNMIX_INFO	0xf72
+#define ATI_VERB_GET_MULTICHANNEL_01	0xf77
+#define ATI_VERB_GET_MULTICHANNEL_23	0xf78
+#define ATI_VERB_GET_MULTICHANNEL_45	0xf79
+#define ATI_VERB_GET_MULTICHANNEL_67	0xf7a
+#define ATI_VERB_GET_HBR_CONTROL	0xf7c
+#define ATI_VERB_GET_MULTICHANNEL_1	0xf85
+#define ATI_VERB_GET_MULTICHANNEL_3	0xf86
+#define ATI_VERB_GET_MULTICHANNEL_5	0xf87
+#define ATI_VERB_GET_MULTICHANNEL_7	0xf88
+#define ATI_VERB_GET_MULTICHANNEL_MODE	0xf89
+
+/* AMD specific HDA cvt verbs */
+#define ATI_VERB_SET_RAMP_RATE		0x770
+#define ATI_VERB_GET_RAMP_RATE		0xf70
+
+#define ATI_OUT_ENABLE 0x1
+
+#define ATI_MULTICHANNEL_MODE_PAIRED	0
+#define ATI_MULTICHANNEL_MODE_SINGLE	1
+
+#define ATI_HBR_CAPABLE 0x01
+#define ATI_HBR_ENABLE 0x10
+
+/* ATI/AMD specific ELD emulation */
+
+#define ATI_VERB_SET_AUDIO_DESCRIPTOR	0x776
+#define ATI_VERB_SET_SINK_INFO_INDEX	0x780
+#define ATI_VERB_GET_SPEAKER_ALLOCATION	0xf70
+#define ATI_VERB_GET_AUDIO_DESCRIPTOR	0xf76
+#define ATI_VERB_GET_AUDIO_VIDEO_DELAY	0xf7b
+#define ATI_VERB_GET_SINK_INFO_INDEX	0xf80
+#define ATI_VERB_GET_SINK_INFO_DATA	0xf81
+
+#define ATI_SPKALLOC_SPKALLOC		0x007f
+#define ATI_SPKALLOC_TYPE_HDMI		0x0100
+#define ATI_SPKALLOC_TYPE_DISPLAYPORT	0x0200
+
+/* first three bytes are just standard SAD */
+#define ATI_AUDIODESC_CHANNELS		0x00000007
+#define ATI_AUDIODESC_RATES		0x0000ff00
+#define ATI_AUDIODESC_LPCM_STEREO_RATES	0xff000000
+
+/* in standard HDMI VSDB format */
+#define ATI_DELAY_VIDEO_LATENCY		0x000000ff
+#define ATI_DELAY_AUDIO_LATENCY		0x0000ff00
+
+enum ati_sink_info_idx {
+	ATI_INFO_IDX_MANUFACTURER_ID	= 0,
+	ATI_INFO_IDX_PRODUCT_ID		= 1,
+	ATI_INFO_IDX_SINK_DESC_LEN	= 2,
+	ATI_INFO_IDX_PORT_ID_LOW	= 3,
+	ATI_INFO_IDX_PORT_ID_HIGH	= 4,
+	ATI_INFO_IDX_SINK_DESC_FIRST	= 5,
+	ATI_INFO_IDX_SINK_DESC_LAST	= 22, /* max len 18 bytes */
+};
+
+static int get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
+		       unsigned char *buf, int *eld_size, bool rev3_or_later)
+{
+	int spkalloc, ati_sad, aud_synch;
+	int sink_desc_len = 0;
+	int pos, i;
+
+	/* ATI/AMD does not have ELD, emulate it */
+
+	spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
+
+	if (spkalloc <= 0) {
+		codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
+		return -EINVAL;
+	}
+
+	memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
+
+	/* version */
+	buf[0] = ELD_VER_CEA_861D << 3;
+
+	/* speaker allocation from EDID */
+	buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
+
+	/* is DisplayPort? */
+	if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
+		buf[5] |= 0x04;
+
+	pos = ELD_FIXED_BYTES;
+
+	if (rev3_or_later) {
+		int sink_info;
+
+		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
+		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+		put_unaligned_le32(sink_info, buf + 8);
+
+		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
+		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+		put_unaligned_le32(sink_info, buf + 12);
+
+		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
+		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+		put_unaligned_le16(sink_info, buf + 16);
+
+		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
+		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+		put_unaligned_le16(sink_info, buf + 18);
+
+		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
+		sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+
+		if (sink_desc_len > ELD_MAX_MNL) {
+			codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
+				   sink_desc_len);
+			sink_desc_len = ELD_MAX_MNL;
+		}
+
+		buf[4] |= sink_desc_len;
+
+		for (i = 0; i < sink_desc_len; i++) {
+			snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
+			buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+		}
+	}
+
+	for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
+		if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
+			continue; /* not handled by ATI/AMD */
+
+		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
+		ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
+
+		if (ati_sad <= 0)
+			continue;
+
+		if (ati_sad & ATI_AUDIODESC_RATES) {
+			/* format is supported, copy SAD as-is */
+			buf[pos++] = (ati_sad & 0x0000ff) >> 0;
+			buf[pos++] = (ati_sad & 0x00ff00) >> 8;
+			buf[pos++] = (ati_sad & 0xff0000) >> 16;
+		}
+
+		if (i == AUDIO_CODING_TYPE_LPCM
+		    && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
+		    && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
+			/* for PCM there is a separate stereo rate mask */
+			buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
+			/* rates from the extra byte */
+			buf[pos++] = (ati_sad & 0xff000000) >> 24;
+			buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
+		}
+	}
+
+	if (pos == ELD_FIXED_BYTES + sink_desc_len) {
+		codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * HDMI VSDB latency format:
+	 * separately for both audio and video:
+	 *  0          field not valid or unknown latency
+	 *  [1..251]   msecs = (x-1)*2  (max 500ms with x = 251 = 0xfb)
+	 *  255        audio/video not supported
+	 *
+	 * HDA latency format:
+	 * single value indicating video latency relative to audio:
+	 *  0          unknown or 0ms
+	 *  [1..250]   msecs = x*2  (max 500ms with x = 250 = 0xfa)
+	 *  [251..255] reserved
+	 */
+	aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
+	if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
+		int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
+		int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
+
+		if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
+		    video_latency_hdmi > audio_latency_hdmi)
+			buf[6] = video_latency_hdmi - audio_latency_hdmi;
+		/* else unknown/invalid or 0ms or video ahead of audio, so use zero */
+	}
+
+	/* SAD count */
+	buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
+
+	/* Baseline ELD block length is 4-byte aligned */
+	pos = round_up(pos, 4);
+
+	/* Baseline ELD length (4-byte header is not counted in) */
+	buf[2] = (pos - 4) / 4;
+
+	*eld_size = pos;
+
+	return 0;
+}
+
+static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+			       int dev_id, unsigned char *buf, int *eld_size)
+{
+	WARN_ON(dev_id != 0);
+	/* call hda_eld.c ATI/AMD-specific function */
+	return get_eld_ati(codec, nid, buf, eld_size,
+			   is_amdhdmi_rev3_or_later(codec));
+}
+
+static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
+					hda_nid_t pin_nid, int dev_id, int ca,
+					int active_channels, int conn_type)
+{
+	WARN_ON(dev_id != 0);
+	snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
+}
+
+static int atihdmi_paired_swap_fc_lfe(int pos)
+{
+	/*
+	 * ATI/AMD have automatic FC/LFE swap built-in
+	 * when in pairwise mapping mode.
+	 */
+
+	switch (pos) {
+	/* see channel_allocations[].speakers[] */
+	case 2: return 3;
+	case 3: return 2;
+	default: return pos;
+	}
+}
+
+static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
+			int ca, int chs, unsigned char *map)
+{
+	struct hdac_cea_channel_speaker_allocation *cap;
+	int i, j;
+
+	/* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
+
+	cap = snd_hdac_get_ch_alloc_from_ca(ca);
+	for (i = 0; i < chs; ++i) {
+		int mask = snd_hdac_chmap_to_spk_mask(map[i]);
+		bool ok = false;
+		bool companion_ok = false;
+
+		if (!mask)
+			continue;
+
+		for (j = 0 + i % 2; j < 8; j += 2) {
+			int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
+
+			if (cap->speakers[chan_idx] == mask) {
+				/* channel is in a supported position */
+				ok = true;
+
+				if (i % 2 == 0 && i + 1 < chs) {
+					/* even channel, check the odd companion */
+					int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
+					int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
+					int comp_mask_act = cap->speakers[comp_chan_idx];
+
+					if (comp_mask_req == comp_mask_act)
+						companion_ok = true;
+					else
+						return -EINVAL;
+				}
+				break;
+			}
+		}
+
+		if (!ok)
+			return -EINVAL;
+
+		if (companion_ok)
+			i++; /* companion channel already checked */
+	}
+
+	return 0;
+}
+
+static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
+		hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
+{
+	struct hda_codec *codec = hdac_to_hda_codec(hdac);
+	int verb;
+	int ati_channel_setup = 0;
+
+	if (hdmi_slot > 7)
+		return -EINVAL;
+
+	if (!has_amd_full_remap_support(codec)) {
+		hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
+
+		/* In case this is an odd slot but without stream channel, do not
+		 * disable the slot since the corresponding even slot could have a
+		 * channel. In case neither have a channel, the slot pair will be
+		 * disabled when this function is called for the even slot.
+		 */
+		if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
+			return 0;
+
+		hdmi_slot -= hdmi_slot % 2;
+
+		if (stream_channel != 0xf)
+			stream_channel -= stream_channel % 2;
+	}
+
+	verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
+
+	/* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
+
+	if (stream_channel != 0xf)
+		ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
+
+	return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
+}
+
+static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
+				hda_nid_t pin_nid, int asp_slot)
+{
+	struct hda_codec *codec = hdac_to_hda_codec(hdac);
+	bool was_odd = false;
+	int ati_asp_slot = asp_slot;
+	int verb;
+	int ati_channel_setup;
+
+	if (asp_slot > 7)
+		return -EINVAL;
+
+	if (!has_amd_full_remap_support(codec)) {
+		ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
+		if (ati_asp_slot % 2 != 0) {
+			ati_asp_slot -= 1;
+			was_odd = true;
+		}
+	}
+
+	verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
+
+	ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
+
+	if (!(ati_channel_setup & ATI_OUT_ENABLE))
+		return 0xf;
+
+	return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
+}
+
+static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
+		struct hdac_chmap *chmap,
+		struct hdac_cea_channel_speaker_allocation *cap,
+		int channels)
+{
+	int c;
+
+	/*
+	 * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
+	 * we need to take that into account (a single channel may take 2
+	 * channel slots if we need to carry a silent channel next to it).
+	 * On Rev3+ AMD codecs this function is not used.
+	 */
+	int chanpairs = 0;
+
+	/* We only produce even-numbered channel count TLVs */
+	if ((channels % 2) != 0)
+		return -1;
+
+	for (c = 0; c < 7; c += 2) {
+		if (cap->speakers[c] || cap->speakers[c+1])
+			chanpairs++;
+	}
+
+	if (chanpairs * 2 != channels)
+		return -1;
+
+	return SNDRV_CTL_TLVT_CHMAP_PAIRED;
+}
+
+static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
+		struct hdac_cea_channel_speaker_allocation *cap,
+		unsigned int *chmap, int channels)
+{
+	/* produce paired maps for pre-rev3 ATI/AMD codecs */
+	int count = 0;
+	int c;
+
+	for (c = 7; c >= 0; c--) {
+		int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
+		int spk = cap->speakers[chan];
+
+		if (!spk) {
+			/* add N/A channel if the companion channel is occupied */
+			if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
+				chmap[count++] = SNDRV_CHMAP_NA;
+
+			continue;
+		}
+
+		chmap[count++] = snd_hdac_spk_to_chmap(spk);
+	}
+
+	WARN_ON(count != channels);
+}
+
+static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+				 int dev_id, bool hbr)
+{
+	int hbr_ctl, hbr_ctl_new;
+
+	WARN_ON(dev_id != 0);
+
+	hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
+	if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
+		if (hbr)
+			hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
+		else
+			hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
+
+		codec_dbg(codec,
+			  "%s: NID=0x%x, %shbr-ctl=0x%x\n",
+			  __func__,
+			  pin_nid,
+			  hbr_ctl == hbr_ctl_new ? "" : "new-",
+			  hbr_ctl_new);
+
+		if (hbr_ctl != hbr_ctl_new)
+			snd_hda_codec_write(codec, pin_nid, 0,
+						ATI_VERB_SET_HBR_CONTROL,
+						hbr_ctl_new);
+
+	} else if (hbr)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+				hda_nid_t pin_nid, int dev_id,
+				u32 stream_tag, int format)
+{
+	if (is_amdhdmi_rev3_or_later(codec)) {
+		int ramp_rate = 180; /* default as per AMD spec */
+		/* disable ramp-up/down for non-pcm as per AMD spec */
+		if (format & AC_FMT_TYPE_NON_PCM)
+			ramp_rate = 0;
+
+		snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
+	}
+
+	return snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+					 stream_tag, format);
+}
+
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx, err;
+
+	err = snd_hda_hdmi_generic_init(codec);
+
+	if (err)
+		return err;
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+		/* make sure downmix information in infoframe is zero */
+		snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
+
+		/* enable channel-wise remap mode if supported */
+		if (has_amd_full_remap_support(codec))
+			snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+					    ATI_VERB_SET_MULTICHANNEL_MODE,
+					    ATI_MULTICHANNEL_MODE_SINGLE);
+	}
+	codec->auto_runtime_pm = 1;
+
+	return 0;
+}
+
+/* map from pin NID to port; port is 0-based */
+/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
+static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
+{
+	return pin_nid / 2 - 1;
+}
+
+/* reverse-map from port to pin NID: see above */
+static int atihdmi_port2pin(struct hda_codec *codec, int port)
+{
+	return port * 2 + 3;
+}
+
+static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
+	.pin2port = atihdmi_pin2port,
+	.pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify,
+	.master_bind = snd_hda_hdmi_acomp_master_bind,
+	.master_unbind = snd_hda_hdmi_acomp_master_unbind,
+};
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	struct hdmi_spec_per_cvt *per_cvt;
+	int err, cvt_idx;
+
+	err = patch_generic_hdmi(codec);
+
+	if (err)
+		return err;
+
+	codec->patch_ops.init = atihdmi_init;
+
+	spec = codec->spec;
+
+	spec->static_pcm_mapping = true;
+
+	spec->ops.pin_get_eld = atihdmi_pin_get_eld;
+	spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
+	spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
+	spec->ops.setup_stream = atihdmi_setup_stream;
+
+	spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
+	spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
+
+	if (!has_amd_full_remap_support(codec)) {
+		/* override to ATI/AMD-specific versions with pairwise mapping */
+		spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+			atihdmi_paired_chmap_cea_alloc_validate_get_type;
+		spec->chmap.ops.cea_alloc_to_tlv_chmap =
+				atihdmi_paired_cea_alloc_to_tlv_chmap;
+		spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
+	}
+
+	/* ATI/AMD converters do not advertise all of their capabilities */
+	for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+		per_cvt = get_cvt(spec, cvt_idx);
+		per_cvt->channels_max = max(per_cvt->channels_max, 8u);
+		per_cvt->rates |= SUPPORTED_RATES;
+		per_cvt->formats |= SUPPORTED_FORMATS;
+		per_cvt->maxbps = max(per_cvt->maxbps, 24u);
+	}
+
+	spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
+
+	/* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
+	 * the link-down as is.  Tell the core to allow it.
+	 */
+	codec->link_down_at_suspend = 1;
+
+	snd_hda_hdmi_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_atihdmi[] = {
+HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI",	patch_atihdmi),
+HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI",	patch_atihdmi),
+HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI",	patch_atihdmi),
+HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",	patch_atihdmi),
+{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD/ATI HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver atihdmi_driver = {
+	.id = snd_hda_id_atihdmi,
+};
+
+module_hda_codec_driver(atihdmi_driver);
diff --git a/sound/hda/codecs/hdmi/eld.c b/sound/hda/codecs/hdmi/eld.c
index d3e87b9c1a4f..1464fd1c675b 100644
--- a/sound/hda/codecs/hdmi/eld.c
+++ b/sound/hda/codecs/hdmi/eld.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
-#include <linux/unaligned.h>
 #include <sound/hda_chmap.h>
 #include <sound/hda_codec.h>
 #include "hda_local.h"
@@ -229,174 +228,3 @@ void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
 	hinfo->maxbps = min(hinfo->maxbps, maxbps);
 	hinfo->channels_max = min(hinfo->channels_max, channels_max);
 }
-
-
-/* ATI/AMD specific stuff (ELD emulation) */
-
-#define ATI_VERB_SET_AUDIO_DESCRIPTOR	0x776
-#define ATI_VERB_SET_SINK_INFO_INDEX	0x780
-#define ATI_VERB_GET_SPEAKER_ALLOCATION	0xf70
-#define ATI_VERB_GET_AUDIO_DESCRIPTOR	0xf76
-#define ATI_VERB_GET_AUDIO_VIDEO_DELAY	0xf7b
-#define ATI_VERB_GET_SINK_INFO_INDEX	0xf80
-#define ATI_VERB_GET_SINK_INFO_DATA	0xf81
-
-#define ATI_SPKALLOC_SPKALLOC		0x007f
-#define ATI_SPKALLOC_TYPE_HDMI		0x0100
-#define ATI_SPKALLOC_TYPE_DISPLAYPORT	0x0200
-
-/* first three bytes are just standard SAD */
-#define ATI_AUDIODESC_CHANNELS		0x00000007
-#define ATI_AUDIODESC_RATES		0x0000ff00
-#define ATI_AUDIODESC_LPCM_STEREO_RATES	0xff000000
-
-/* in standard HDMI VSDB format */
-#define ATI_DELAY_VIDEO_LATENCY		0x000000ff
-#define ATI_DELAY_AUDIO_LATENCY		0x0000ff00
-
-enum ati_sink_info_idx {
-	ATI_INFO_IDX_MANUFACTURER_ID	= 0,
-	ATI_INFO_IDX_PRODUCT_ID		= 1,
-	ATI_INFO_IDX_SINK_DESC_LEN	= 2,
-	ATI_INFO_IDX_PORT_ID_LOW	= 3,
-	ATI_INFO_IDX_PORT_ID_HIGH	= 4,
-	ATI_INFO_IDX_SINK_DESC_FIRST	= 5,
-	ATI_INFO_IDX_SINK_DESC_LAST	= 22, /* max len 18 bytes */
-};
-
-int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
-			 unsigned char *buf, int *eld_size, bool rev3_or_later)
-{
-	int spkalloc, ati_sad, aud_synch;
-	int sink_desc_len = 0;
-	int pos, i;
-
-	/* ATI/AMD does not have ELD, emulate it */
-
-	spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
-
-	if (spkalloc <= 0) {
-		codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
-		return -EINVAL;
-	}
-
-	memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
-
-	/* version */
-	buf[0] = ELD_VER_CEA_861D << 3;
-
-	/* speaker allocation from EDID */
-	buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
-
-	/* is DisplayPort? */
-	if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
-		buf[5] |= 0x04;
-
-	pos = ELD_FIXED_BYTES;
-
-	if (rev3_or_later) {
-		int sink_info;
-
-		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
-		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-		put_unaligned_le32(sink_info, buf + 8);
-
-		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
-		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-		put_unaligned_le32(sink_info, buf + 12);
-
-		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
-		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-		put_unaligned_le16(sink_info, buf + 16);
-
-		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
-		sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-		put_unaligned_le16(sink_info, buf + 18);
-
-		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
-		sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-
-		if (sink_desc_len > ELD_MAX_MNL) {
-			codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
-				   sink_desc_len);
-			sink_desc_len = ELD_MAX_MNL;
-		}
-
-		buf[4] |= sink_desc_len;
-
-		for (i = 0; i < sink_desc_len; i++) {
-			snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
-			buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-		}
-	}
-
-	for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
-		if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
-			continue; /* not handled by ATI/AMD */
-
-		snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
-		ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
-
-		if (ati_sad <= 0)
-			continue;
-
-		if (ati_sad & ATI_AUDIODESC_RATES) {
-			/* format is supported, copy SAD as-is */
-			buf[pos++] = (ati_sad & 0x0000ff) >> 0;
-			buf[pos++] = (ati_sad & 0x00ff00) >> 8;
-			buf[pos++] = (ati_sad & 0xff0000) >> 16;
-		}
-
-		if (i == AUDIO_CODING_TYPE_LPCM
-		    && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
-		    && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
-			/* for PCM there is a separate stereo rate mask */
-			buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
-			/* rates from the extra byte */
-			buf[pos++] = (ati_sad & 0xff000000) >> 24;
-			buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
-		}
-	}
-
-	if (pos == ELD_FIXED_BYTES + sink_desc_len) {
-		codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * HDMI VSDB latency format:
-	 * separately for both audio and video:
-	 *  0          field not valid or unknown latency
-	 *  [1..251]   msecs = (x-1)*2  (max 500ms with x = 251 = 0xfb)
-	 *  255        audio/video not supported
-	 *
-	 * HDA latency format:
-	 * single value indicating video latency relative to audio:
-	 *  0          unknown or 0ms
-	 *  [1..250]   msecs = x*2  (max 500ms with x = 250 = 0xfa)
-	 *  [251..255] reserved
-	 */
-	aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
-	if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
-		int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
-		int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
-
-		if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
-		    video_latency_hdmi > audio_latency_hdmi)
-			buf[6] = video_latency_hdmi - audio_latency_hdmi;
-		/* else unknown/invalid or 0ms or video ahead of audio, so use zero */
-	}
-
-	/* SAD count */
-	buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
-
-	/* Baseline ELD block length is 4-byte aligned */
-	pos = round_up(pos, 4);
-
-	/* Baseline ELD length (4-byte header is not counted in) */
-	buf[2] = (pos - 4) / 4;
-
-	*eld_size = pos;
-
-	return 0;
-}
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
index 3811eb1dc998..85aaa454072f 100644
--- a/sound/hda/codecs/hdmi/hdmi.c
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -33,6 +33,7 @@
 #include "hda_local.h"
 #include "hda_jack.h"
 #include "hda_controller.h"
+#include "hdmi_local.h"
 
 static bool static_hdmi_pcm;
 module_param(static_hdmi_pcm, bool, 0644);
@@ -42,214 +43,12 @@ static bool enable_acomp = true;
 module_param(enable_acomp, bool, 0444);
 MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
 
-static bool enable_silent_stream =
-IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
-module_param(enable_silent_stream, bool, 0644);
-MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
-
 static bool enable_all_pins;
 module_param(enable_all_pins, bool, 0444);
 MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins");
 
-struct hdmi_spec_per_cvt {
-	hda_nid_t cvt_nid;
-	bool assigned;		/* the stream has been assigned */
-	bool silent_stream;	/* silent stream activated */
-	unsigned int channels_min;
-	unsigned int channels_max;
-	u32 rates;
-	u64 formats;
-	unsigned int maxbps;
-};
-
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS	32
-
-struct hdmi_spec_per_pin {
-	hda_nid_t pin_nid;
-	int dev_id;
-	/* pin idx, different device entries on the same pin use the same idx */
-	int pin_nid_idx;
-	int num_mux_nids;
-	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
-	int mux_idx;
-	hda_nid_t cvt_nid;
-
-	struct hda_codec *codec;
-	struct hdmi_eld sink_eld;
-	struct mutex lock;
-	struct delayed_work work;
-	struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
-	int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
-	int prev_pcm_idx; /* previously assigned pcm index */
-	int repoll_count;
-	bool setup; /* the stream has been set up by prepare callback */
-	bool silent_stream;
-	int channels; /* current number of channels */
-	bool non_pcm;
-	bool chmap_set;		/* channel-map override by ALSA API? */
-	unsigned char chmap[8]; /* ALSA API channel-map */
-#ifdef CONFIG_SND_PROC_FS
-	struct snd_info_entry *proc_entry;
-#endif
-};
-
-/* operations used by generic code that can be overridden by patches */
-struct hdmi_ops {
-	int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
-			   int dev_id, unsigned char *buf, int *eld_size);
-
-	void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
-				    int dev_id,
-				    int ca, int active_channels, int conn_type);
-
-	/* enable/disable HBR (HD passthrough) */
-	int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
-			     int dev_id, bool hbr);
-
-	int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
-			    hda_nid_t pin_nid, int dev_id, u32 stream_tag,
-			    int format);
-
-	void (*pin_cvt_fixup)(struct hda_codec *codec,
-			      struct hdmi_spec_per_pin *per_pin,
-			      hda_nid_t cvt_nid);
-};
-
-struct hdmi_pcm {
-	struct hda_pcm *pcm;
-	struct snd_jack *jack;
-	struct snd_kcontrol *eld_ctl;
-};
-
-enum {
-	SILENT_STREAM_OFF = 0,
-	SILENT_STREAM_KAE,	/* use standard HDA Keep-Alive */
-	SILENT_STREAM_I915,	/* Intel i915 extension */
-};
-
-struct hdmi_spec {
-	struct hda_codec *codec;
-	int num_cvts;
-	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
-	hda_nid_t cvt_nids[4]; /* only for haswell fix */
-
-	/*
-	 * num_pins is the number of virtual pins
-	 * for example, there are 3 pins, and each pin
-	 * has 4 device entries, then the num_pins is 12
-	 */
-	int num_pins;
-	/*
-	 * num_nids is the number of real pins
-	 * In the above example, num_nids is 3
-	 */
-	int num_nids;
-	/*
-	 * dev_num is the number of device entries
-	 * on each pin.
-	 * In the above example, dev_num is 4
-	 */
-	int dev_num;
-	struct snd_array pins; /* struct hdmi_spec_per_pin */
-	struct hdmi_pcm pcm_rec[8];
-	struct mutex pcm_lock;
-	struct mutex bind_lock; /* for audio component binding */
-	/* pcm_bitmap means which pcms have been assigned to pins*/
-	unsigned long pcm_bitmap;
-	int pcm_used;	/* counter of pcm_rec[] */
-	/* bitmap shows whether the pcm is opened in user space
-	 * bit 0 means the first playback PCM (PCM3);
-	 * bit 1 means the second playback PCM, and so on.
-	 */
-	unsigned long pcm_in_use;
-
-	struct hdmi_eld temp_eld;
-	struct hdmi_ops ops;
-
-	bool dyn_pin_out;
-	bool static_pcm_mapping;
-	/* hdmi interrupt trigger control flag for Nvidia codec */
-	bool hdmi_intr_trig_ctrl;
-	bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
-
-	bool intel_hsw_fixup;	/* apply Intel platform-specific fixups */
-	/*
-	 * Non-generic VIA/NVIDIA specific
-	 */
-	struct hda_multi_out multiout;
-	struct hda_pcm_stream pcm_playback;
-
-	bool use_acomp_notifier; /* use eld_notify callback for hotplug */
-	bool acomp_registered; /* audio component registered in this driver */
-	bool force_connect; /* force connectivity */
-	struct drm_audio_component_audio_ops drm_audio_ops;
-	int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */
-
-	struct hdac_chmap chmap;
-	hda_nid_t vendor_nid;
-	const int *port_map;
-	int port_num;
-	int silent_stream_type;
-};
-
-#ifdef CONFIG_SND_HDA_COMPONENT
-static inline bool codec_has_acomp(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	return spec->use_acomp_notifier;
-}
-#else
-#define codec_has_acomp(codec)	false
-#endif
-
-struct hdmi_audio_infoframe {
-	u8 type; /* 0x84 */
-	u8 ver;  /* 0x01 */
-	u8 len;  /* 0x0a */
-
-	u8 checksum;
-
-	u8 CC02_CT47;	/* CC in bits 0:2, CT in 4:7 */
-	u8 SS01_SF24;
-	u8 CXT04;
-	u8 CA;
-	u8 LFEPBL01_LSV36_DM_INH7;
-};
-
-struct dp_audio_infoframe {
-	u8 type; /* 0x84 */
-	u8 len;  /* 0x1b */
-	u8 ver;  /* 0x11 << 2 */
-
-	u8 CC02_CT47;	/* match with HDMI infoframe from this on */
-	u8 SS01_SF24;
-	u8 CXT04;
-	u8 CA;
-	u8 LFEPBL01_LSV36_DM_INH7;
-};
-
-union audio_infoframe {
-	struct hdmi_audio_infoframe hdmi;
-	struct dp_audio_infoframe dp;
-	DECLARE_FLEX_ARRAY(u8, bytes);
-};
-
-/*
- * HDMI routines
- */
-
-#define get_pin(spec, idx) \
-	((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
-#define get_cvt(spec, idx) \
-	((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
-/* obtain hdmi_pcm object assigned to idx */
-#define get_hdmi_pcm(spec, idx)	(&(spec)->pcm_rec[idx])
-/* obtain hda_pcm object assigned to idx */
-#define get_pcm_rec(spec, idx)	(get_hdmi_pcm(spec, idx)->pcm)
-
-static int pin_id_to_pin_index(struct hda_codec *codec,
-			       hda_nid_t pin_nid, int dev_id)
+int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec,
+				     hda_nid_t pin_nid, int dev_id)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
@@ -272,6 +71,7 @@ static int pin_id_to_pin_index(struct hda_codec *codec,
 	codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid);
 	return -EINVAL;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_pin_id_to_pin_index, "SND_HDA_CODEC_HDMI");
 
 static int hinfo_to_pcm_index(struct hda_codec *codec,
 			struct hda_pcm_stream *hinfo)
@@ -735,9 +535,9 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
 	}
 }
 
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
-				       struct hdmi_spec_per_pin *per_pin,
-				       bool non_pcm)
+void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec,
+					struct hdmi_spec_per_pin *per_pin,
+					bool non_pcm)
 {
 	struct hdmi_spec *spec = codec->spec;
 	struct hdac_chmap *chmap = &spec->chmap;
@@ -783,6 +583,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
 
 	per_pin->non_pcm = non_pcm;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_audio_infoframe, "SND_HDA_CODEC_HDMI");
 
 /*
  * Unsolicited events
@@ -790,8 +591,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
 
 static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 
-static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
-				      int dev_id)
+void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec,
+					    hda_nid_t nid, int dev_id)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
@@ -802,6 +603,8 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
 	hdmi_present_sense(get_pin(spec, pin_idx), 1);
 	mutex_unlock(&spec->pcm_lock);
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_check_presence_and_report,
+		     "SND_HDA_CODEC_HDMI");
 
 static void jack_callback(struct hda_codec *codec,
 			  struct hda_jack_callback *jack)
@@ -810,7 +613,7 @@ static void jack_callback(struct hda_codec *codec,
 	if (codec_has_acomp(codec))
 		return;
 
-	check_presence_and_report(codec, jack->nid, jack->dev_id);
+	snd_hda_hdmi_check_presence_and_report(codec, jack->nid, jack->dev_id);
 }
 
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
@@ -823,7 +626,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
 		codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA),
 		!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 
-	check_presence_and_report(codec, jack->nid, jack->dev_id);
+	snd_hda_hdmi_check_presence_and_report(codec, jack->nid, jack->dev_id);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -850,8 +653,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 	}
 }
 
-
-static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
+void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res)
 {
 	int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
 	int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
@@ -879,27 +681,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 	else
 		hdmi_non_intrinsic_event(codec, res);
 }
-
-static void haswell_verify_D0(struct hda_codec *codec,
-		hda_nid_t cvt_nid, hda_nid_t nid)
-{
-	int pwr;
-
-	/* For Haswell, the converter 1/2 may keep in D3 state after bootup,
-	 * thus pins could only choose converter 0 for use. Make sure the
-	 * converters are in correct power state */
-	if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
-		snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-	if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
-				    AC_PWRST_D0);
-		msleep(40);
-		pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
-		pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
-		codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
-	}
-}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_unsol_event, "SND_HDA_CODEC_HDMI");
 
 /*
  * Callbacks
@@ -944,7 +726,8 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
 	return 0;
 }
 
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+int snd_hda_hdmi_setup_stream(struct hda_codec *codec,
+			      hda_nid_t cvt_nid,
 			      hda_nid_t pin_nid, int dev_id,
 			      u32 stream_tag, int format)
 {
@@ -983,6 +766,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
 	snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_stream, "SND_HDA_CODEC_HDMI");
 
 /* Try to find an available converter
  * If pin_idx is less then zero, just try to find an available converter.
@@ -1046,137 +830,6 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
 	return 0;
 }
 
-/* Assure the pin select the right convetor */
-static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
-			struct hdmi_spec_per_pin *per_pin)
-{
-	hda_nid_t pin_nid = per_pin->pin_nid;
-	int mux_idx, curr;
-
-	mux_idx = per_pin->mux_idx;
-	curr = snd_hda_codec_read(codec, pin_nid, 0,
-					  AC_VERB_GET_CONNECT_SEL, 0);
-	if (curr != mux_idx)
-		snd_hda_codec_write_cache(codec, pin_nid, 0,
-					    AC_VERB_SET_CONNECT_SEL,
-					    mux_idx);
-}
-
-/* get the mux index for the converter of the pins
- * converter's mux index is the same for all pins on Intel platform
- */
-static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
-			hda_nid_t cvt_nid)
-{
-	int i;
-
-	for (i = 0; i < spec->num_cvts; i++)
-		if (spec->cvt_nids[i] == cvt_nid)
-			return i;
-	return -EINVAL;
-}
-
-/* Intel HDMI workaround to fix audio routing issue:
- * For some Intel display codecs, pins share the same connection list.
- * So a conveter can be selected by multiple pins and playback on any of these
- * pins will generate sound on the external display, because audio flows from
- * the same converter to the display pipeline. Also muting one pin may make
- * other pins have no sound output.
- * So this function assures that an assigned converter for a pin is not selected
- * by any other pins.
- */
-static void intel_not_share_assigned_cvt(struct hda_codec *codec,
-					 hda_nid_t pin_nid,
-					 int dev_id, int mux_idx)
-{
-	struct hdmi_spec *spec = codec->spec;
-	hda_nid_t nid;
-	int cvt_idx, curr;
-	struct hdmi_spec_per_cvt *per_cvt;
-	struct hdmi_spec_per_pin *per_pin;
-	int pin_idx;
-
-	/* configure the pins connections */
-	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		int dev_id_saved;
-		int dev_num;
-
-		per_pin = get_pin(spec, pin_idx);
-		/*
-		 * pin not connected to monitor
-		 * no need to operate on it
-		 */
-		if (!per_pin->pcm)
-			continue;
-
-		if ((per_pin->pin_nid == pin_nid) &&
-			(per_pin->dev_id == dev_id))
-			continue;
-
-		/*
-		 * if per_pin->dev_id >= dev_num,
-		 * snd_hda_get_dev_select() will fail,
-		 * and the following operation is unpredictable.
-		 * So skip this situation.
-		 */
-		dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
-		if (per_pin->dev_id >= dev_num)
-			continue;
-
-		nid = per_pin->pin_nid;
-
-		/*
-		 * Calling this function should not impact
-		 * on the device entry selection
-		 * So let's save the dev id for each pin,
-		 * and restore it when return
-		 */
-		dev_id_saved = snd_hda_get_dev_select(codec, nid);
-		snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
-		curr = snd_hda_codec_read(codec, nid, 0,
-					  AC_VERB_GET_CONNECT_SEL, 0);
-		if (curr != mux_idx) {
-			snd_hda_set_dev_select(codec, nid, dev_id_saved);
-			continue;
-		}
-
-
-		/* choose an unassigned converter. The conveters in the
-		 * connection list are in the same order as in the codec.
-		 */
-		for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-			per_cvt = get_cvt(spec, cvt_idx);
-			if (!per_cvt->assigned) {
-				codec_dbg(codec,
-					  "choose cvt %d for pin NID 0x%x\n",
-					  cvt_idx, nid);
-				snd_hda_codec_write_cache(codec, nid, 0,
-					    AC_VERB_SET_CONNECT_SEL,
-					    cvt_idx);
-				break;
-			}
-		}
-		snd_hda_set_dev_select(codec, nid, dev_id_saved);
-	}
-}
-
-/* A wrapper of intel_not_share_asigned_cvt() */
-static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
-			hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
-{
-	int mux_idx;
-	struct hdmi_spec *spec = codec->spec;
-
-	/* On Intel platform, the mapping of converter nid to
-	 * mux index of the pins are always the same.
-	 * The pin nid may be 0, this means all pins will not
-	 * share the converter.
-	 */
-	mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
-	if (mux_idx >= 0)
-		intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
-}
-
 /* skeleton caller of pin_cvt_fixup ops */
 static void pin_cvt_fixup(struct hda_codec *codec,
 			  struct hdmi_spec_per_pin *per_pin,
@@ -1466,7 +1119,7 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
 	per_pin->setup = true;
 	per_pin->mux_idx = mux_idx;
 
-	hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+	snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
 }
 
 static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
@@ -1583,7 +1236,7 @@ static void update_eld(struct hda_codec *codec,
 	 */
 	if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
 		pin_cvt_fixup(codec, per_pin, 0);
-		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+		snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
 	}
 
 	if (eld_changed && pcm_idx >= 0)
@@ -1653,57 +1306,12 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
 	snd_hda_power_down_pm(codec);
 }
 
-#define I915_SILENT_RATE		48000
-#define I915_SILENT_CHANNELS		2
-#define I915_SILENT_FORMAT_BITS	16
-#define I915_SILENT_FMT_MASK		0xf
-
-static void silent_stream_enable_i915(struct hda_codec *codec,
-				      struct hdmi_spec_per_pin *per_pin)
-{
-	unsigned int format;
-
-	snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
-				 per_pin->dev_id, I915_SILENT_RATE);
-
-	/* trigger silent stream generation in hw */
-	format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS,
-					I915_SILENT_RATE);
-	snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
-				   I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
-	usleep_range(100, 200);
-	snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
-
-	per_pin->channels = I915_SILENT_CHANNELS;
-	hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
-}
-
-static void silent_stream_set_kae(struct hda_codec *codec,
-				  struct hdmi_spec_per_pin *per_pin,
-				  bool enable)
-{
-	unsigned int param;
-
-	codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
-
-	param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
-	param = (param >> 16) & 0xff;
-
-	if (enable)
-		param |= AC_DIG3_KAE;
-	else
-		param &= ~AC_DIG3_KAE;
-
-	snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
-}
-
 static void silent_stream_enable(struct hda_codec *codec,
 				 struct hdmi_spec_per_pin *per_pin)
 {
 	struct hdmi_spec *spec = codec->spec;
 	struct hdmi_spec_per_cvt *per_cvt;
 	int cvt_idx, pin_idx, err;
-	int keep_power = 0;
 
 	/*
 	 * Power-up will call hdmi_present_sense, so the PM calls
@@ -1749,24 +1357,12 @@ static void silent_stream_enable(struct hda_codec *codec,
 	/* configure unused pins to choose other converters */
 	pin_cvt_fixup(codec, per_pin, 0);
 
-	switch (spec->silent_stream_type) {
-	case SILENT_STREAM_KAE:
-		silent_stream_enable_i915(codec, per_pin);
-		silent_stream_set_kae(codec, per_pin, true);
-		break;
-	case SILENT_STREAM_I915:
-		silent_stream_enable_i915(codec, per_pin);
-		keep_power = 1;
-		break;
-	default:
-		break;
-	}
+	spec->ops.silent_stream(codec, per_pin, true);
 
  unlock_out:
 	mutex_unlock(&per_pin->lock);
 
-	if (err || !keep_power)
-		snd_hda_power_down_pm(codec);
+	snd_hda_power_down_pm(codec);
 }
 
 static void silent_stream_disable(struct hda_codec *codec,
@@ -1798,12 +1394,7 @@ static void silent_stream_disable(struct hda_codec *codec,
 		per_cvt->silent_stream = false;
 	}
 
-	if (spec->silent_stream_type == SILENT_STREAM_I915) {
-		/* release ref taken in silent_stream_enable() */
-		snd_hda_power_down_pm(codec);
-	} else if (spec->silent_stream_type == SILENT_STREAM_KAE) {
-		silent_stream_set_kae(codec, per_pin, false);
-	}
+	spec->ops.silent_stream(codec, per_pin, false);
 
 	per_pin->cvt_nid = 0;
 	per_pin->silent_stream = false;
@@ -2003,7 +1594,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
 	{}
 };
 
-static int hdmi_parse_codec(struct hda_codec *codec)
+int snd_hda_hdmi_parse_codec(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	hda_nid_t start_nid;
@@ -2056,6 +1647,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_parse_codec, "SND_HDA_CODEC_HDMI");
 
 /*
  */
@@ -2082,11 +1674,11 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
  * HDMI callbacks
  */
 
-static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-					   struct hda_codec *codec,
-					   unsigned int stream_tag,
-					   unsigned int format,
-					   struct snd_pcm_substream *substream)
+int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     struct snd_pcm_substream *substream)
 {
 	hda_nid_t cvt_nid = hinfo->nid;
 	struct hdmi_spec *spec = codec->spec;
@@ -2140,7 +1732,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 				    stripe);
 	}
 
-	hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+	snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
 	mutex_unlock(&per_pin->lock);
 	if (spec->dyn_pin_out) {
 		snd_hda_set_dev_select(codec, per_pin->pin_nid,
@@ -2159,14 +1751,16 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	mutex_unlock(&spec->pcm_lock);
 	return err;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_prepare, "SND_HDA_CODEC_HDMI");
 
-static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-					     struct hda_codec *codec,
-					     struct snd_pcm_substream *substream)
+int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream)
 {
 	snd_hda_codec_cleanup_stream(codec, hinfo->nid);
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_pcm_cleanup, "SND_HDA_CODEC_HDMI");
 
 static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
 			  struct hda_codec *codec,
@@ -2237,8 +1831,8 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
 static const struct hda_pcm_ops generic_ops = {
 	.open = hdmi_pcm_open,
 	.close = hdmi_pcm_close,
-	.prepare = generic_hdmi_playback_pcm_prepare,
-	.cleanup = generic_hdmi_playback_pcm_cleanup,
+	.prepare = snd_hda_hdmi_generic_pcm_prepare,
+	.cleanup = snd_hda_hdmi_generic_pcm_cleanup,
 };
 
 static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
@@ -2280,7 +1874,7 @@ static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
 	per_pin->chmap_set = true;
 	memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
 	if (prepared)
-		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+		snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
 	mutex_unlock(&per_pin->lock);
 }
 
@@ -2293,7 +1887,7 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
 	return per_pin ? true:false;
 }
 
-static int generic_hdmi_build_pcms(struct hda_codec *codec)
+int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int idx, pcm_num;
@@ -2332,6 +1926,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_build_pcms, "SND_HDA_CODEC_HDMI");
 
 static void free_hdmi_jack_priv(struct snd_jack *jack)
 {
@@ -2362,7 +1957,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
 	return 0;
 }
 
-static int generic_hdmi_build_controls(struct hda_codec *codec)
+int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int dev, err;
@@ -2425,8 +2020,9 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_build_controls, "SND_HDA_CODEC_HDMI");
 
-static int generic_hdmi_init_per_pins(struct hda_codec *codec)
+int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
@@ -2441,8 +2037,9 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
 	}
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init_per_pins, "SND_HDA_CODEC_HDMI");
 
-static int generic_hdmi_init(struct hda_codec *codec)
+int snd_hda_hdmi_generic_init(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
@@ -2463,6 +2060,7 @@ static int generic_hdmi_init(struct hda_codec *codec)
 	mutex_unlock(&spec->bind_lock);
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_init, "SND_HDA_CODEC_HDMI");
 
 static void hdmi_array_init(struct hdmi_spec *spec, int nums)
 {
@@ -2476,7 +2074,7 @@ static void hdmi_array_free(struct hdmi_spec *spec)
 	snd_array_free(&spec->cvts);
 }
 
-static void generic_spec_free(struct hda_codec *codec)
+void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 
@@ -2487,8 +2085,9 @@ static void generic_spec_free(struct hda_codec *codec)
 	}
 	codec->dp_mst = false;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_spec_free, "SND_HDA_CODEC_HDMI");
 
-static void generic_hdmi_free(struct hda_codec *codec)
+void snd_hda_hdmi_generic_free(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx, pcm_idx;
@@ -2512,10 +2111,11 @@ static void generic_hdmi_free(struct hda_codec *codec)
 		snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack);
 	}
 
-	generic_spec_free(codec);
+	snd_hda_hdmi_generic_spec_free(codec);
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_free, "SND_HDA_CODEC_HDMI");
 
-static int generic_hdmi_suspend(struct hda_codec *codec)
+int snd_hda_hdmi_generic_suspend(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
@@ -2526,8 +2126,9 @@ static int generic_hdmi_suspend(struct hda_codec *codec)
 	}
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_suspend, "SND_HDA_CODEC_HDMI");
 
-static int generic_hdmi_resume(struct hda_codec *codec)
+int snd_hda_hdmi_generic_resume(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
@@ -2541,26 +2142,27 @@ static int generic_hdmi_resume(struct hda_codec *codec)
 	}
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_resume, "SND_HDA_CODEC_HDMI");
 
 static const struct hda_codec_ops generic_hdmi_patch_ops = {
-	.init			= generic_hdmi_init,
-	.free			= generic_hdmi_free,
-	.build_pcms		= generic_hdmi_build_pcms,
-	.build_controls		= generic_hdmi_build_controls,
-	.unsol_event		= hdmi_unsol_event,
-	.suspend		= generic_hdmi_suspend,
-	.resume			= generic_hdmi_resume,
+	.init			= snd_hda_hdmi_generic_init,
+	.free			= snd_hda_hdmi_generic_free,
+	.build_pcms		= snd_hda_hdmi_generic_build_pcms,
+	.build_controls		= snd_hda_hdmi_generic_build_controls,
+	.unsol_event		= snd_hda_hdmi_generic_unsol_event,
+	.suspend		= snd_hda_hdmi_generic_suspend,
+	.resume			= snd_hda_hdmi_generic_resume,
 };
 
 static const struct hdmi_ops generic_standard_hdmi_ops = {
 	.pin_get_eld				= hdmi_pin_get_eld,
 	.pin_setup_infoframe			= hdmi_pin_setup_infoframe,
 	.pin_hbr_setup				= hdmi_pin_hbr_setup,
-	.setup_stream				= hdmi_setup_stream,
+	.setup_stream				= snd_hda_hdmi_setup_stream,
 };
 
 /* allocate codec->spec and assign/initialize generic parser ops */
-static int alloc_generic_hdmi(struct hda_codec *codec)
+int snd_hda_hdmi_generic_alloc(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
 
@@ -2587,25 +2189,27 @@ static int alloc_generic_hdmi(struct hda_codec *codec)
 
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_alloc, "SND_HDA_CODEC_HDMI");
 
 /* generic HDMI parser */
-static int patch_generic_hdmi(struct hda_codec *codec)
+int patch_generic_hdmi(struct hda_codec *codec)
 {
 	int err;
 
-	err = alloc_generic_hdmi(codec);
+	err = snd_hda_hdmi_generic_alloc(codec);
 	if (err < 0)
 		return err;
 
-	err = hdmi_parse_codec(codec);
+	err = snd_hda_hdmi_parse_codec(codec);
 	if (err < 0) {
-		generic_spec_free(codec);
+		snd_hda_hdmi_generic_spec_free(codec);
 		return err;
 	}
 
-	generic_hdmi_init_per_pins(codec);
+	snd_hda_hdmi_generic_init_per_pins(codec);
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(patch_generic_hdmi, "SND_HDA_CODEC_HDMI");
 
 /*
  * generic audio component binding
@@ -2650,18 +2254,20 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
 }
 
 /* enable / disable the notifier via master bind / unbind */
-static int generic_acomp_master_bind(struct device *dev,
-				     struct drm_audio_component *acomp)
+int snd_hda_hdmi_acomp_master_bind(struct device *dev,
+				   struct drm_audio_component *acomp)
 {
 	generic_acomp_notifier_set(acomp, true);
 	return 0;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_master_bind, "SND_HDA_CODEC_HDMI");
 
-static void generic_acomp_master_unbind(struct device *dev,
-					struct drm_audio_component *acomp)
+void snd_hda_hdmi_acomp_master_unbind(struct device *dev,
+				      struct drm_audio_component *acomp)
 {
 	generic_acomp_notifier_set(acomp, false);
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_master_unbind, "SND_HDA_CODEC_HDMI");
 
 /* check whether both HD-audio and DRM PCI devices belong to the same bus */
 static int match_bound_vga(struct device *dev, int subtype, void *data)
@@ -2677,7 +2283,7 @@ static int match_bound_vga(struct device *dev, int subtype, void *data)
 }
 
 /* audio component notifier for AMD/Nvidia HDMI codecs */
-static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
+void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
 {
 	struct hda_codec *codec = audio_ptr;
 	struct hdmi_spec *spec = codec->spec;
@@ -2693,12 +2299,13 @@ static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
 	if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
 		return;
 
-	check_presence_and_report(codec, pin_nid, dev_id);
+	snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id);
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_pin_eld_notify, "SND_HDA_CODEC_HDMI");
 
 /* set up the private drm_audio_ops from the template */
-static void setup_drm_audio_ops(struct hda_codec *codec,
-				const struct drm_audio_component_audio_ops *ops)
+void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec,
+				      const struct drm_audio_component_audio_ops *ops)
 {
 	struct hdmi_spec *spec = codec->spec;
 
@@ -2713,11 +2320,12 @@ static void setup_drm_audio_ops(struct hda_codec *codec,
 	spec->drm_audio_ops.master_bind = ops->master_bind;
 	spec->drm_audio_ops.master_unbind = ops->master_unbind;
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_setup_drm_audio_ops, "SND_HDA_CODEC_HDMI");
 
 /* initialize the generic HDMI audio component */
-static void generic_acomp_init(struct hda_codec *codec,
-			       const struct drm_audio_component_audio_ops *ops,
-			       int (*port2pin)(struct hda_codec *, int))
+void snd_hda_hdmi_acomp_init(struct hda_codec *codec,
+			     const struct drm_audio_component_audio_ops *ops,
+			     int (*port2pin)(struct hda_codec *, int))
 {
 	struct hdmi_spec *spec = codec->spec;
 
@@ -2727,1767 +2335,17 @@ static void generic_acomp_init(struct hda_codec *codec,
 	}
 
 	spec->port2pin = port2pin;
-	setup_drm_audio_ops(codec, ops);
+	snd_hda_hdmi_setup_drm_audio_ops(codec, ops);
 	if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
 				 match_bound_vga, 0)) {
 		spec->acomp_registered = true;
 	}
 }
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_init, "SND_HDA_CODEC_HDMI");
 
 /*
- * Intel codec parsers and helpers
  */
 
-#define INTEL_GET_VENDOR_VERB	0xf81
-#define INTEL_SET_VENDOR_VERB	0x781
-#define INTEL_EN_DP12		0x02	/* enable DP 1.2 features */
-#define INTEL_EN_ALL_PIN_CVTS	0x01	/* enable 2nd & 3rd pins and convertors */
-
-static void intel_haswell_enable_all_pins(struct hda_codec *codec,
-					  bool update_tree)
-{
-	unsigned int vendor_param;
-	struct hdmi_spec *spec = codec->spec;
-
-	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
-				INTEL_GET_VENDOR_VERB, 0);
-	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
-		return;
-
-	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
-	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
-				INTEL_SET_VENDOR_VERB, vendor_param);
-	if (vendor_param == -1)
-		return;
-
-	if (update_tree)
-		snd_hda_codec_update_widgets(codec);
-}
-
-static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
-{
-	unsigned int vendor_param;
-	struct hdmi_spec *spec = codec->spec;
-
-	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
-				INTEL_GET_VENDOR_VERB, 0);
-	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
-		return;
-
-	/* enable DP1.2 mode */
-	vendor_param |= INTEL_EN_DP12;
-	snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
-	snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
-				INTEL_SET_VENDOR_VERB, vendor_param);
-}
-
-/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
- * Otherwise you may get severe h/w communication errors.
- */
-static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
-				unsigned int power_state)
-{
-	if (power_state == AC_PWRST_D0) {
-		intel_haswell_enable_all_pins(codec, false);
-		intel_haswell_fixup_enable_dp12(codec);
-	}
-
-	snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
-	snd_hda_codec_set_power_to_all(codec, fg, power_state);
-}
-
-/* There is a fixed mapping between audio pin node and display port.
- * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- *
- * on VLV, ILK:
- * Pin Widget 4 - PORT B (port = 1 in i915 driver)
- * Pin Widget 5 - PORT C (port = 2 in i915 driver)
- * Pin Widget 6 - PORT D (port = 3 in i915 driver)
- */
-static int intel_base_nid(struct hda_codec *codec)
-{
-	switch (codec->core.vendor_id) {
-	case 0x80860054: /* ILK */
-	case 0x80862804: /* ILK */
-	case 0x80862882: /* VLV */
-		return 4;
-	default:
-		return 5;
-	}
-}
-
-static int intel_pin2port(void *audio_ptr, int pin_nid)
-{
-	struct hda_codec *codec = audio_ptr;
-	struct hdmi_spec *spec = codec->spec;
-	int base_nid, i;
-
-	if (!spec->port_num) {
-		base_nid = intel_base_nid(codec);
-		if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
-			return -1;
-		return pin_nid - base_nid + 1;
-	}
-
-	/*
-	 * looking for the pin number in the mapping table and return
-	 * the index which indicate the port number
-	 */
-	for (i = 0; i < spec->port_num; i++) {
-		if (pin_nid == spec->port_map[i])
-			return i;
-	}
-
-	codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
-	return -1;
-}
-
-static int intel_port2pin(struct hda_codec *codec, int port)
-{
-	struct hdmi_spec *spec = codec->spec;
-
-	if (!spec->port_num) {
-		/* we assume only from port-B to port-D */
-		if (port < 1 || port > 3)
-			return 0;
-		return port + intel_base_nid(codec) - 1;
-	}
-
-	if (port < 0 || port >= spec->port_num)
-		return 0;
-	return spec->port_map[port];
-}
-
-static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
-{
-	struct hda_codec *codec = audio_ptr;
-	int pin_nid;
-	int dev_id = pipe;
-
-	pin_nid = intel_port2pin(codec, port);
-	if (!pin_nid)
-		return;
-	/* skip notification during system suspend (but not in runtime PM);
-	 * the state will be updated at resume
-	 */
-	if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
-		return;
-
-	snd_hdac_i915_set_bclk(&codec->bus->core);
-	check_presence_and_report(codec, pin_nid, dev_id);
-}
-
-static const struct drm_audio_component_audio_ops intel_audio_ops = {
-	.pin2port = intel_pin2port,
-	.pin_eld_notify = intel_pin_eld_notify,
-};
-
-/* register i915 component pin_eld_notify callback */
-static void register_i915_notifier(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-
-	spec->use_acomp_notifier = true;
-	spec->port2pin = intel_port2pin;
-	setup_drm_audio_ops(codec, &intel_audio_ops);
-	snd_hdac_acomp_register_notifier(&codec->bus->core,
-					&spec->drm_audio_ops);
-	/* no need for forcible resume for jack check thanks to notifier */
-	codec->relaxed_resume = 1;
-}
-
-/* setup_stream ops override for HSW+ */
-static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-				 hda_nid_t pin_nid, int dev_id, u32 stream_tag,
-				 int format)
-{
-	struct hdmi_spec *spec = codec->spec;
-	int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
-	struct hdmi_spec_per_pin *per_pin;
-	int res;
-
-	if (pin_idx < 0)
-		per_pin = NULL;
-	else
-		per_pin = get_pin(spec, pin_idx);
-
-	haswell_verify_D0(codec, cvt_nid, pin_nid);
-
-	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
-		silent_stream_set_kae(codec, per_pin, false);
-		/* wait for pending transfers in codec to clear */
-		usleep_range(100, 200);
-	}
-
-	res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
-				stream_tag, format);
-
-	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
-		usleep_range(100, 200);
-		silent_stream_set_kae(codec, per_pin, true);
-	}
-
-	return res;
-}
-
-/* pin_cvt_fixup ops override for HSW+ and VLV+ */
-static void i915_pin_cvt_fixup(struct hda_codec *codec,
-			       struct hdmi_spec_per_pin *per_pin,
-			       hda_nid_t cvt_nid)
-{
-	if (per_pin) {
-		haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
-		snd_hda_set_dev_select(codec, per_pin->pin_nid,
-			       per_pin->dev_id);
-		intel_verify_pin_cvt_connect(codec, per_pin);
-		intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
-				     per_pin->dev_id, per_pin->mux_idx);
-	} else {
-		intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
-	}
-}
-
-static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	bool silent_streams = false;
-	int pin_idx, res;
-
-	res = generic_hdmi_suspend(codec);
-
-	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-		if (per_pin->silent_stream) {
-			silent_streams = true;
-			break;
-		}
-	}
-
-	if (silent_streams && spec->silent_stream_type == SILENT_STREAM_KAE) {
-		/*
-		 * stream-id should remain programmed when codec goes
-		 * to runtime suspend
-		 */
-		codec->no_stream_clean_at_suspend = 1;
-
-		/*
-		 * the system might go to S3, in which case keep-alive
-		 * must be reprogrammed upon resume
-		 */
-		codec->forced_resume = 1;
-
-		codec_dbg(codec, "HDMI: KAE active at suspend\n");
-	} else {
-		codec->no_stream_clean_at_suspend = 0;
-		codec->forced_resume = 0;
-	}
-
-	return res;
-}
-
-static int i915_adlp_hdmi_resume(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	int pin_idx, res;
-
-	res = generic_hdmi_resume(codec);
-
-	/* KAE not programmed at suspend, nothing to do here */
-	if (!codec->no_stream_clean_at_suspend)
-		return res;
-
-	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-		/*
-		 * If system was in suspend with monitor connected,
-		 * the codec setting may have been lost. Re-enable
-		 * keep-alive.
-		 */
-		if (per_pin->silent_stream) {
-			unsigned int param;
-
-			param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
-						   AC_VERB_GET_CONV, 0);
-			if (!param) {
-				codec_dbg(codec, "HDMI: KAE: restore stream id\n");
-				silent_stream_enable_i915(codec, per_pin);
-			}
-
-			param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
-						   AC_VERB_GET_DIGI_CONVERT_1, 0);
-			if (!(param & (AC_DIG3_KAE << 16))) {
-				codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
-				silent_stream_set_kae(codec, per_pin, true);
-			}
-		}
-	}
-
-	return res;
-}
-
-/* precondition and allocation for Intel codecs */
-static int alloc_intel_hdmi(struct hda_codec *codec)
-{
-	int err;
-
-	/* requires i915 binding */
-	if (!codec->bus->core.audio_component) {
-		codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
-		/* set probe_id here to prevent generic fallback binding */
-		codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
-		return -ENODEV;
-	}
-
-	err = alloc_generic_hdmi(codec);
-	if (err < 0)
-		return err;
-	/* no need to handle unsol events */
-	codec->patch_ops.unsol_event = NULL;
-	return 0;
-}
-
-/* parse and post-process for Intel codecs */
-static int parse_intel_hdmi(struct hda_codec *codec)
-{
-	int err, retries = 3;
-
-	do {
-		err = hdmi_parse_codec(codec);
-	} while (err < 0 && retries--);
-
-	if (err < 0) {
-		generic_spec_free(codec);
-		return err;
-	}
-
-	generic_hdmi_init_per_pins(codec);
-	register_i915_notifier(codec);
-	return 0;
-}
-
-/* Intel Haswell and onwards; audio component with eld notifier */
-static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
-				 const int *port_map, int port_num, int dev_num,
-				 bool send_silent_stream)
-{
-	struct hdmi_spec *spec;
-	int err;
-
-	err = alloc_intel_hdmi(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-	codec->dp_mst = true;
-	spec->vendor_nid = vendor_nid;
-	spec->port_map = port_map;
-	spec->port_num = port_num;
-	spec->intel_hsw_fixup = true;
-	spec->dev_num = dev_num;
-
-	intel_haswell_enable_all_pins(codec, true);
-	intel_haswell_fixup_enable_dp12(codec);
-
-	codec->display_power_control = 1;
-
-	codec->patch_ops.set_power_state = haswell_set_power_state;
-	codec->depop_delay = 0;
-	codec->auto_runtime_pm = 1;
-
-	spec->ops.setup_stream = i915_hsw_setup_stream;
-	spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
-
-	/*
-	 * Enable silent stream feature, if it is enabled via
-	 * module param or Kconfig option
-	 */
-	if (send_silent_stream)
-		spec->silent_stream_type = SILENT_STREAM_I915;
-
-	return parse_intel_hdmi(codec);
-}
-
-static int patch_i915_hsw_hdmi(struct hda_codec *codec)
-{
-	return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
-				     enable_silent_stream);
-}
-
-static int patch_i915_glk_hdmi(struct hda_codec *codec)
-{
-	/*
-	 * Silent stream calls audio component .get_power() from
-	 * .pin_eld_notify(). On GLK this will deadlock in i915 due
-	 * to the audio vs. CDCLK workaround.
-	 */
-	return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
-}
-
-static int patch_i915_icl_hdmi(struct hda_codec *codec)
-{
-	/*
-	 * pin to port mapping table where the value indicate the pin number and
-	 * the index indicate the port number.
-	 */
-	static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
-
-	return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
-				     enable_silent_stream);
-}
-
-static int patch_i915_tgl_hdmi(struct hda_codec *codec)
-{
-	/*
-	 * pin to port mapping table where the value indicate the pin number and
-	 * the index indicate the port number.
-	 */
-	static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
-
-	return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
-				     enable_silent_stream);
-}
-
-static int patch_i915_adlp_hdmi(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int res;
-
-	res = patch_i915_tgl_hdmi(codec);
-	if (!res) {
-		spec = codec->spec;
-
-		if (spec->silent_stream_type) {
-			spec->silent_stream_type = SILENT_STREAM_KAE;
-
-			codec->patch_ops.resume = i915_adlp_hdmi_resume;
-			codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
-		}
-	}
-
-	return res;
-}
-
-/* Intel Baytrail and Braswell; with eld notifier */
-static int patch_i915_byt_hdmi(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err;
-
-	err = alloc_intel_hdmi(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	/* For Valleyview/Cherryview, only the display codec is in the display
-	 * power well and can use link_power ops to request/release the power.
-	 */
-	codec->display_power_control = 1;
-
-	codec->depop_delay = 0;
-	codec->auto_runtime_pm = 1;
-
-	spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
-
-	return parse_intel_hdmi(codec);
-}
-
-/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
-static int patch_i915_cpt_hdmi(struct hda_codec *codec)
-{
-	int err;
-
-	err = alloc_intel_hdmi(codec);
-	if (err < 0)
-		return err;
-	return parse_intel_hdmi(codec);
-}
-
-/*
- * Shared non-generic implementations
- */
-
-static int simple_playback_build_pcms(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	struct hda_pcm *info;
-	unsigned int chans;
-	struct hda_pcm_stream *pstr;
-	struct hdmi_spec_per_cvt *per_cvt;
-
-	per_cvt = get_cvt(spec, 0);
-	chans = get_wcaps(codec, per_cvt->cvt_nid);
-	chans = get_wcaps_channels(chans);
-
-	info = snd_hda_codec_pcm_new(codec, "HDMI 0");
-	if (!info)
-		return -ENOMEM;
-	spec->pcm_rec[0].pcm = info;
-	info->pcm_type = HDA_PCM_TYPE_HDMI;
-	pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
-	*pstr = spec->pcm_playback;
-	pstr->nid = per_cvt->cvt_nid;
-	if (pstr->channels_max <= 2 && chans && chans <= 16)
-		pstr->channels_max = chans;
-
-	return 0;
-}
-
-/* unsolicited event for jack sensing */
-static void simple_hdmi_unsol_event(struct hda_codec *codec,
-				    unsigned int res)
-{
-	snd_hda_jack_set_dirty_all(codec);
-	snd_hda_jack_report_sync(codec);
-}
-
-/* generic_hdmi_build_jack can be used for simple_hdmi, too,
- * as long as spec->pins[] is set correctly
- */
-#define simple_hdmi_build_jack	generic_hdmi_build_jack
-
-static int simple_playback_build_controls(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_cvt *per_cvt;
-	int err;
-
-	per_cvt = get_cvt(spec, 0);
-	err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
-					  per_cvt->cvt_nid,
-					  HDA_PCM_TYPE_HDMI);
-	if (err < 0)
-		return err;
-	return simple_hdmi_build_jack(codec, 0);
-}
-
-static int simple_playback_init(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
-	hda_nid_t pin = per_pin->pin_nid;
-
-	snd_hda_codec_write(codec, pin, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-	/* some codecs require to unmute the pin */
-	if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
-		snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-				    AMP_OUT_UNMUTE);
-	snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
-	return 0;
-}
-
-static void simple_playback_free(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-
-	hdmi_array_free(spec);
-	kfree(spec);
-}
-
-/*
- * Nvidia specific implementations
- */
-
-#define Nv_VERB_SET_Channel_Allocation          0xF79
-#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
-#define Nv_VERB_SET_Audio_Protection_On         0xF98
-#define Nv_VERB_SET_Audio_Protection_Off        0xF99
-
-#define nvhdmi_master_con_nid_7x	0x04
-#define nvhdmi_master_pin_nid_7x	0x05
-
-static const hda_nid_t nvhdmi_con_nids_7x[4] = {
-	/*front, rear, clfe, rear_surr */
-	0x6, 0x8, 0xa, 0xc,
-};
-
-static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
-	/* set audio protect on */
-	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
-	/* enable digital output on pin widget */
-	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-	{} /* terminator */
-};
-
-static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
-	/* set audio protect on */
-	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
-	/* enable digital output on pin widget */
-	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-	{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-	{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-	{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-	{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-	{} /* terminator */
-};
-
-#ifdef LIMITED_RATE_FMT_SUPPORT
-/* support only the safe format and rate */
-#define SUPPORTED_RATES		SNDRV_PCM_RATE_48000
-#define SUPPORTED_MAXBPS	16
-#define SUPPORTED_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
-#else
-/* support all rates and formats */
-#define SUPPORTED_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 |\
-	 SNDRV_PCM_RATE_192000)
-#define SUPPORTED_MAXBPS	24
-#define SUPPORTED_FORMATS \
-	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#endif
-
-static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
-{
-	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
-	return 0;
-}
-
-static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
-{
-	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
-	return 0;
-}
-
-static const unsigned int channels_2_6_8[] = {
-	2, 6, 8
-};
-
-static const unsigned int channels_2_8[] = {
-	2, 8
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
-	.count = ARRAY_SIZE(channels_2_6_8),
-	.list = channels_2_6_8,
-	.mask = 0,
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
-	.count = ARRAY_SIZE(channels_2_8),
-	.list = channels_2_8,
-	.mask = 0,
-};
-
-static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
-				    struct hda_codec *codec,
-				    struct snd_pcm_substream *substream)
-{
-	struct hdmi_spec *spec = codec->spec;
-	const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
-
-	switch (codec->preset->vendor_id) {
-	case 0x10de0002:
-	case 0x10de0003:
-	case 0x10de0005:
-	case 0x10de0006:
-		hw_constraints_channels = &hw_constraints_2_8_channels;
-		break;
-	case 0x10de0007:
-		hw_constraints_channels = &hw_constraints_2_6_8_channels;
-		break;
-	default:
-		break;
-	}
-
-	if (hw_constraints_channels != NULL) {
-		snd_pcm_hw_constraint_list(substream->runtime, 0,
-				SNDRV_PCM_HW_PARAM_CHANNELS,
-				hw_constraints_channels);
-	} else {
-		snd_pcm_hw_constraint_step(substream->runtime, 0,
-					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-	}
-
-	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
-				     struct hda_codec *codec,
-				     struct snd_pcm_substream *substream)
-{
-	struct hdmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-				       struct hda_codec *codec,
-				       unsigned int stream_tag,
-				       unsigned int format,
-				       struct snd_pcm_substream *substream)
-{
-	struct hdmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-					     stream_tag, format, substream);
-}
-
-static const struct hda_pcm_stream simple_pcm_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	.ops = {
-		.open = simple_playback_pcm_open,
-		.close = simple_playback_pcm_close,
-		.prepare = simple_playback_pcm_prepare
-	},
-};
-
-static const struct hda_codec_ops simple_hdmi_patch_ops = {
-	.build_controls = simple_playback_build_controls,
-	.build_pcms = simple_playback_build_pcms,
-	.init = simple_playback_init,
-	.free = simple_playback_free,
-	.unsol_event = simple_hdmi_unsol_event,
-};
-
-static int patch_simple_hdmi(struct hda_codec *codec,
-			     hda_nid_t cvt_nid, hda_nid_t pin_nid)
-{
-	struct hdmi_spec *spec;
-	struct hdmi_spec_per_cvt *per_cvt;
-	struct hdmi_spec_per_pin *per_pin;
-
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (!spec)
-		return -ENOMEM;
-
-	spec->codec = codec;
-	codec->spec = spec;
-	hdmi_array_init(spec, 1);
-
-	spec->multiout.num_dacs = 0;  /* no analog */
-	spec->multiout.max_channels = 2;
-	spec->multiout.dig_out_nid = cvt_nid;
-	spec->num_cvts = 1;
-	spec->num_pins = 1;
-	per_pin = snd_array_new(&spec->pins);
-	per_cvt = snd_array_new(&spec->cvts);
-	if (!per_pin || !per_cvt) {
-		simple_playback_free(codec);
-		return -ENOMEM;
-	}
-	per_cvt->cvt_nid = cvt_nid;
-	per_pin->pin_nid = pin_nid;
-	spec->pcm_playback = simple_pcm_playback;
-
-	codec->patch_ops = simple_hdmi_patch_ops;
-
-	return 0;
-}
-
-static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
-						    int channels)
-{
-	unsigned int chanmask;
-	int chan = channels ? (channels - 1) : 1;
-
-	switch (channels) {
-	default:
-	case 0:
-	case 2:
-		chanmask = 0x00;
-		break;
-	case 4:
-		chanmask = 0x08;
-		break;
-	case 6:
-		chanmask = 0x0b;
-		break;
-	case 8:
-		chanmask = 0x13;
-		break;
-	}
-
-	/* Set the audio infoframe channel allocation and checksum fields.  The
-	 * channel count is computed implicitly by the hardware. */
-	snd_hda_codec_write(codec, 0x1, 0,
-			Nv_VERB_SET_Channel_Allocation, chanmask);
-
-	snd_hda_codec_write(codec, 0x1, 0,
-			Nv_VERB_SET_Info_Frame_Checksum,
-			(0x71 - chan - chanmask));
-}
-
-static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
-				   struct hda_codec *codec,
-				   struct snd_pcm_substream *substream)
-{
-	struct hdmi_spec *spec = codec->spec;
-	int i;
-
-	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
-			0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-	for (i = 0; i < 4; i++) {
-		/* set the stream id */
-		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-				AC_VERB_SET_CHANNEL_STREAMID, 0);
-		/* set the stream format */
-		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-				AC_VERB_SET_STREAM_FORMAT, 0);
-	}
-
-	/* The audio hardware sends a channel count of 0x7 (8ch) when all the
-	 * streams are disabled. */
-	nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
-
-	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
-				     struct hda_codec *codec,
-				     unsigned int stream_tag,
-				     unsigned int format,
-				     struct snd_pcm_substream *substream)
-{
-	int chs;
-	unsigned int dataDCC2, channel_id;
-	int i;
-	struct hdmi_spec *spec = codec->spec;
-	struct hda_spdif_out *spdif;
-	struct hdmi_spec_per_cvt *per_cvt;
-
-	mutex_lock(&codec->spdif_mutex);
-	per_cvt = get_cvt(spec, 0);
-	spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
-
-	chs = substream->runtime->channels;
-
-	dataDCC2 = 0x2;
-
-	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-	if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
-		snd_hda_codec_write(codec,
-				nvhdmi_master_con_nid_7x,
-				0,
-				AC_VERB_SET_DIGI_CONVERT_1,
-				spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
-
-	/* set the stream id */
-	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-			AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
-
-	/* set the stream format */
-	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-			AC_VERB_SET_STREAM_FORMAT, format);
-
-	/* turn on again (if needed) */
-	/* enable and set the channel status audio/data flag */
-	if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
-		snd_hda_codec_write(codec,
-				nvhdmi_master_con_nid_7x,
-				0,
-				AC_VERB_SET_DIGI_CONVERT_1,
-				spdif->ctls & 0xff);
-		snd_hda_codec_write(codec,
-				nvhdmi_master_con_nid_7x,
-				0,
-				AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-	}
-
-	for (i = 0; i < 4; i++) {
-		if (chs == 2)
-			channel_id = 0;
-		else
-			channel_id = i * 2;
-
-		/* turn off SPDIF once;
-		 *otherwise the IEC958 bits won't be updated
-		 */
-		if (codec->spdif_status_reset &&
-		(spdif->ctls & AC_DIG1_ENABLE))
-			snd_hda_codec_write(codec,
-				nvhdmi_con_nids_7x[i],
-				0,
-				AC_VERB_SET_DIGI_CONVERT_1,
-				spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
-		/* set the stream id */
-		snd_hda_codec_write(codec,
-				nvhdmi_con_nids_7x[i],
-				0,
-				AC_VERB_SET_CHANNEL_STREAMID,
-				(stream_tag << 4) | channel_id);
-		/* set the stream format */
-		snd_hda_codec_write(codec,
-				nvhdmi_con_nids_7x[i],
-				0,
-				AC_VERB_SET_STREAM_FORMAT,
-				format);
-		/* turn on again (if needed) */
-		/* enable and set the channel status audio/data flag */
-		if (codec->spdif_status_reset &&
-		(spdif->ctls & AC_DIG1_ENABLE)) {
-			snd_hda_codec_write(codec,
-					nvhdmi_con_nids_7x[i],
-					0,
-					AC_VERB_SET_DIGI_CONVERT_1,
-					spdif->ctls & 0xff);
-			snd_hda_codec_write(codec,
-					nvhdmi_con_nids_7x[i],
-					0,
-					AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-		}
-	}
-
-	nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
-
-	mutex_unlock(&codec->spdif_mutex);
-	return 0;
-}
-
-static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 8,
-	.nid = nvhdmi_master_con_nid_7x,
-	.rates = SUPPORTED_RATES,
-	.maxbps = SUPPORTED_MAXBPS,
-	.formats = SUPPORTED_FORMATS,
-	.ops = {
-		.open = simple_playback_pcm_open,
-		.close = nvhdmi_8ch_7x_pcm_close,
-		.prepare = nvhdmi_8ch_7x_pcm_prepare
-	},
-};
-
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
-				    nvhdmi_master_pin_nid_7x);
-	if (err < 0)
-		return err;
-
-	codec->patch_ops.init = nvhdmi_7x_init_2ch;
-	/* override the PCM rates, etc, as the codec doesn't give full list */
-	spec = codec->spec;
-	spec->pcm_playback.rates = SUPPORTED_RATES;
-	spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
-	spec->pcm_playback.formats = SUPPORTED_FORMATS;
-	spec->nv_dp_workaround = true;
-	return 0;
-}
-
-static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	int err = simple_playback_build_pcms(codec);
-	if (!err) {
-		struct hda_pcm *info = get_pcm_rec(spec, 0);
-		info->own_chmap = true;
-	}
-	return err;
-}
-
-static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	struct hda_pcm *info;
-	struct snd_pcm_chmap *chmap;
-	int err;
-
-	err = simple_playback_build_controls(codec);
-	if (err < 0)
-		return err;
-
-	/* add channel maps */
-	info = get_pcm_rec(spec, 0);
-	err = snd_pcm_add_chmap_ctls(info->pcm,
-				     SNDRV_PCM_STREAM_PLAYBACK,
-				     snd_pcm_alt_chmaps, 8, 0, &chmap);
-	if (err < 0)
-		return err;
-	switch (codec->preset->vendor_id) {
-	case 0x10de0002:
-	case 0x10de0003:
-	case 0x10de0005:
-	case 0x10de0006:
-		chmap->channel_mask = (1U << 2) | (1U << 8);
-		break;
-	case 0x10de0007:
-		chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
-	}
-	return 0;
-}
-
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err = patch_nvhdmi_2ch(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-	spec->multiout.max_channels = 8;
-	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
-	codec->patch_ops.init = nvhdmi_7x_init_8ch;
-	codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
-	codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
-
-	/* Initialize the audio infoframe channel mask and checksum to something
-	 * valid */
-	nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
-
-	return 0;
-}
-
-/*
- * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
- * - 0x10de0015
- * - 0x10de0040
- */
-static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
-		struct hdac_cea_channel_speaker_allocation *cap, int channels)
-{
-	if (cap->ca_index == 0x00 && channels == 2)
-		return SNDRV_CTL_TLVT_CHMAP_FIXED;
-
-	/* If the speaker allocation matches the channel count, it is OK. */
-	if (cap->channels != channels)
-		return -1;
-
-	/* all channels are remappable freely */
-	return SNDRV_CTL_TLVT_CHMAP_VAR;
-}
-
-static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
-		int ca, int chs, unsigned char *map)
-{
-	if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
-		return -EINVAL;
-
-	return 0;
-}
-
-/* map from pin NID to port; port is 0-based */
-/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
-static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
-{
-	return pin_nid - 4;
-}
-
-/* reverse-map from port to pin NID: see above */
-static int nvhdmi_port2pin(struct hda_codec *codec, int port)
-{
-	return port + 4;
-}
-
-static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
-	.pin2port = nvhdmi_pin2port,
-	.pin_eld_notify = generic_acomp_pin_eld_notify,
-	.master_bind = generic_acomp_master_bind,
-	.master_unbind = generic_acomp_master_unbind,
-};
-
-static int patch_nvhdmi(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err;
-
-	err = alloc_generic_hdmi(codec);
-	if (err < 0)
-		return err;
-	codec->dp_mst = true;
-
-	spec = codec->spec;
-
-	err = hdmi_parse_codec(codec);
-	if (err < 0) {
-		generic_spec_free(codec);
-		return err;
-	}
-
-	generic_hdmi_init_per_pins(codec);
-
-	spec->dyn_pin_out = true;
-
-	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-		nvhdmi_chmap_cea_alloc_validate_get_type;
-	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-	spec->nv_dp_workaround = true;
-
-	codec->link_down_at_suspend = 1;
-
-	generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
-
-	return 0;
-}
-
-static int patch_nvhdmi_legacy(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err;
-
-	err = patch_generic_hdmi(codec);
-	if (err)
-		return err;
-
-	spec = codec->spec;
-	spec->dyn_pin_out = true;
-
-	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-		nvhdmi_chmap_cea_alloc_validate_get_type;
-	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-	spec->nv_dp_workaround = true;
-
-	codec->link_down_at_suspend = 1;
-
-	return 0;
-}
-
-/*
- * The HDA codec on NVIDIA Tegra contains two scratch registers that are
- * accessed using vendor-defined verbs. These registers can be used for
- * interoperability between the HDA and HDMI drivers.
- */
-
-/* Audio Function Group node */
-#define NVIDIA_AFG_NID 0x01
-
-/*
- * The SCRATCH0 register is used to notify the HDMI codec of changes in audio
- * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
- * be raised in the HDMI codec. The remainder of the bits is arbitrary. This
- * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
- * additional bit (at position 30) to signal the validity of the format.
- *
- * | 31      | 30    | 29  16 | 15   0 |
- * +---------+-------+--------+--------+
- * | TRIGGER | VALID | UNUSED | FORMAT |
- * +-----------------------------------|
- *
- * Note that for the trigger bit to take effect it needs to change value
- * (i.e. it needs to be toggled). The trigger bit is not applicable from
- * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
- * trigger to hdmi.
- */
-#define NVIDIA_SET_HOST_INTR		0xf80
-#define NVIDIA_GET_SCRATCH0		0xfa6
-#define NVIDIA_SET_SCRATCH0_BYTE0	0xfa7
-#define NVIDIA_SET_SCRATCH0_BYTE1	0xfa8
-#define NVIDIA_SET_SCRATCH0_BYTE2	0xfa9
-#define NVIDIA_SET_SCRATCH0_BYTE3	0xfaa
-#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
-#define NVIDIA_SCRATCH_VALID   (1 << 6)
-
-#define NVIDIA_GET_SCRATCH1		0xfab
-#define NVIDIA_SET_SCRATCH1_BYTE0	0xfac
-#define NVIDIA_SET_SCRATCH1_BYTE1	0xfad
-#define NVIDIA_SET_SCRATCH1_BYTE2	0xfae
-#define NVIDIA_SET_SCRATCH1_BYTE3	0xfaf
-
-/*
- * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
- * the format is invalidated so that the HDMI codec can be disabled.
- */
-static void tegra_hdmi_set_format(struct hda_codec *codec,
-				  hda_nid_t cvt_nid,
-				  unsigned int format)
-{
-	unsigned int value;
-	unsigned int nid = NVIDIA_AFG_NID;
-	struct hdmi_spec *spec = codec->spec;
-
-	/*
-	 * Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
-	 * This resulted in moving scratch registers from audio function
-	 * group to converter widget context. So CVT NID should be used for
-	 * scratch register read/write for DP MST supported Tegra HDA codec.
-	 */
-	if (codec->dp_mst)
-		nid = cvt_nid;
-
-	/* bits [31:30] contain the trigger and valid bits */
-	value = snd_hda_codec_read(codec, nid, 0,
-				   NVIDIA_GET_SCRATCH0, 0);
-	value = (value >> 24) & 0xff;
-
-	/* bits [15:0] are used to store the HDA format */
-	snd_hda_codec_write(codec, nid, 0,
-			    NVIDIA_SET_SCRATCH0_BYTE0,
-			    (format >> 0) & 0xff);
-	snd_hda_codec_write(codec, nid, 0,
-			    NVIDIA_SET_SCRATCH0_BYTE1,
-			    (format >> 8) & 0xff);
-
-	/* bits [16:24] are unused */
-	snd_hda_codec_write(codec, nid, 0,
-			    NVIDIA_SET_SCRATCH0_BYTE2, 0);
-
-	/*
-	 * Bit 30 signals that the data is valid and hence that HDMI audio can
-	 * be enabled.
-	 */
-	if (format == 0)
-		value &= ~NVIDIA_SCRATCH_VALID;
-	else
-		value |= NVIDIA_SCRATCH_VALID;
-
-	if (spec->hdmi_intr_trig_ctrl) {
-		/*
-		 * For Tegra HDA Codec design from TEGRA234 onwards, the
-		 * Interrupt to hdmi driver is triggered by writing
-		 * non-zero values to verb 0xF80 instead of 31st bit of
-		 * scratch register.
-		 */
-		snd_hda_codec_write(codec, nid, 0,
-				NVIDIA_SET_SCRATCH0_BYTE3, value);
-		snd_hda_codec_write(codec, nid, 0,
-				NVIDIA_SET_HOST_INTR, 0x1);
-	} else {
-		/*
-		 * Whenever the 31st trigger bit is toggled, an interrupt is raised
-		 * in the HDMI codec. The HDMI driver will use that as trigger
-		 * to update its configuration.
-		 */
-		value ^= NVIDIA_SCRATCH_TRIGGER;
-
-		snd_hda_codec_write(codec, nid, 0,
-				NVIDIA_SET_SCRATCH0_BYTE3, value);
-	}
-}
-
-static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
-				  struct hda_codec *codec,
-				  unsigned int stream_tag,
-				  unsigned int format,
-				  struct snd_pcm_substream *substream)
-{
-	int err;
-
-	err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag,
-						format, substream);
-	if (err < 0)
-		return err;
-
-	/* notify the HDMI codec of the format change */
-	tegra_hdmi_set_format(codec, hinfo->nid, format);
-
-	return 0;
-}
-
-static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
-				  struct hda_codec *codec,
-				  struct snd_pcm_substream *substream)
-{
-	/* invalidate the format in the HDMI codec */
-	tegra_hdmi_set_format(codec, hinfo->nid, 0);
-
-	return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream);
-}
-
-static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
-{
-	struct hdmi_spec *spec = codec->spec;
-	unsigned int i;
-
-	for (i = 0; i < spec->num_pins; i++) {
-		struct hda_pcm *pcm = get_pcm_rec(spec, i);
-
-		if (pcm->pcm_type == type)
-			return pcm;
-	}
-
-	return NULL;
-}
-
-static int tegra_hdmi_build_pcms(struct hda_codec *codec)
-{
-	struct hda_pcm_stream *stream;
-	struct hda_pcm *pcm;
-	int err;
-
-	err = generic_hdmi_build_pcms(codec);
-	if (err < 0)
-		return err;
-
-	pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
-	if (!pcm)
-		return -ENODEV;
-
-	/*
-	 * Override ->prepare() and ->cleanup() operations to notify the HDMI
-	 * codec about format changes.
-	 */
-	stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
-	stream->ops.prepare = tegra_hdmi_pcm_prepare;
-	stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
-
-	return 0;
-}
-
-static int tegra_hdmi_init(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	int i, err;
-
-	err = hdmi_parse_codec(codec);
-	if (err < 0) {
-		generic_spec_free(codec);
-		return err;
-	}
-
-	for (i = 0; i < spec->num_cvts; i++)
-		snd_hda_codec_write(codec, spec->cvt_nids[i], 0,
-					AC_VERB_SET_DIGI_CONVERT_1,
-					AC_DIG1_ENABLE);
-
-	generic_hdmi_init_per_pins(codec);
-
-	codec->depop_delay = 10;
-	codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
-	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-		nvhdmi_chmap_cea_alloc_validate_get_type;
-	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-
-	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-		nvhdmi_chmap_cea_alloc_validate_get_type;
-	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-	spec->nv_dp_workaround = true;
-
-	return 0;
-}
-
-static int patch_tegra_hdmi(struct hda_codec *codec)
-{
-	int err;
-
-	err = alloc_generic_hdmi(codec);
-	if (err < 0)
-		return err;
-
-	return tegra_hdmi_init(codec);
-}
-
-static int patch_tegra234_hdmi(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err;
-
-	err = alloc_generic_hdmi(codec);
-	if (err < 0)
-		return err;
-
-	codec->dp_mst = true;
-	spec = codec->spec;
-	spec->dyn_pin_out = true;
-	spec->hdmi_intr_trig_ctrl = true;
-
-	return tegra_hdmi_init(codec);
-}
-
-/*
- * ATI/AMD-specific implementations
- */
-
-#define is_amdhdmi_rev3_or_later(codec) \
-	((codec)->core.vendor_id == 0x1002aa01 && \
-	 ((codec)->core.revision_id & 0xff00) >= 0x0300)
-#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
-
-/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
-#define ATI_VERB_SET_CHANNEL_ALLOCATION	0x771
-#define ATI_VERB_SET_DOWNMIX_INFO	0x772
-#define ATI_VERB_SET_MULTICHANNEL_01	0x777
-#define ATI_VERB_SET_MULTICHANNEL_23	0x778
-#define ATI_VERB_SET_MULTICHANNEL_45	0x779
-#define ATI_VERB_SET_MULTICHANNEL_67	0x77a
-#define ATI_VERB_SET_HBR_CONTROL	0x77c
-#define ATI_VERB_SET_MULTICHANNEL_1	0x785
-#define ATI_VERB_SET_MULTICHANNEL_3	0x786
-#define ATI_VERB_SET_MULTICHANNEL_5	0x787
-#define ATI_VERB_SET_MULTICHANNEL_7	0x788
-#define ATI_VERB_SET_MULTICHANNEL_MODE	0x789
-#define ATI_VERB_GET_CHANNEL_ALLOCATION	0xf71
-#define ATI_VERB_GET_DOWNMIX_INFO	0xf72
-#define ATI_VERB_GET_MULTICHANNEL_01	0xf77
-#define ATI_VERB_GET_MULTICHANNEL_23	0xf78
-#define ATI_VERB_GET_MULTICHANNEL_45	0xf79
-#define ATI_VERB_GET_MULTICHANNEL_67	0xf7a
-#define ATI_VERB_GET_HBR_CONTROL	0xf7c
-#define ATI_VERB_GET_MULTICHANNEL_1	0xf85
-#define ATI_VERB_GET_MULTICHANNEL_3	0xf86
-#define ATI_VERB_GET_MULTICHANNEL_5	0xf87
-#define ATI_VERB_GET_MULTICHANNEL_7	0xf88
-#define ATI_VERB_GET_MULTICHANNEL_MODE	0xf89
-
-/* AMD specific HDA cvt verbs */
-#define ATI_VERB_SET_RAMP_RATE		0x770
-#define ATI_VERB_GET_RAMP_RATE		0xf70
-
-#define ATI_OUT_ENABLE 0x1
-
-#define ATI_MULTICHANNEL_MODE_PAIRED	0
-#define ATI_MULTICHANNEL_MODE_SINGLE	1
-
-#define ATI_HBR_CAPABLE 0x01
-#define ATI_HBR_ENABLE 0x10
-
-static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
-			       int dev_id, unsigned char *buf, int *eld_size)
-{
-	WARN_ON(dev_id != 0);
-	/* call hda_eld.c ATI/AMD-specific function */
-	return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
-				    is_amdhdmi_rev3_or_later(codec));
-}
-
-static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
-					hda_nid_t pin_nid, int dev_id, int ca,
-					int active_channels, int conn_type)
-{
-	WARN_ON(dev_id != 0);
-	snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
-}
-
-static int atihdmi_paired_swap_fc_lfe(int pos)
-{
-	/*
-	 * ATI/AMD have automatic FC/LFE swap built-in
-	 * when in pairwise mapping mode.
-	 */
-
-	switch (pos) {
-		/* see channel_allocations[].speakers[] */
-		case 2: return 3;
-		case 3: return 2;
-		default: break;
-	}
-
-	return pos;
-}
-
-static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
-			int ca, int chs, unsigned char *map)
-{
-	struct hdac_cea_channel_speaker_allocation *cap;
-	int i, j;
-
-	/* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
-
-	cap = snd_hdac_get_ch_alloc_from_ca(ca);
-	for (i = 0; i < chs; ++i) {
-		int mask = snd_hdac_chmap_to_spk_mask(map[i]);
-		bool ok = false;
-		bool companion_ok = false;
-
-		if (!mask)
-			continue;
-
-		for (j = 0 + i % 2; j < 8; j += 2) {
-			int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
-			if (cap->speakers[chan_idx] == mask) {
-				/* channel is in a supported position */
-				ok = true;
-
-				if (i % 2 == 0 && i + 1 < chs) {
-					/* even channel, check the odd companion */
-					int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
-					int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
-					int comp_mask_act = cap->speakers[comp_chan_idx];
-
-					if (comp_mask_req == comp_mask_act)
-						companion_ok = true;
-					else
-						return -EINVAL;
-				}
-				break;
-			}
-		}
-
-		if (!ok)
-			return -EINVAL;
-
-		if (companion_ok)
-			i++; /* companion channel already checked */
-	}
-
-	return 0;
-}
-
-static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
-		hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
-{
-	struct hda_codec *codec = hdac_to_hda_codec(hdac);
-	int verb;
-	int ati_channel_setup = 0;
-
-	if (hdmi_slot > 7)
-		return -EINVAL;
-
-	if (!has_amd_full_remap_support(codec)) {
-		hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
-
-		/* In case this is an odd slot but without stream channel, do not
-		 * disable the slot since the corresponding even slot could have a
-		 * channel. In case neither have a channel, the slot pair will be
-		 * disabled when this function is called for the even slot. */
-		if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
-			return 0;
-
-		hdmi_slot -= hdmi_slot % 2;
-
-		if (stream_channel != 0xf)
-			stream_channel -= stream_channel % 2;
-	}
-
-	verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
-
-	/* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
-
-	if (stream_channel != 0xf)
-		ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
-
-	return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
-}
-
-static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
-				hda_nid_t pin_nid, int asp_slot)
-{
-	struct hda_codec *codec = hdac_to_hda_codec(hdac);
-	bool was_odd = false;
-	int ati_asp_slot = asp_slot;
-	int verb;
-	int ati_channel_setup;
-
-	if (asp_slot > 7)
-		return -EINVAL;
-
-	if (!has_amd_full_remap_support(codec)) {
-		ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
-		if (ati_asp_slot % 2 != 0) {
-			ati_asp_slot -= 1;
-			was_odd = true;
-		}
-	}
-
-	verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
-
-	ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
-
-	if (!(ati_channel_setup & ATI_OUT_ENABLE))
-		return 0xf;
-
-	return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
-}
-
-static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
-		struct hdac_chmap *chmap,
-		struct hdac_cea_channel_speaker_allocation *cap,
-		int channels)
-{
-	int c;
-
-	/*
-	 * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
-	 * we need to take that into account (a single channel may take 2
-	 * channel slots if we need to carry a silent channel next to it).
-	 * On Rev3+ AMD codecs this function is not used.
-	 */
-	int chanpairs = 0;
-
-	/* We only produce even-numbered channel count TLVs */
-	if ((channels % 2) != 0)
-		return -1;
-
-	for (c = 0; c < 7; c += 2) {
-		if (cap->speakers[c] || cap->speakers[c+1])
-			chanpairs++;
-	}
-
-	if (chanpairs * 2 != channels)
-		return -1;
-
-	return SNDRV_CTL_TLVT_CHMAP_PAIRED;
-}
-
-static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
-		struct hdac_cea_channel_speaker_allocation *cap,
-		unsigned int *chmap, int channels)
-{
-	/* produce paired maps for pre-rev3 ATI/AMD codecs */
-	int count = 0;
-	int c;
-
-	for (c = 7; c >= 0; c--) {
-		int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
-		int spk = cap->speakers[chan];
-		if (!spk) {
-			/* add N/A channel if the companion channel is occupied */
-			if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
-				chmap[count++] = SNDRV_CHMAP_NA;
-
-			continue;
-		}
-
-		chmap[count++] = snd_hdac_spk_to_chmap(spk);
-	}
-
-	WARN_ON(count != channels);
-}
-
-static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
-				 int dev_id, bool hbr)
-{
-	int hbr_ctl, hbr_ctl_new;
-
-	WARN_ON(dev_id != 0);
-
-	hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
-	if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
-		if (hbr)
-			hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
-		else
-			hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
-
-		codec_dbg(codec,
-			  "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
-				pin_nid,
-				hbr_ctl == hbr_ctl_new ? "" : "new-",
-				hbr_ctl_new);
-
-		if (hbr_ctl != hbr_ctl_new)
-			snd_hda_codec_write(codec, pin_nid, 0,
-						ATI_VERB_SET_HBR_CONTROL,
-						hbr_ctl_new);
-
-	} else if (hbr)
-		return -EINVAL;
-
-	return 0;
-}
-
-static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-				hda_nid_t pin_nid, int dev_id,
-				u32 stream_tag, int format)
-{
-	if (is_amdhdmi_rev3_or_later(codec)) {
-		int ramp_rate = 180; /* default as per AMD spec */
-		/* disable ramp-up/down for non-pcm as per AMD spec */
-		if (format & AC_FMT_TYPE_NON_PCM)
-			ramp_rate = 0;
-
-		snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
-	}
-
-	return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
-				 stream_tag, format);
-}
-
-
-static int atihdmi_init(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec = codec->spec;
-	int pin_idx, err;
-
-	err = generic_hdmi_init(codec);
-
-	if (err)
-		return err;
-
-	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-		/* make sure downmix information in infoframe is zero */
-		snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
-
-		/* enable channel-wise remap mode if supported */
-		if (has_amd_full_remap_support(codec))
-			snd_hda_codec_write(codec, per_pin->pin_nid, 0,
-					    ATI_VERB_SET_MULTICHANNEL_MODE,
-					    ATI_MULTICHANNEL_MODE_SINGLE);
-	}
-	codec->auto_runtime_pm = 1;
-
-	return 0;
-}
-
-/* map from pin NID to port; port is 0-based */
-/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
-static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
-{
-	return pin_nid / 2 - 1;
-}
-
-/* reverse-map from port to pin NID: see above */
-static int atihdmi_port2pin(struct hda_codec *codec, int port)
-{
-	return port * 2 + 3;
-}
-
-static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
-	.pin2port = atihdmi_pin2port,
-	.pin_eld_notify = generic_acomp_pin_eld_notify,
-	.master_bind = generic_acomp_master_bind,
-	.master_unbind = generic_acomp_master_unbind,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	struct hdmi_spec_per_cvt *per_cvt;
-	int err, cvt_idx;
-
-	err = patch_generic_hdmi(codec);
-
-	if (err)
-		return err;
-
-	codec->patch_ops.init = atihdmi_init;
-
-	spec = codec->spec;
-
-	spec->static_pcm_mapping = true;
-
-	spec->ops.pin_get_eld = atihdmi_pin_get_eld;
-	spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
-	spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
-	spec->ops.setup_stream = atihdmi_setup_stream;
-
-	spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
-	spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
-
-	if (!has_amd_full_remap_support(codec)) {
-		/* override to ATI/AMD-specific versions with pairwise mapping */
-		spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-			atihdmi_paired_chmap_cea_alloc_validate_get_type;
-		spec->chmap.ops.cea_alloc_to_tlv_chmap =
-				atihdmi_paired_cea_alloc_to_tlv_chmap;
-		spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
-	}
-
-	/* ATI/AMD converters do not advertise all of their capabilities */
-	for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-		per_cvt = get_cvt(spec, cvt_idx);
-		per_cvt->channels_max = max(per_cvt->channels_max, 8u);
-		per_cvt->rates |= SUPPORTED_RATES;
-		per_cvt->formats |= SUPPORTED_FORMATS;
-		per_cvt->maxbps = max(per_cvt->maxbps, 24u);
-	}
-
-	spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
-
-	/* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
-	 * the link-down as is.  Tell the core to allow it.
-	 */
-	codec->link_down_at_suspend = 1;
-
-	generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
-
-	return 0;
-}
-
-/* VIA HDMI Implementation */
-#define VIAHDMI_CVT_NID	0x02	/* audio converter1 */
-#define VIAHDMI_PIN_NID	0x03	/* HDMI output pin1 */
-
-static int patch_via_hdmi(struct hda_codec *codec)
-{
-	return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
-}
-
 static int patch_gf_hdmi(struct hda_codec *codec)
 {
 	int err;
@@ -4509,125 +2367,15 @@ static int patch_gf_hdmi(struct hda_codec *codec)
  */
 static const struct hda_device_id snd_hda_id_hdmi[] = {
 HDA_CODEC_ENTRY(0x00147a47, "Loongson HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI",	patch_atihdmi),
-HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI",	patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI",	patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",	patch_atihdmi),
 HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",	patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP",	patch_nvhdmi_legacy),
-/* 17 is known to be absent */
-HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP",	patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP",	patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP",	patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",	patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",	patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",	patch_via_hdmi),
-HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",	patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP",	patch_gf_hdmi),
@@ -4641,40 +2389,10 @@ HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP",	patch_gf_hdmi),
 HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",	patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI",	patch_i915_glk_hdmi),
 HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",	patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",	patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI",	patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI",	patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",	patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI",	patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",	patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI",	patch_i915_adlp_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",	patch_i915_byt_hdmi),
-HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",	patch_i915_byt_hdmi),
 HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI",	patch_generic_hdmi),
 /* special ID for generic HDMI */
 HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
@@ -4684,9 +2402,6 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("HDMI HD-audio codec");
-MODULE_ALIAS("snd-hda-codec-intelhdmi");
-MODULE_ALIAS("snd-hda-codec-nvhdmi");
-MODULE_ALIAS("snd-hda-codec-atihdmi");
 
 static struct hda_codec_driver hdmi_driver = {
 	.id = snd_hda_id_hdmi,
diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h
new file mode 100644
index 000000000000..96351bebbc1b
--- /dev/null
+++ b/sound/hda/codecs/hdmi/hdmi_local.h
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD-audio HDMI codec driver
+ */
+
+#ifndef __HDA_HDMI_LOCAL_H
+#define __HDA_HDMI_LOCAL_H
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_chmap.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+
+struct hdmi_spec_per_cvt {
+	hda_nid_t cvt_nid;
+	bool assigned;		/* the stream has been assigned */
+	bool silent_stream;	/* silent stream activated */
+	unsigned int channels_min;
+	unsigned int channels_max;
+	u32 rates;
+	u64 formats;
+	unsigned int maxbps;
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS	32
+
+struct hdmi_spec_per_pin {
+	hda_nid_t pin_nid;
+	int dev_id;
+	/* pin idx, different device entries on the same pin use the same idx */
+	int pin_nid_idx;
+	int num_mux_nids;
+	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+	int mux_idx;
+	hda_nid_t cvt_nid;
+
+	struct hda_codec *codec;
+	struct hdmi_eld sink_eld;
+	struct mutex lock;
+	struct delayed_work work;
+	struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
+	int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
+	int prev_pcm_idx; /* previously assigned pcm index */
+	int repoll_count;
+	bool setup; /* the stream has been set up by prepare callback */
+	bool silent_stream;
+	int channels; /* current number of channels */
+	bool non_pcm;
+	bool chmap_set;		/* channel-map override by ALSA API? */
+	unsigned char chmap[8]; /* ALSA API channel-map */
+#ifdef CONFIG_SND_PROC_FS
+	struct snd_info_entry *proc_entry;
+#endif
+};
+
+/* operations used by generic code that can be overridden by patches */
+struct hdmi_ops {
+	int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
+			   int dev_id, unsigned char *buf, int *eld_size);
+
+	void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
+				    int dev_id,
+				    int ca, int active_channels, int conn_type);
+
+	/* enable/disable HBR (HD passthrough) */
+	int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
+			     int dev_id, bool hbr);
+
+	int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
+			    hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+			    int format);
+
+	void (*pin_cvt_fixup)(struct hda_codec *codec,
+			      struct hdmi_spec_per_pin *per_pin,
+			      hda_nid_t cvt_nid);
+
+	void (*silent_stream)(struct hda_codec *codec,
+			      struct hdmi_spec_per_pin *per_pin,
+			      bool enable);
+};
+
+struct hdmi_pcm {
+	struct hda_pcm *pcm;
+	struct snd_jack *jack;
+	struct snd_kcontrol *eld_ctl;
+};
+
+enum {
+	SILENT_STREAM_OFF = 0,
+	SILENT_STREAM_KAE,	/* use standard HDA Keep-Alive */
+	SILENT_STREAM_I915,	/* Intel i915 extension */
+};
+
+struct hdmi_spec {
+	struct hda_codec *codec;
+	int num_cvts;
+	struct snd_array cvts; /* struct hdmi_spec_per_cvt */
+	hda_nid_t cvt_nids[4]; /* only for haswell fix */
+
+	/*
+	 * num_pins is the number of virtual pins
+	 * for example, there are 3 pins, and each pin
+	 * has 4 device entries, then the num_pins is 12
+	 */
+	int num_pins;
+	/*
+	 * num_nids is the number of real pins
+	 * In the above example, num_nids is 3
+	 */
+	int num_nids;
+	/*
+	 * dev_num is the number of device entries
+	 * on each pin.
+	 * In the above example, dev_num is 4
+	 */
+	int dev_num;
+	struct snd_array pins; /* struct hdmi_spec_per_pin */
+	struct hdmi_pcm pcm_rec[8];
+	struct mutex pcm_lock;
+	struct mutex bind_lock; /* for audio component binding */
+	/* pcm_bitmap means which pcms have been assigned to pins*/
+	unsigned long pcm_bitmap;
+	int pcm_used;	/* counter of pcm_rec[] */
+	/* bitmap shows whether the pcm is opened in user space
+	 * bit 0 means the first playback PCM (PCM3);
+	 * bit 1 means the second playback PCM, and so on.
+	 */
+	unsigned long pcm_in_use;
+
+	struct hdmi_eld temp_eld;
+	struct hdmi_ops ops;
+
+	bool dyn_pin_out;
+	bool static_pcm_mapping;
+	/* hdmi interrupt trigger control flag for Nvidia codec */
+	bool hdmi_intr_trig_ctrl;
+	bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
+
+	bool intel_hsw_fixup;	/* apply Intel platform-specific fixups */
+	/*
+	 * Non-generic VIA/NVIDIA specific
+	 */
+	struct hda_multi_out multiout;
+	struct hda_pcm_stream pcm_playback;
+
+	bool use_acomp_notifier; /* use eld_notify callback for hotplug */
+	bool acomp_registered; /* audio component registered in this driver */
+	bool force_connect; /* force connectivity */
+	struct drm_audio_component_audio_ops drm_audio_ops;
+	int (*port2pin)(struct hda_codec *codec, int port); /* reverse port/pin mapping */
+
+	struct hdac_chmap chmap;
+	hda_nid_t vendor_nid;
+	const int *port_map;
+	int port_num;
+	int silent_stream_type;
+
+	const struct snd_pcm_hw_constraint_list *hw_constraints_channels;
+};
+
+#ifdef CONFIG_SND_HDA_COMPONENT
+static inline bool codec_has_acomp(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	return spec->use_acomp_notifier;
+}
+#else
+#define codec_has_acomp(codec)	false
+#endif
+
+struct hdmi_audio_infoframe {
+	u8 type; /* 0x84 */
+	u8 ver;  /* 0x01 */
+	u8 len;  /* 0x0a */
+
+	u8 checksum;
+
+	u8 CC02_CT47;	/* CC in bits 0:2, CT in 4:7 */
+	u8 SS01_SF24;
+	u8 CXT04;
+	u8 CA;
+	u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+struct dp_audio_infoframe {
+	u8 type; /* 0x84 */
+	u8 len;  /* 0x1b */
+	u8 ver;  /* 0x11 << 2 */
+
+	u8 CC02_CT47;	/* match with HDMI infoframe from this on */
+	u8 SS01_SF24;
+	u8 CXT04;
+	u8 CA;
+	u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+union audio_infoframe {
+	struct hdmi_audio_infoframe hdmi;
+	struct dp_audio_infoframe dp;
+	DECLARE_FLEX_ARRAY(u8, bytes);
+};
+
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES		SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS	16
+#define SUPPORTED_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_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 |\
+	 SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS	24
+#define SUPPORTED_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
+/*
+ * HDMI routines
+ */
+
+#define get_pin(spec, idx) \
+	((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
+#define get_cvt(spec, idx) \
+	((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
+/* obtain hdmi_pcm object assigned to idx */
+#define get_hdmi_pcm(spec, idx)	(&(spec)->pcm_rec[idx])
+/* obtain hda_pcm object assigned to idx */
+#define get_pcm_rec(spec, idx)	(get_hdmi_pcm(spec, idx)->pcm)
+
+/* Generic HDMI codec support */
+int snd_hda_hdmi_generic_alloc(struct hda_codec *codec);
+int snd_hda_hdmi_parse_codec(struct hda_codec *codec);
+int patch_generic_hdmi(struct hda_codec *codec);
+void snd_hda_hdmi_generic_free(struct hda_codec *codec);
+
+int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec);
+int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec);
+int snd_hda_hdmi_generic_init(struct hda_codec *codec);
+int snd_hda_hdmi_generic_suspend(struct hda_codec *codec);
+int snd_hda_hdmi_generic_resume(struct hda_codec *codec);
+void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res);
+
+int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec,
+				     hda_nid_t pin_nid, int dev_id);
+#define pin_id_to_pin_index(codec, pin, dev) \
+	snd_hda_hdmi_pin_id_to_pin_index(codec, pin, dev)
+int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec);
+void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec);
+int snd_hda_hdmi_setup_stream(struct hda_codec *codec,
+			      hda_nid_t cvt_nid,
+			      hda_nid_t pin_nid, int dev_id,
+			      u32 stream_tag, int format);
+
+int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     struct snd_pcm_substream *substream);
+int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream);
+
+void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec,
+					    hda_nid_t nid, int dev_id);
+void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec,
+					struct hdmi_spec_per_pin *per_pin,
+					bool non_pcm);
+
+/* Audio component support */
+void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec,
+				      const struct drm_audio_component_audio_ops *ops);
+void snd_hda_hdmi_acomp_init(struct hda_codec *codec,
+			     const struct drm_audio_component_audio_ops *ops,
+			     int (*port2pin)(struct hda_codec *, int));
+void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id);
+int snd_hda_hdmi_acomp_master_bind(struct device *dev,
+				   struct drm_audio_component *acomp);
+void snd_hda_hdmi_acomp_master_unbind(struct device *dev,
+				      struct drm_audio_component *acomp);
+
+/* Simple / legacy HDMI codec support */
+int patch_simple_hdmi(struct hda_codec *codec,
+		      hda_nid_t cvt_nid, hda_nid_t pin_nid);
+void snd_hda_hdmi_simple_free(struct hda_codec *codec);
+
+int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec);
+int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec);
+int snd_hda_hdmi_simple_init(struct hda_codec *codec);
+void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec,
+				     unsigned int res);
+int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo,
+				 struct hda_codec *codec,
+				 struct snd_pcm_substream *substream);
+
+#endif /* __HDA_HDMI_LOCAL_H */
diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c
new file mode 100644
index 000000000000..a88ac1f80db6
--- /dev/null
+++ b/sound/hda/codecs/hdmi/intelhdmi.c
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Intel HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+static bool enable_silent_stream =
+IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
+module_param(enable_silent_stream, bool, 0644);
+MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
+
+#define INTEL_GET_VENDOR_VERB	0xf81
+#define INTEL_SET_VENDOR_VERB	0x781
+#define INTEL_EN_DP12		0x02	/* enable DP 1.2 features */
+#define INTEL_EN_ALL_PIN_CVTS	0x01	/* enable 2nd & 3rd pins and convertors */
+
+static void intel_haswell_enable_all_pins(struct hda_codec *codec,
+					  bool update_tree)
+{
+	unsigned int vendor_param;
+	struct hdmi_spec *spec = codec->spec;
+
+	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+				INTEL_GET_VENDOR_VERB, 0);
+	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
+		return;
+
+	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
+	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+				INTEL_SET_VENDOR_VERB, vendor_param);
+	if (vendor_param == -1)
+		return;
+
+	if (update_tree)
+		snd_hda_codec_update_widgets(codec);
+}
+
+static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
+{
+	unsigned int vendor_param;
+	struct hdmi_spec *spec = codec->spec;
+
+	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+				INTEL_GET_VENDOR_VERB, 0);
+	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
+		return;
+
+	/* enable DP1.2 mode */
+	vendor_param |= INTEL_EN_DP12;
+	snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
+	snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
+				INTEL_SET_VENDOR_VERB, vendor_param);
+}
+
+/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
+ * Otherwise you may get severe h/w communication errors.
+ */
+static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+				unsigned int power_state)
+{
+	if (power_state == AC_PWRST_D0) {
+		intel_haswell_enable_all_pins(codec, false);
+		intel_haswell_fixup_enable_dp12(codec);
+	}
+
+	snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
+	snd_hda_codec_set_power_to_all(codec, fg, power_state);
+}
+
+/* There is a fixed mapping between audio pin node and display port.
+ * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ *
+ * on VLV, ILK:
+ * Pin Widget 4 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 5 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 6 - PORT D (port = 3 in i915 driver)
+ */
+static int intel_base_nid(struct hda_codec *codec)
+{
+	switch (codec->core.vendor_id) {
+	case 0x80860054: /* ILK */
+	case 0x80862804: /* ILK */
+	case 0x80862882: /* VLV */
+		return 4;
+	default:
+		return 5;
+	}
+}
+
+static int intel_pin2port(void *audio_ptr, int pin_nid)
+{
+	struct hda_codec *codec = audio_ptr;
+	struct hdmi_spec *spec = codec->spec;
+	int base_nid, i;
+
+	if (!spec->port_num) {
+		base_nid = intel_base_nid(codec);
+		if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
+			return -1;
+		return pin_nid - base_nid + 1;
+	}
+
+	/*
+	 * looking for the pin number in the mapping table and return
+	 * the index which indicate the port number
+	 */
+	for (i = 0; i < spec->port_num; i++) {
+		if (pin_nid == spec->port_map[i])
+			return i;
+	}
+
+	codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
+	return -1;
+}
+
+static int intel_port2pin(struct hda_codec *codec, int port)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	if (!spec->port_num) {
+		/* we assume only from port-B to port-D */
+		if (port < 1 || port > 3)
+			return 0;
+		return port + intel_base_nid(codec) - 1;
+	}
+
+	if (port < 0 || port >= spec->port_num)
+		return 0;
+	return spec->port_map[port];
+}
+
+static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
+{
+	struct hda_codec *codec = audio_ptr;
+	int pin_nid;
+	int dev_id = pipe;
+
+	pin_nid = intel_port2pin(codec, port);
+	if (!pin_nid)
+		return;
+	/* skip notification during system suspend (but not in runtime PM);
+	 * the state will be updated at resume
+	 */
+	if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+		return;
+
+	snd_hdac_i915_set_bclk(&codec->bus->core);
+	snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id);
+}
+
+static const struct drm_audio_component_audio_ops intel_audio_ops = {
+	.pin2port = intel_pin2port,
+	.pin_eld_notify = intel_pin_eld_notify,
+};
+
+/* register i915 component pin_eld_notify callback */
+static void register_i915_notifier(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	spec->use_acomp_notifier = true;
+	spec->port2pin = intel_port2pin;
+	snd_hda_hdmi_setup_drm_audio_ops(codec, &intel_audio_ops);
+	snd_hdac_acomp_register_notifier(&codec->bus->core,
+					&spec->drm_audio_ops);
+	/* no need for forcible resume for jack check thanks to notifier */
+	codec->relaxed_resume = 1;
+}
+
+#define I915_SILENT_RATE		48000
+#define I915_SILENT_CHANNELS		2
+#define I915_SILENT_FORMAT_BITS	16
+#define I915_SILENT_FMT_MASK		0xf
+
+static void silent_stream_enable_i915(struct hda_codec *codec,
+				      struct hdmi_spec_per_pin *per_pin)
+{
+	unsigned int format;
+
+	snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
+				 per_pin->dev_id, I915_SILENT_RATE);
+
+	/* trigger silent stream generation in hw */
+	format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS,
+					I915_SILENT_RATE);
+	snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
+				   I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
+	usleep_range(100, 200);
+	snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
+
+	per_pin->channels = I915_SILENT_CHANNELS;
+	snd_hda_hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+}
+
+static void silent_stream_set_kae(struct hda_codec *codec,
+				  struct hdmi_spec_per_pin *per_pin,
+				  bool enable)
+{
+	unsigned int param;
+
+	codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
+
+	param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
+	param = (param >> 16) & 0xff;
+
+	if (enable)
+		param |= AC_DIG3_KAE;
+	else
+		param &= ~AC_DIG3_KAE;
+
+	snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
+}
+
+static void i915_set_silent_stream(struct hda_codec *codec,
+				   struct hdmi_spec_per_pin *per_pin,
+				   bool enable)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	switch (spec->silent_stream_type) {
+	case SILENT_STREAM_KAE:
+		if (enable) {
+			silent_stream_enable_i915(codec, per_pin);
+			silent_stream_set_kae(codec, per_pin, true);
+		} else {
+			silent_stream_set_kae(codec, per_pin, false);
+		}
+		break;
+	case SILENT_STREAM_I915:
+		if (enable) {
+			silent_stream_enable_i915(codec, per_pin);
+			snd_hda_power_up_pm(codec);
+		} else {
+			/* release ref taken in silent_stream_enable() */
+			snd_hda_power_down_pm(codec);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void haswell_verify_D0(struct hda_codec *codec,
+			      hda_nid_t cvt_nid, hda_nid_t nid)
+{
+	int pwr;
+
+	/* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+	 * thus pins could only choose converter 0 for use. Make sure the
+	 * converters are in correct power state
+	 */
+	if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
+		snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+	if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+				    AC_PWRST_D0);
+		msleep(40);
+		pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+		pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+		codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
+	}
+}
+
+/* Assure the pin select the right convetor */
+static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
+			struct hdmi_spec_per_pin *per_pin)
+{
+	hda_nid_t pin_nid = per_pin->pin_nid;
+	int mux_idx, curr;
+
+	mux_idx = per_pin->mux_idx;
+	curr = snd_hda_codec_read(codec, pin_nid, 0,
+					  AC_VERB_GET_CONNECT_SEL, 0);
+	if (curr != mux_idx)
+		snd_hda_codec_write_cache(codec, pin_nid, 0,
+					    AC_VERB_SET_CONNECT_SEL,
+					    mux_idx);
+}
+
+/* get the mux index for the converter of the pins
+ * converter's mux index is the same for all pins on Intel platform
+ */
+static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
+			hda_nid_t cvt_nid)
+{
+	int i;
+
+	for (i = 0; i < spec->num_cvts; i++)
+		if (spec->cvt_nids[i] == cvt_nid)
+			return i;
+	return -EINVAL;
+}
+
+/* Intel HDMI workaround to fix audio routing issue:
+ * For some Intel display codecs, pins share the same connection list.
+ * So a conveter can be selected by multiple pins and playback on any of these
+ * pins will generate sound on the external display, because audio flows from
+ * the same converter to the display pipeline. Also muting one pin may make
+ * other pins have no sound output.
+ * So this function assures that an assigned converter for a pin is not selected
+ * by any other pins.
+ */
+static void intel_not_share_assigned_cvt(struct hda_codec *codec,
+					 hda_nid_t pin_nid,
+					 int dev_id, int mux_idx)
+{
+	struct hdmi_spec *spec = codec->spec;
+	hda_nid_t nid;
+	int cvt_idx, curr;
+	struct hdmi_spec_per_cvt *per_cvt;
+	struct hdmi_spec_per_pin *per_pin;
+	int pin_idx;
+
+	/* configure the pins connections */
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		int dev_id_saved;
+		int dev_num;
+
+		per_pin = get_pin(spec, pin_idx);
+		/*
+		 * pin not connected to monitor
+		 * no need to operate on it
+		 */
+		if (!per_pin->pcm)
+			continue;
+
+		if ((per_pin->pin_nid == pin_nid) &&
+			(per_pin->dev_id == dev_id))
+			continue;
+
+		/*
+		 * if per_pin->dev_id >= dev_num,
+		 * snd_hda_get_dev_select() will fail,
+		 * and the following operation is unpredictable.
+		 * So skip this situation.
+		 */
+		dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
+		if (per_pin->dev_id >= dev_num)
+			continue;
+
+		nid = per_pin->pin_nid;
+
+		/*
+		 * Calling this function should not impact
+		 * on the device entry selection
+		 * So let's save the dev id for each pin,
+		 * and restore it when return
+		 */
+		dev_id_saved = snd_hda_get_dev_select(codec, nid);
+		snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
+		curr = snd_hda_codec_read(codec, nid, 0,
+					  AC_VERB_GET_CONNECT_SEL, 0);
+		if (curr != mux_idx) {
+			snd_hda_set_dev_select(codec, nid, dev_id_saved);
+			continue;
+		}
+
+
+		/* choose an unassigned converter. The conveters in the
+		 * connection list are in the same order as in the codec.
+		 */
+		for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+			per_cvt = get_cvt(spec, cvt_idx);
+			if (!per_cvt->assigned) {
+				codec_dbg(codec,
+					  "choose cvt %d for pin NID 0x%x\n",
+					  cvt_idx, nid);
+				snd_hda_codec_write_cache(codec, nid, 0,
+					    AC_VERB_SET_CONNECT_SEL,
+					    cvt_idx);
+				break;
+			}
+		}
+		snd_hda_set_dev_select(codec, nid, dev_id_saved);
+	}
+}
+
+/* A wrapper of intel_not_share_asigned_cvt() */
+static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
+			hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
+{
+	int mux_idx;
+	struct hdmi_spec *spec = codec->spec;
+
+	/* On Intel platform, the mapping of converter nid to
+	 * mux index of the pins are always the same.
+	 * The pin nid may be 0, this means all pins will not
+	 * share the converter.
+	 */
+	mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
+	if (mux_idx >= 0)
+		intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
+}
+
+/* setup_stream ops override for HSW+ */
+static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+				 hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+				 int format)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
+	struct hdmi_spec_per_pin *per_pin;
+	int res;
+
+	if (pin_idx < 0)
+		per_pin = NULL;
+	else
+		per_pin = get_pin(spec, pin_idx);
+
+	haswell_verify_D0(codec, cvt_nid, pin_nid);
+
+	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+		silent_stream_set_kae(codec, per_pin, false);
+		/* wait for pending transfers in codec to clear */
+		usleep_range(100, 200);
+	}
+
+	res = snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+					stream_tag, format);
+
+	if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+		usleep_range(100, 200);
+		silent_stream_set_kae(codec, per_pin, true);
+	}
+
+	return res;
+}
+
+/* pin_cvt_fixup ops override for HSW+ and VLV+ */
+static void i915_pin_cvt_fixup(struct hda_codec *codec,
+			       struct hdmi_spec_per_pin *per_pin,
+			       hda_nid_t cvt_nid)
+{
+	if (per_pin) {
+		haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
+		snd_hda_set_dev_select(codec, per_pin->pin_nid,
+			       per_pin->dev_id);
+		intel_verify_pin_cvt_connect(codec, per_pin);
+		intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+				     per_pin->dev_id, per_pin->mux_idx);
+	} else {
+		intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
+	}
+}
+
+static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	bool silent_streams = false;
+	int pin_idx, res;
+
+	res = snd_hda_hdmi_generic_suspend(codec);
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+		if (per_pin->silent_stream) {
+			silent_streams = true;
+			break;
+		}
+	}
+
+	if (silent_streams) {
+		/*
+		 * stream-id should remain programmed when codec goes
+		 * to runtime suspend
+		 */
+		codec->no_stream_clean_at_suspend = 1;
+
+		/*
+		 * the system might go to S3, in which case keep-alive
+		 * must be reprogrammed upon resume
+		 */
+		codec->forced_resume = 1;
+
+		codec_dbg(codec, "HDMI: KAE active at suspend\n");
+	} else {
+		codec->no_stream_clean_at_suspend = 0;
+		codec->forced_resume = 0;
+	}
+
+	return res;
+}
+
+static int i915_adlp_hdmi_resume(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int pin_idx, res;
+
+	res = snd_hda_hdmi_generic_resume(codec);
+
+	/* KAE not programmed at suspend, nothing to do here */
+	if (!codec->no_stream_clean_at_suspend)
+		return res;
+
+	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+		/*
+		 * If system was in suspend with monitor connected,
+		 * the codec setting may have been lost. Re-enable
+		 * keep-alive.
+		 */
+		if (per_pin->silent_stream) {
+			unsigned int param;
+
+			param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
+						   AC_VERB_GET_CONV, 0);
+			if (!param) {
+				codec_dbg(codec, "HDMI: KAE: restore stream id\n");
+				silent_stream_enable_i915(codec, per_pin);
+			}
+
+			param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
+						   AC_VERB_GET_DIGI_CONVERT_1, 0);
+			if (!(param & (AC_DIG3_KAE << 16))) {
+				codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
+				silent_stream_set_kae(codec, per_pin, true);
+			}
+		}
+	}
+
+	return res;
+}
+
+/* precondition and allocation for Intel codecs */
+static int alloc_intel_hdmi(struct hda_codec *codec)
+{
+	int err;
+
+	/* requires i915 binding */
+	if (!codec->bus->core.audio_component) {
+		codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+		/* set probe_id here to prevent generic fallback binding */
+		codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
+		return -ENODEV;
+	}
+
+	err = snd_hda_hdmi_generic_alloc(codec);
+	if (err < 0)
+		return err;
+	/* no need to handle unsol events */
+	codec->patch_ops.unsol_event = NULL;
+	return 0;
+}
+
+/* parse and post-process for Intel codecs */
+static int parse_intel_hdmi(struct hda_codec *codec)
+{
+	int err, retries = 3;
+
+	do {
+		err = snd_hda_hdmi_parse_codec(codec);
+	} while (err < 0 && retries--);
+
+	if (err < 0)
+		return err;
+
+	snd_hda_hdmi_generic_init_per_pins(codec);
+	register_i915_notifier(codec);
+	return 0;
+}
+
+/* Intel Haswell and onwards; audio component with eld notifier */
+static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
+				 const int *port_map, int port_num, int dev_num,
+				 bool send_silent_stream)
+{
+	struct hdmi_spec *spec;
+	int err;
+
+	err = alloc_intel_hdmi(codec);
+	if (err < 0)
+		return err;
+	spec = codec->spec;
+	codec->dp_mst = true;
+	spec->vendor_nid = vendor_nid;
+	spec->port_map = port_map;
+	spec->port_num = port_num;
+	spec->intel_hsw_fixup = true;
+	spec->dev_num = dev_num;
+
+	intel_haswell_enable_all_pins(codec, true);
+	intel_haswell_fixup_enable_dp12(codec);
+
+	codec->display_power_control = 1;
+
+	codec->patch_ops.set_power_state = haswell_set_power_state;
+	codec->depop_delay = 0;
+	codec->auto_runtime_pm = 1;
+
+	spec->ops.setup_stream = i915_hsw_setup_stream;
+	spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+	spec->ops.silent_stream = i915_set_silent_stream;
+
+	/*
+	 * Enable silent stream feature, if it is enabled via
+	 * module param or Kconfig option
+	 */
+	if (send_silent_stream)
+		spec->silent_stream_type = SILENT_STREAM_I915;
+
+	return parse_intel_hdmi(codec);
+}
+
+static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+{
+	return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
+				     enable_silent_stream);
+}
+
+static int patch_i915_glk_hdmi(struct hda_codec *codec)
+{
+	/*
+	 * Silent stream calls audio component .get_power() from
+	 * .pin_eld_notify(). On GLK this will deadlock in i915 due
+	 * to the audio vs. CDCLK workaround.
+	 */
+	return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
+}
+
+static int patch_i915_icl_hdmi(struct hda_codec *codec)
+{
+	/*
+	 * pin to port mapping table where the value indicate the pin number and
+	 * the index indicate the port number.
+	 */
+	static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
+
+	return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
+				     enable_silent_stream);
+}
+
+static int patch_i915_tgl_hdmi(struct hda_codec *codec)
+{
+	/*
+	 * pin to port mapping table where the value indicate the pin number and
+	 * the index indicate the port number.
+	 */
+	static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+	return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
+				     enable_silent_stream);
+}
+
+static int patch_i915_adlp_hdmi(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int res;
+
+	res = patch_i915_tgl_hdmi(codec);
+	if (!res) {
+		spec = codec->spec;
+
+		if (spec->silent_stream_type) {
+			spec->silent_stream_type = SILENT_STREAM_KAE;
+
+			codec->patch_ops.resume = i915_adlp_hdmi_resume;
+			codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
+		}
+	}
+
+	return res;
+}
+
+/* Intel Baytrail and Braswell; with eld notifier */
+static int patch_i915_byt_hdmi(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int err;
+
+	err = alloc_intel_hdmi(codec);
+	if (err < 0)
+		return err;
+	spec = codec->spec;
+
+	/* For Valleyview/Cherryview, only the display codec is in the display
+	 * power well and can use link_power ops to request/release the power.
+	 */
+	codec->display_power_control = 1;
+
+	codec->depop_delay = 0;
+	codec->auto_runtime_pm = 1;
+
+	spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
+	return parse_intel_hdmi(codec);
+}
+
+/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
+static int patch_i915_cpt_hdmi(struct hda_codec *codec)
+{
+	int err;
+
+	err = alloc_intel_hdmi(codec);
+	if (err < 0)
+		return err;
+	return parse_intel_hdmi(codec);
+}
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_intelhdmi[] = {
+HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",	patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI",	patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",	patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",	patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",	patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",	patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",	patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",	patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",	patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI",	patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI",	patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",	patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",	patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI",	patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI",	patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI",	patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI",	patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI",	patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI",	patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",	patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI",	patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI",	patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI",	patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI",	patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI",	patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI",	patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",	patch_i915_byt_hdmi),
+HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",	patch_i915_byt_hdmi),
+{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_intelhdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver intelhdmi_driver = {
+	.id = snd_hda_id_intelhdmi,
+};
+
+module_hda_codec_driver(intelhdmi_driver);
diff --git a/sound/hda/codecs/hdmi/nvhdmi-mcp.c b/sound/hda/codecs/hdmi/nvhdmi-mcp.c
new file mode 100644
index 000000000000..67e187a351d7
--- /dev/null
+++ b/sound/hda/codecs/hdmi/nvhdmi-mcp.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Legacy Nvidia HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+#define Nv_VERB_SET_Channel_Allocation          0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
+#define Nv_VERB_SET_Audio_Protection_On         0xF98
+#define Nv_VERB_SET_Audio_Protection_Off        0xF99
+
+#define nvhdmi_master_con_nid_7x	0x04
+#define nvhdmi_master_pin_nid_7x	0x05
+
+static const hda_nid_t nvhdmi_con_nids_7x[4] = {
+	/*front, rear, clfe, rear_surr */
+	0x6, 0x8, 0xa, 0xc,
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
+	/* set audio protect on */
+	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+	/* enable digital output on pin widget */
+	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{} /* terminator */
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
+	/* set audio protect on */
+	{ 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+	/* enable digital output on pin widget */
+	{ 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{ 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+	{} /* terminator */
+};
+
+static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
+	return 0;
+}
+
+static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
+{
+	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
+	return 0;
+}
+
+static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
+						    int channels)
+{
+	unsigned int chanmask;
+	int chan = channels ? (channels - 1) : 1;
+
+	switch (channels) {
+	default:
+	case 0:
+	case 2:
+		chanmask = 0x00;
+		break;
+	case 4:
+		chanmask = 0x08;
+		break;
+	case 6:
+		chanmask = 0x0b;
+		break;
+	case 8:
+		chanmask = 0x13;
+		break;
+	}
+
+	/* Set the audio infoframe channel allocation and checksum fields.  The
+	 * channel count is computed implicitly by the hardware.
+	 */
+	snd_hda_codec_write(codec, 0x1, 0,
+			Nv_VERB_SET_Channel_Allocation, chanmask);
+
+	snd_hda_codec_write(codec, 0x1, 0,
+			Nv_VERB_SET_Info_Frame_Checksum,
+			(0x71 - chan - chanmask));
+}
+
+static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   struct snd_pcm_substream *substream)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int i;
+
+	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
+			0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+	for (i = 0; i < 4; i++) {
+		/* set the stream id */
+		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+				AC_VERB_SET_CHANNEL_STREAMID, 0);
+		/* set the stream format */
+		snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+				AC_VERB_SET_STREAM_FORMAT, 0);
+	}
+
+	/* The audio hardware sends a channel count of 0x7 (8ch) when all the
+	 * streams are disabled.
+	 */
+	nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
+
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     struct snd_pcm_substream *substream)
+{
+	int chs;
+	unsigned int dataDCC2, channel_id;
+	int i;
+	struct hdmi_spec *spec = codec->spec;
+	struct hda_spdif_out *spdif;
+	struct hdmi_spec_per_cvt *per_cvt;
+
+	mutex_lock(&codec->spdif_mutex);
+	per_cvt = get_cvt(spec, 0);
+	spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
+
+	chs = substream->runtime->channels;
+
+	dataDCC2 = 0x2;
+
+	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+	if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
+		snd_hda_codec_write(codec,
+				nvhdmi_master_con_nid_7x,
+				0,
+				AC_VERB_SET_DIGI_CONVERT_1,
+				spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
+
+	/* set the stream id */
+	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+			AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+	/* set the stream format */
+	snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+			AC_VERB_SET_STREAM_FORMAT, format);
+
+	/* turn on again (if needed) */
+	/* enable and set the channel status audio/data flag */
+	if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
+		snd_hda_codec_write(codec,
+				nvhdmi_master_con_nid_7x,
+				0,
+				AC_VERB_SET_DIGI_CONVERT_1,
+				spdif->ctls & 0xff);
+		snd_hda_codec_write(codec,
+				nvhdmi_master_con_nid_7x,
+				0,
+				AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (chs == 2)
+			channel_id = 0;
+		else
+			channel_id = i * 2;
+
+		/* turn off SPDIF once;
+		 *otherwise the IEC958 bits won't be updated
+		 */
+		if (codec->spdif_status_reset &&
+		(spdif->ctls & AC_DIG1_ENABLE))
+			snd_hda_codec_write(codec,
+				nvhdmi_con_nids_7x[i],
+				0,
+				AC_VERB_SET_DIGI_CONVERT_1,
+				spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
+		/* set the stream id */
+		snd_hda_codec_write(codec,
+				nvhdmi_con_nids_7x[i],
+				0,
+				AC_VERB_SET_CHANNEL_STREAMID,
+				(stream_tag << 4) | channel_id);
+		/* set the stream format */
+		snd_hda_codec_write(codec,
+				nvhdmi_con_nids_7x[i],
+				0,
+				AC_VERB_SET_STREAM_FORMAT,
+				format);
+		/* turn on again (if needed) */
+		/* enable and set the channel status audio/data flag */
+		if (codec->spdif_status_reset &&
+		(spdif->ctls & AC_DIG1_ENABLE)) {
+			snd_hda_codec_write(codec,
+					nvhdmi_con_nids_7x[i],
+					0,
+					AC_VERB_SET_DIGI_CONVERT_1,
+					spdif->ctls & 0xff);
+			snd_hda_codec_write(codec,
+					nvhdmi_con_nids_7x[i],
+					0,
+					AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+		}
+	}
+
+	nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
+
+	mutex_unlock(&codec->spdif_mutex);
+	return 0;
+}
+
+static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = nvhdmi_master_con_nid_7x,
+	.rates = SUPPORTED_RATES,
+	.maxbps = SUPPORTED_MAXBPS,
+	.formats = SUPPORTED_FORMATS,
+	.ops = {
+		.open = snd_hda_hdmi_simple_pcm_open,
+		.close = nvhdmi_8ch_7x_pcm_close,
+		.prepare = nvhdmi_8ch_7x_pcm_prepare
+	},
+};
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
+				    nvhdmi_master_pin_nid_7x);
+	if (err < 0)
+		return err;
+
+	codec->patch_ops.init = nvhdmi_7x_init_2ch;
+	/* override the PCM rates, etc, as the codec doesn't give full list */
+	spec = codec->spec;
+	spec->pcm_playback.rates = SUPPORTED_RATES;
+	spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
+	spec->pcm_playback.formats = SUPPORTED_FORMATS;
+	spec->nv_dp_workaround = true;
+	return 0;
+}
+
+static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_hdmi_simple_build_pcms(codec);
+	if (!err) {
+		struct hda_pcm *info = get_pcm_rec(spec, 0);
+
+		info->own_chmap = true;
+	}
+	return err;
+}
+
+static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	struct hda_pcm *info;
+	struct snd_pcm_chmap *chmap;
+	int err;
+
+	err = snd_hda_hdmi_simple_build_controls(codec);
+	if (err < 0)
+		return err;
+
+	/* add channel maps */
+	info = get_pcm_rec(spec, 0);
+	err = snd_pcm_add_chmap_ctls(info->pcm,
+				     SNDRV_PCM_STREAM_PLAYBACK,
+				     snd_pcm_alt_chmaps, 8, 0, &chmap);
+	if (err < 0)
+		return err;
+	switch (codec->preset->vendor_id) {
+	case 0x10de0002:
+	case 0x10de0003:
+	case 0x10de0005:
+	case 0x10de0006:
+		chmap->channel_mask = (1U << 2) | (1U << 8);
+		break;
+	case 0x10de0007:
+		chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
+	}
+	return 0;
+}
+
+static const unsigned int channels_2_6_8[] = {
+	2, 6, 8
+};
+
+static const unsigned int channels_2_8[] = {
+	2, 8
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
+	.count = ARRAY_SIZE(channels_2_6_8),
+	.list = channels_2_6_8,
+	.mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
+	.count = ARRAY_SIZE(channels_2_8),
+	.list = channels_2_8,
+	.mask = 0,
+};
+
+static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int err;
+
+	err = patch_nvhdmi_2ch(codec);
+	if (err < 0)
+		return err;
+	spec = codec->spec;
+	spec->multiout.max_channels = 8;
+	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
+	codec->patch_ops.init = nvhdmi_7x_init_8ch;
+	codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
+	codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
+
+	switch (codec->preset->vendor_id) {
+	case 0x10de0002:
+	case 0x10de0003:
+	case 0x10de0005:
+	case 0x10de0006:
+		spec->hw_constraints_channels = &hw_constraints_2_8_channels;
+		break;
+	case 0x10de0007:
+		spec->hw_constraints_channels = &hw_constraints_2_6_8_channels;
+		break;
+	default:
+		break;
+	}
+
+	/* Initialize the audio infoframe channel mask and checksum to something
+	 * valid
+	 */
+	nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = {
+HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",	patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",	patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",	patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",	patch_nvhdmi_2ch),
+{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Legacy Nvidia HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver nvhdmi_mcp_driver = {
+	.id = snd_hda_id_nvhdmi_mcp,
+};
+
+module_hda_codec_driver(nvhdmi_mcp_driver);
diff --git a/sound/hda/codecs/hdmi/nvhdmi.c b/sound/hda/codecs/hdmi/nvhdmi.c
new file mode 100644
index 000000000000..2add5f59daf5
--- /dev/null
+++ b/sound/hda/codecs/hdmi/nvhdmi.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Nvidia HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+/*
+ * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
+ * - 0x10de0015
+ * - 0x10de0040
+ */
+static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
+		struct hdac_cea_channel_speaker_allocation *cap, int channels)
+{
+	if (cap->ca_index == 0x00 && channels == 2)
+		return SNDRV_CTL_TLVT_CHMAP_FIXED;
+
+	/* If the speaker allocation matches the channel count, it is OK. */
+	if (cap->channels != channels)
+		return -1;
+
+	/* all channels are remappable freely */
+	return SNDRV_CTL_TLVT_CHMAP_VAR;
+}
+
+static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
+		int ca, int chs, unsigned char *map)
+{
+	if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
+		return -EINVAL;
+
+	return 0;
+}
+
+/* map from pin NID to port; port is 0-based */
+/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
+static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
+{
+	return pin_nid - 4;
+}
+
+/* reverse-map from port to pin NID: see above */
+static int nvhdmi_port2pin(struct hda_codec *codec, int port)
+{
+	return port + 4;
+}
+
+static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
+	.pin2port = nvhdmi_pin2port,
+	.pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify,
+	.master_bind = snd_hda_hdmi_acomp_master_bind,
+	.master_unbind = snd_hda_hdmi_acomp_master_unbind,
+};
+
+static int patch_nvhdmi(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int err;
+
+	err = snd_hda_hdmi_generic_alloc(codec);
+	if (err < 0)
+		return err;
+	codec->dp_mst = true;
+
+	spec = codec->spec;
+
+	err = snd_hda_hdmi_parse_codec(codec);
+	if (err < 0) {
+		snd_hda_hdmi_generic_spec_free(codec);
+		return err;
+	}
+
+	snd_hda_hdmi_generic_init_per_pins(codec);
+
+	spec->dyn_pin_out = true;
+
+	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+		nvhdmi_chmap_cea_alloc_validate_get_type;
+	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+	spec->nv_dp_workaround = true;
+
+	codec->link_down_at_suspend = 1;
+
+	snd_hda_hdmi_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
+
+	return 0;
+}
+
+static int patch_nvhdmi_legacy(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int err;
+
+	err = patch_generic_hdmi(codec);
+	if (err)
+		return err;
+
+	spec = codec->spec;
+	spec->dyn_pin_out = true;
+
+	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+		nvhdmi_chmap_cea_alloc_validate_get_type;
+	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+	spec->nv_dp_workaround = true;
+
+	codec->link_down_at_suspend = 1;
+
+	return 0;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_nvhdmi[] = {
+HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP",	patch_nvhdmi_legacy),
+/* 17 is known to be absent */
+HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP",	patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP",	patch_nvhdmi),
+{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver nvhdmi_driver = {
+	.id = snd_hda_id_nvhdmi,
+};
+
+module_hda_codec_driver(nvhdmi_driver);
diff --git a/sound/hda/codecs/hdmi/simplehdmi.c b/sound/hda/codecs/hdmi/simplehdmi.c
new file mode 100644
index 000000000000..87ea997a6d3b
--- /dev/null
+++ b/sound/hda/codecs/hdmi/simplehdmi.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Non-generic simple HDMI codec support
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "hdmi_local.h"
+#include "hda_jack.h"
+
+int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	struct hda_pcm *info;
+	unsigned int chans;
+	struct hda_pcm_stream *pstr;
+	struct hdmi_spec_per_cvt *per_cvt;
+
+	per_cvt = get_cvt(spec, 0);
+	chans = get_wcaps(codec, per_cvt->cvt_nid);
+	chans = get_wcaps_channels(chans);
+
+	info = snd_hda_codec_pcm_new(codec, "HDMI 0");
+	if (!info)
+		return -ENOMEM;
+	spec->pcm_rec[0].pcm = info;
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
+	pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+	*pstr = spec->pcm_playback;
+	pstr->nid = per_cvt->cvt_nid;
+	if (pstr->channels_max <= 2 && chans && chans <= 16)
+		pstr->channels_max = chans;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_build_pcms, "SND_HDA_CODEC_HDMI");
+
+/* unsolicited event for jack sensing */
+void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec,
+				     unsigned int res)
+{
+	snd_hda_jack_set_dirty_all(codec);
+	snd_hda_jack_report_sync(codec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_unsol_event, "SND_HDA_CODEC_HDMI");
+
+static void free_hdmi_jack_priv(struct snd_jack *jack)
+{
+	struct hdmi_pcm *pcm = jack->private_data;
+
+	pcm->jack = NULL;
+}
+
+static int simple_hdmi_build_jack(struct hda_codec *codec)
+{
+	char hdmi_str[32] = "HDMI/DP";
+	struct hdmi_spec *spec = codec->spec;
+	struct snd_jack *jack;
+	struct hdmi_pcm *pcmp = get_hdmi_pcm(spec, 0);
+	int pcmdev = pcmp->pcm->device;
+	int err;
+
+	if (pcmdev > 0)
+		sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+
+	err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
+			   true, false);
+	if (err < 0)
+		return err;
+
+	pcmp->jack = jack;
+	jack->private_data = pcmp;
+	jack->private_free = free_hdmi_jack_priv;
+	return 0;
+}
+
+int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	struct hdmi_spec_per_cvt *per_cvt;
+	int err;
+
+	per_cvt = get_cvt(spec, 0);
+	err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
+					  per_cvt->cvt_nid,
+					  HDA_PCM_TYPE_HDMI);
+	if (err < 0)
+		return err;
+	return simple_hdmi_build_jack(codec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_build_controls, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_simple_init(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
+	hda_nid_t pin = per_pin->pin_nid;
+
+	snd_hda_codec_write(codec, pin, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+	/* some codecs require to unmute the pin */
+	if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_OUT_UNMUTE);
+	snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_init, "SND_HDA_CODEC_HDMI");
+
+void snd_hda_hdmi_simple_free(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	snd_array_free(&spec->pins);
+	snd_array_free(&spec->cvts);
+	kfree(spec);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_free, "SND_HDA_CODEC_HDMI");
+
+int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo,
+				 struct hda_codec *codec,
+				 struct snd_pcm_substream *substream)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	if (spec->hw_constraints_channels) {
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_CHANNELS,
+				spec->hw_constraints_channels);
+	} else {
+		snd_pcm_hw_constraint_step(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+	}
+
+	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_pcm_open, "SND_HDA_CODEC_HDMI");
+
+static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+				       struct hda_codec *codec,
+				       unsigned int stream_tag,
+				       unsigned int format,
+				       struct snd_pcm_substream *substream)
+{
+	struct hdmi_spec *spec = codec->spec;
+
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+					     stream_tag, format, substream);
+}
+
+static const struct hda_pcm_stream simple_pcm_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.ops = {
+		.open = snd_hda_hdmi_simple_pcm_open,
+		.close = simple_playback_pcm_close,
+		.prepare = simple_playback_pcm_prepare
+	},
+};
+
+static const struct hda_codec_ops simple_hdmi_patch_ops = {
+	.build_controls = snd_hda_hdmi_simple_build_controls,
+	.build_pcms = snd_hda_hdmi_simple_build_pcms,
+	.init = snd_hda_hdmi_simple_init,
+	.free = snd_hda_hdmi_simple_free,
+	.unsol_event = snd_hda_hdmi_simple_unsol_event,
+};
+
+int patch_simple_hdmi(struct hda_codec *codec,
+		      hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+	struct hdmi_spec *spec;
+	struct hdmi_spec_per_cvt *per_cvt;
+	struct hdmi_spec_per_pin *per_pin;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+
+	spec->codec = codec;
+	codec->spec = spec;
+	snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), 1);
+	snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), 1);
+
+	spec->multiout.num_dacs = 0;  /* no analog */
+	spec->multiout.max_channels = 2;
+	spec->multiout.dig_out_nid = cvt_nid;
+	spec->num_cvts = 1;
+	spec->num_pins = 1;
+	per_pin = snd_array_new(&spec->pins);
+	per_cvt = snd_array_new(&spec->cvts);
+	if (!per_pin || !per_cvt) {
+		snd_hda_hdmi_simple_free(codec);
+		return -ENOMEM;
+	}
+	per_cvt->cvt_nid = cvt_nid;
+	per_pin->pin_nid = pin_nid;
+	spec->pcm_playback = simple_pcm_playback;
+
+	codec->patch_ops = simple_hdmi_patch_ops;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(patch_simple_hdmi, "SND_HDA_CODEC_HDMI");
+
+/* VIA HDMI Implementation */
+#define VIAHDMI_CVT_NID	0x02	/* audio converter1 */
+#define VIAHDMI_PIN_NID	0x03	/* HDMI output pin1 */
+
+static int patch_via_hdmi(struct hda_codec *codec)
+{
+	return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_simplehdmi[] = {
+HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",	patch_via_hdmi),
+HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",	patch_via_hdmi),
+{} /* terminator */
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simple HDMI HD-audio codec support");
+
+static struct hda_codec_driver simplehdmi_driver = {
+	.id = snd_hda_id_simplehdmi,
+};
+
+module_hda_codec_driver(simplehdmi_driver);
diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c
new file mode 100644
index 000000000000..c13a63788799
--- /dev/null
+++ b/sound/hda/codecs/hdmi/tegrahdmi.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Nvidia Tegra HDMI codec support
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hdmi_local.h"
+
+/*
+ * The HDA codec on NVIDIA Tegra contains two scratch registers that are
+ * accessed using vendor-defined verbs. These registers can be used for
+ * interoperability between the HDA and HDMI drivers.
+ */
+
+/* Audio Function Group node */
+#define NVIDIA_AFG_NID 0x01
+
+/*
+ * The SCRATCH0 register is used to notify the HDMI codec of changes in audio
+ * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
+ * be raised in the HDMI codec. The remainder of the bits is arbitrary. This
+ * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
+ * additional bit (at position 30) to signal the validity of the format.
+ *
+ * | 31      | 30    | 29  16 | 15   0 |
+ * +---------+-------+--------+--------+
+ * | TRIGGER | VALID | UNUSED | FORMAT |
+ * +-----------------------------------|
+ *
+ * Note that for the trigger bit to take effect it needs to change value
+ * (i.e. it needs to be toggled). The trigger bit is not applicable from
+ * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
+ * trigger to hdmi.
+ */
+#define NVIDIA_SET_HOST_INTR		0xf80
+#define NVIDIA_GET_SCRATCH0		0xfa6
+#define NVIDIA_SET_SCRATCH0_BYTE0	0xfa7
+#define NVIDIA_SET_SCRATCH0_BYTE1	0xfa8
+#define NVIDIA_SET_SCRATCH0_BYTE2	0xfa9
+#define NVIDIA_SET_SCRATCH0_BYTE3	0xfaa
+#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
+#define NVIDIA_SCRATCH_VALID   (1 << 6)
+
+#define NVIDIA_GET_SCRATCH1		0xfab
+#define NVIDIA_SET_SCRATCH1_BYTE0	0xfac
+#define NVIDIA_SET_SCRATCH1_BYTE1	0xfad
+#define NVIDIA_SET_SCRATCH1_BYTE2	0xfae
+#define NVIDIA_SET_SCRATCH1_BYTE3	0xfaf
+
+/*
+ * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
+ * the format is invalidated so that the HDMI codec can be disabled.
+ */
+static void tegra_hdmi_set_format(struct hda_codec *codec,
+				  hda_nid_t cvt_nid,
+				  unsigned int format)
+{
+	unsigned int value;
+	unsigned int nid = NVIDIA_AFG_NID;
+	struct hdmi_spec *spec = codec->spec;
+
+	/*
+	 * Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
+	 * This resulted in moving scratch registers from audio function
+	 * group to converter widget context. So CVT NID should be used for
+	 * scratch register read/write for DP MST supported Tegra HDA codec.
+	 */
+	if (codec->dp_mst)
+		nid = cvt_nid;
+
+	/* bits [31:30] contain the trigger and valid bits */
+	value = snd_hda_codec_read(codec, nid, 0,
+				   NVIDIA_GET_SCRATCH0, 0);
+	value = (value >> 24) & 0xff;
+
+	/* bits [15:0] are used to store the HDA format */
+	snd_hda_codec_write(codec, nid, 0,
+			    NVIDIA_SET_SCRATCH0_BYTE0,
+			    (format >> 0) & 0xff);
+	snd_hda_codec_write(codec, nid, 0,
+			    NVIDIA_SET_SCRATCH0_BYTE1,
+			    (format >> 8) & 0xff);
+
+	/* bits [16:24] are unused */
+	snd_hda_codec_write(codec, nid, 0,
+			    NVIDIA_SET_SCRATCH0_BYTE2, 0);
+
+	/*
+	 * Bit 30 signals that the data is valid and hence that HDMI audio can
+	 * be enabled.
+	 */
+	if (format == 0)
+		value &= ~NVIDIA_SCRATCH_VALID;
+	else
+		value |= NVIDIA_SCRATCH_VALID;
+
+	if (spec->hdmi_intr_trig_ctrl) {
+		/*
+		 * For Tegra HDA Codec design from TEGRA234 onwards, the
+		 * Interrupt to hdmi driver is triggered by writing
+		 * non-zero values to verb 0xF80 instead of 31st bit of
+		 * scratch register.
+		 */
+		snd_hda_codec_write(codec, nid, 0,
+				NVIDIA_SET_SCRATCH0_BYTE3, value);
+		snd_hda_codec_write(codec, nid, 0,
+				NVIDIA_SET_HOST_INTR, 0x1);
+	} else {
+		/*
+		 * Whenever the 31st trigger bit is toggled, an interrupt is raised
+		 * in the HDMI codec. The HDMI driver will use that as trigger
+		 * to update its configuration.
+		 */
+		value ^= NVIDIA_SCRATCH_TRIGGER;
+
+		snd_hda_codec_write(codec, nid, 0,
+				NVIDIA_SET_SCRATCH0_BYTE3, value);
+	}
+}
+
+static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
+				  struct hda_codec *codec,
+				  unsigned int stream_tag,
+				  unsigned int format,
+				  struct snd_pcm_substream *substream)
+{
+	int err;
+
+	err = snd_hda_hdmi_generic_pcm_prepare(hinfo, codec, stream_tag,
+					       format, substream);
+	if (err < 0)
+		return err;
+
+	/* notify the HDMI codec of the format change */
+	tegra_hdmi_set_format(codec, hinfo->nid, format);
+
+	return 0;
+}
+
+static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				  struct hda_codec *codec,
+				  struct snd_pcm_substream *substream)
+{
+	/* invalidate the format in the HDMI codec */
+	tegra_hdmi_set_format(codec, hinfo->nid, 0);
+
+	return snd_hda_hdmi_generic_pcm_cleanup(hinfo, codec, substream);
+}
+
+static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
+{
+	struct hdmi_spec *spec = codec->spec;
+	unsigned int i;
+
+	for (i = 0; i < spec->num_pins; i++) {
+		struct hda_pcm *pcm = get_pcm_rec(spec, i);
+
+		if (pcm->pcm_type == type)
+			return pcm;
+	}
+
+	return NULL;
+}
+
+static int tegra_hdmi_build_pcms(struct hda_codec *codec)
+{
+	struct hda_pcm_stream *stream;
+	struct hda_pcm *pcm;
+	int err;
+
+	err = snd_hda_hdmi_generic_build_pcms(codec);
+	if (err < 0)
+		return err;
+
+	pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
+	if (!pcm)
+		return -ENODEV;
+
+	/*
+	 * Override ->prepare() and ->cleanup() operations to notify the HDMI
+	 * codec about format changes.
+	 */
+	stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
+	stream->ops.prepare = tegra_hdmi_pcm_prepare;
+	stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
+
+	return 0;
+}
+
+/*
+ * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
+ * - 0x10de0015
+ * - 0x10de0040
+ */
+static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
+		struct hdac_cea_channel_speaker_allocation *cap, int channels)
+{
+	if (cap->ca_index == 0x00 && channels == 2)
+		return SNDRV_CTL_TLVT_CHMAP_FIXED;
+
+	/* If the speaker allocation matches the channel count, it is OK. */
+	if (cap->channels != channels)
+		return -1;
+
+	/* all channels are remappable freely */
+	return SNDRV_CTL_TLVT_CHMAP_VAR;
+}
+
+static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
+		int ca, int chs, unsigned char *map)
+{
+	if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int tegra_hdmi_init(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec = codec->spec;
+	int i, err;
+
+	err = snd_hda_hdmi_parse_codec(codec);
+	if (err < 0) {
+		snd_hda_hdmi_generic_spec_free(codec);
+		return err;
+	}
+
+	for (i = 0; i < spec->num_cvts; i++)
+		snd_hda_codec_write(codec, spec->cvt_nids[i], 0,
+					AC_VERB_SET_DIGI_CONVERT_1,
+					AC_DIG1_ENABLE);
+
+	snd_hda_hdmi_generic_init_per_pins(codec);
+
+	codec->depop_delay = 10;
+	codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
+	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+		nvhdmi_chmap_cea_alloc_validate_get_type;
+	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+
+	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+		nvhdmi_chmap_cea_alloc_validate_get_type;
+	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+	spec->nv_dp_workaround = true;
+
+	return 0;
+}
+
+static int patch_tegra_hdmi(struct hda_codec *codec)
+{
+	int err;
+
+	err = snd_hda_hdmi_generic_alloc(codec);
+	if (err < 0)
+		return err;
+
+	return tegra_hdmi_init(codec);
+}
+
+static int patch_tegra234_hdmi(struct hda_codec *codec)
+{
+	struct hdmi_spec *spec;
+	int err;
+
+	err = snd_hda_hdmi_generic_alloc(codec);
+	if (err < 0)
+		return err;
+
+	codec->dp_mst = true;
+	spec = codec->spec;
+	spec->dyn_pin_out = true;
+	spec->hdmi_intr_trig_ctrl = true;
+
+	return tegra_hdmi_init(codec);
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_tegrahdmi[] = {
+HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",	patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",	patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",	patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",	patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP",	patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP",	patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP",	patch_tegra234_hdmi),
+{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_tegrahdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nvidia Tegra HDMI HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
+
+static struct hda_codec_driver tegrahdmi_driver = {
+	.id = snd_hda_id_tegrahdmi,
+};
+
+module_hda_codec_driver(tegrahdmi_driver);
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index 68c31f5354b7..428aa5a06ead 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -689,10 +689,6 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
 void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
 			      struct hda_pcm_stream *hinfo);
 
-int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
-			 unsigned char *buf, int *eld_size,
-			 bool rev3_or_later);
-
 #ifdef CONFIG_SND_PROC_FS
 void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
 			     struct snd_info_buffer *buffer,
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 09/27] ALSA: hda: Introduce hda_codec_driver ops
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (7 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 08/27] ALSA: hda/hdmi: Split vendor codec drivers Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 10/27] ALSA: hda/generic: Rewrite to new probe method Takashi Iwai
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Until now, we use "patch_ops" embedded in hda_codec object for
defining the callbacks that are used in various places to manage
HD-audio codec.  But from the device driver POV, this should have been
rather the driver ops, instead of the callbacks in the codec object.

This patch defines the driver ops for HD-audio codec driver as the
replacement.  We reuse the same struct hda_codec_ops, and this is put
as hda_codec_driver.ops.  When the driver->ops callbacks are defined,
they are called primarily instead of codec->patch_ops callbacks.

With converting to the driver ops, there is no need to pass the ugly
patch_ops handling in hda_device_id tables.  That is, driver_data
field of hda_device_id becomes really optional and it can be used for
passing the codec-specific data (e.g. specifying a model).

The codec entries after the conversion should be with HDA_CODEC_ID()
and co, instead of the former HDA_CODEC_ENTRY().

Once after converting all codec drivers to use driver ops, we can get
rid of codec patch_ops.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/hda_codec.h    | 26 +++++++++++++++--
 sound/hda/common/bind.c      | 27 +++++++++++++----
 sound/hda/common/codec.c     | 56 ++++++++++++++++++++++++++----------
 sound/hda/common/hda_local.h | 11 +++++++
 sound/soc/codecs/hda.c       | 27 +++++++++++------
 sound/soc/codecs/hdac_hda.c  | 28 +++++++++++++-----
 6 files changed, 137 insertions(+), 38 deletions(-)

diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
index c1fe6290d04d..a725ac48c20c 100644
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -27,6 +27,7 @@ struct hda_beep;
 struct hda_codec;
 struct hda_pcm;
 struct hda_pcm_stream;
+struct hda_codec_ops;
 
 /*
  * codec bus
@@ -79,6 +80,17 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *);
 #define HDA_CODEC_ID_GENERIC_HDMI	0x00000101
 #define HDA_CODEC_ID_GENERIC		0x00000201
 
+#define HDA_CODEC_ID_REV_MODEL(_vid, _rev, _name, _model)	  \
+	{ .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
+	  .api_version = HDA_DEV_LEGACY, .driver_data = (_model) }
+#define HDA_CODEC_ID_MODEL(_vid, _name, _model)	  \
+	HDA_CODEC_ID_REV_MODEL(_vid, 0, _name, _model)
+#define HDA_CODEC_ID_REV(_vid, _rev, _name) \
+	HDA_CODEC_ID_REV_MODEL(_vid, _rev, _name, 0)
+#define HDA_CODEC_ID(_vid, _name) \
+	HDA_CODEC_ID_REV(_vid, 0, _name)
+
+/* old macros for patch_ops -- to be deprecated */
 #define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \
 	{ .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
 	  .api_version = HDA_DEV_LEGACY, \
@@ -89,8 +101,12 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *);
 struct hda_codec_driver {
 	struct hdac_driver core;
 	const struct hda_device_id *id;
+	const struct hda_codec_ops *ops;
 };
 
+#define hda_codec_to_driver(codec) \
+	container_of((codec)->core.dev.driver, struct hda_codec_driver, core.driver)
+
 int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
 			       struct module *owner);
 #define hda_codec_driver_register(drv) \
@@ -102,6 +118,8 @@ void hda_codec_driver_unregister(struct hda_codec_driver *drv);
 
 /* ops set by the preset patch */
 struct hda_codec_ops {
+	int (*probe)(struct hda_codec *codec, const struct hda_device_id *id);
+	void (*remove)(struct hda_codec *codec);
 	int (*build_controls)(struct hda_codec *codec);
 	int (*build_pcms)(struct hda_codec *codec);
 	int (*init)(struct hda_codec *codec);
@@ -184,7 +202,7 @@ struct hda_codec {
 	/* set by patch */
 	struct hda_codec_ops patch_ops;
 
-	/* PCM to create, set by patch_ops.build_pcms callback */
+	/* PCM to create, set by hda_codec_ops.build_pcms callback */
 	struct list_head pcm_list_head;
 	refcount_t pcm_ref;
 	wait_queue_head_t remove_sleep;
@@ -478,7 +496,11 @@ extern const struct dev_pm_ops hda_codec_driver_pm;
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
-	if (codec->patch_ops.check_power_status)
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
+	if (driver->ops && driver->ops->check_power_status)
+		return driver->ops->check_power_status(codec, nid);
+	else if (codec->patch_ops.check_power_status)
 		return codec->patch_ops.check_power_status(codec, nid);
 	return 0;
 }
diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c
index df8f88beddd0..56975178f533 100644
--- a/sound/hda/common/bind.c
+++ b/sound/hda/common/bind.c
@@ -42,6 +42,7 @@ static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *dr
 static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
 {
 	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 
 	/* ignore unsol events during shutdown */
 	if (codec->card->shutdown || codec->bus->shutdown)
@@ -51,7 +52,9 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
 	if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
 		return;
 
-	if (codec->patch_ops.unsol_event)
+	if (driver->ops && driver->ops->unsol_event)
+		driver->ops->unsol_event(codec, ev);
+	else if (codec->patch_ops.unsol_event)
 		codec->patch_ops.unsol_event(codec, ev);
 }
 
@@ -87,6 +90,7 @@ static int hda_codec_driver_probe(struct device *dev)
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 	struct module *owner = dev->driver->owner;
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	hda_codec_patch_t patch;
 	int err;
 
@@ -111,11 +115,17 @@ static int hda_codec_driver_probe(struct device *dev)
 		goto error;
 	}
 
-	patch = (hda_codec_patch_t)codec->preset->driver_data;
-	if (patch) {
-		err = patch(codec);
+	if (driver->ops && driver->ops->probe) {
+		err = driver->ops->probe(codec, codec->preset);
 		if (err < 0)
 			goto error_module_put;
+	} else {
+		patch = (hda_codec_patch_t)codec->preset->driver_data;
+		if (patch) {
+			err = patch(codec);
+			if (err < 0)
+				goto error_module_put;
+		}
 	}
 
 	err = snd_hda_codec_build_pcms(codec);
@@ -136,7 +146,9 @@ static int hda_codec_driver_probe(struct device *dev)
 	return 0;
 
  error_module:
-	if (codec->patch_ops.free)
+	if (driver->ops && driver->ops->remove)
+		driver->ops->remove(codec);
+	else if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
  error_module_put:
 	module_put(owner);
@@ -150,6 +162,7 @@ static int hda_codec_driver_probe(struct device *dev)
 static int hda_codec_driver_remove(struct device *dev)
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 
 	if (codec->bus->core.ext_ops) {
 		if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
@@ -163,7 +176,9 @@ static int hda_codec_driver_remove(struct device *dev)
 		wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
 	snd_power_sync_ref(codec->bus->card);
 
-	if (codec->patch_ops.free)
+	if (driver->ops && driver->ops->remove)
+		driver->ops->remove(codec);
+	else if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
 	snd_hda_codec_cleanup_for_unbind(codec);
 	codec->preset = NULL;
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index cb72e9655c8a..8899be764d68 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -1114,6 +1114,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 				u32 stream_tag,
 				int channel_id, int format)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	struct hda_codec *c;
 	struct hda_cvt_setup *p;
 	int type;
@@ -1129,7 +1130,9 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 	if (!p)
 		return;
 
-	if (codec->patch_ops.stream_pm)
+	if (driver->ops && driver->ops->stream_pm)
+		driver->ops->stream_pm(codec, nid, true);
+	else if (codec->patch_ops.stream_pm)
 		codec->patch_ops.stream_pm(codec, nid, true);
 	if (codec->pcm_format_first)
 		update_pcm_format(codec, p, nid, format);
@@ -1190,7 +1193,9 @@ EXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream);
 static void really_cleanup_stream(struct hda_codec *codec,
 				  struct hda_cvt_setup *q)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	hda_nid_t nid = q->nid;
+
 	if (q->stream_tag || q->channel_id)
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
 	if (q->format_id)
@@ -1198,7 +1203,9 @@ static void really_cleanup_stream(struct hda_codec *codec,
 );
 	memset(q, 0, sizeof(*q));
 	q->nid = nid;
-	if (codec->patch_ops.stream_pm)
+	if (driver->ops && driver->ops->stream_pm)
+		driver->ops->stream_pm(codec, nid, false);
+	else if (codec->patch_ops.stream_pm)
 		codec->patch_ops.stream_pm(codec, nid, false);
 }
 
@@ -2746,6 +2753,7 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter);
 static unsigned int hda_set_power_state(struct hda_codec *codec,
 					unsigned int power_state)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	hda_nid_t fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
 	int count;
 	unsigned int state;
@@ -2762,7 +2770,10 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
 
 	/* repeat power states setting at most 10 times*/
 	for (count = 0; count < 10; count++) {
-		if (codec->patch_ops.set_power_state)
+		/* might be called before binding to driver, too */
+		if (driver && driver->ops && driver->ops->set_power_state)
+			driver->ops->set_power_state(codec, fg, power_state);
+		else if (codec->patch_ops.set_power_state)
 			codec->patch_ops.set_power_state(codec, fg,
 							 power_state);
 		else {
@@ -2842,10 +2853,13 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
  */
 static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	unsigned int state;
 
 	snd_hdac_enter_pm(&codec->core);
-	if (codec->patch_ops.suspend)
+	if (driver->ops && driver->ops->suspend)
+		driver->ops->suspend(codec);
+	else if (codec->patch_ops.suspend)
 		codec->patch_ops.suspend(codec);
 	if (!codec->no_stream_clean_at_suspend)
 		hda_cleanup_all_streams(codec);
@@ -2860,6 +2874,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
  */
 static void hda_call_codec_resume(struct hda_codec *codec)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
 	snd_hdac_enter_pm(&codec->core);
 	if (codec->core.regmap)
 		regcache_mark_dirty(codec->core.regmap);
@@ -2870,11 +2886,12 @@ static void hda_call_codec_resume(struct hda_codec *codec)
 	restore_shutup_pins(codec);
 	hda_exec_init_verbs(codec);
 	snd_hda_jack_set_dirty_all(codec);
-	if (codec->patch_ops.resume)
+	if (driver->ops && driver->ops->resume)
+		driver->ops->resume(codec);
+	else if (codec->patch_ops.resume)
 		codec->patch_ops.resume(codec);
 	else {
-		if (codec->patch_ops.init)
-			codec->patch_ops.init(codec);
+		snd_hda_codec_init(codec);
 		snd_hda_regmap_sync(codec);
 	}
 
@@ -3059,15 +3076,20 @@ EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps);
 
 int snd_hda_codec_build_controls(struct hda_codec *codec)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	int err = 0;
+
 	hda_exec_init_verbs(codec);
 	/* continue to initialize... */
-	if (codec->patch_ops.init)
-		err = codec->patch_ops.init(codec);
-	if (!err && codec->patch_ops.build_controls)
-		err = codec->patch_ops.build_controls(codec);
-	if (err < 0)
-		return err;
+	err = snd_hda_codec_init(codec);
+	if (!err) {
+		if (driver->ops && driver->ops->build_controls)
+			err = driver->ops->build_controls(codec);
+		else if (codec->patch_ops.build_controls)
+			err = codec->patch_ops.build_controls(codec);
+		if (err < 0)
+			return err;
+	}
 
 	/* we create chmaps here instead of build_pcms */
 	err = add_std_chmaps(codec);
@@ -3253,16 +3275,20 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
 /* call build_pcms ops of the given codec and set up the default parameters */
 int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 {
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	struct hda_pcm *cpcm;
 	int err;
 
 	if (!list_empty(&codec->pcm_list_head))
 		return 0; /* already parsed */
 
-	if (!codec->patch_ops.build_pcms)
+	if (driver->ops && driver->ops->build_pcms)
+		err = driver->ops->build_pcms(codec);
+	else if (codec->patch_ops.build_pcms)
+		err = codec->patch_ops.build_pcms(codec);
+	else
 		return 0;
 
-	err = codec->patch_ops.build_pcms(codec);
 	if (err < 0) {
 		codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
 			  codec->core.addr, err);
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index 428aa5a06ead..654fe1156d56 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -652,6 +652,17 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
 
 void snd_hda_codec_shutdown(struct hda_codec *codec);
 
+static inline int snd_hda_codec_init(struct hda_codec *codec)
+{
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
+	if (driver->ops && driver->ops->init)
+		return driver->ops->init(codec);
+	else if (codec->patch_ops.init)
+		return codec->patch_ops.init(codec);
+	return 0;
+}
+
 /*
  * AMP control callbacks
  */
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index dc7794c9ac44..ddb31001657e 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -173,6 +173,7 @@ EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
 static int hda_codec_probe(struct snd_soc_component *component)
 {
 	struct hda_codec *codec = dev_to_hda_codec(component->dev);
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	struct hdac_device *hdev = &codec->core;
 	struct hdac_bus *bus = hdev->bus;
 	struct hdac_ext_link *hlink;
@@ -214,14 +215,19 @@ static int hda_codec_probe(struct snd_soc_component *component)
 		goto err;
 	}
 
-	patch = (hda_codec_patch_t)codec->preset->driver_data;
-	if (!patch) {
-		dev_err(&hdev->dev, "no patch specified\n");
-		ret = -EINVAL;
-		goto err;
+	if (driver->ops && driver->ops->probe) {
+		ret = driver->ops->probe(codec, codec->preset);
+	} else {
+		patch = (hda_codec_patch_t)codec->preset->driver_data;
+		if (!patch) {
+			dev_err(&hdev->dev, "no patch specified\n");
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ret = patch(codec);
 	}
 
-	ret = patch(codec);
 	if (ret < 0) {
 		dev_err(&hdev->dev, "codec init failed: %d\n", ret);
 		goto err;
@@ -252,7 +258,9 @@ static int hda_codec_probe(struct snd_soc_component *component)
 complete_err:
 	hda_codec_unregister_dais(codec, component);
 parse_pcms_err:
-	if (codec->patch_ops.free)
+	if (driver->ops && driver->ops->remove)
+		driver->ops->remove(codec);
+	else if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
 err:
 	snd_hda_codec_cleanup_for_unbind(codec);
@@ -271,6 +279,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
 static void hda_codec_remove(struct snd_soc_component *component)
 {
 	struct hda_codec *codec = dev_to_hda_codec(component->dev);
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	struct hdac_device *hdev = &codec->core;
 	struct hdac_bus *bus = hdev->bus;
 	struct hdac_ext_link *hlink;
@@ -281,7 +290,9 @@ static void hda_codec_remove(struct snd_soc_component *component)
 
 	hda_codec_unregister_dais(codec, component);
 
-	if (codec->patch_ops.free)
+	if (driver->ops && driver->ops->remove)
+		driver->ops->remove(codec);
+	else if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
 
 	snd_hda_codec_cleanup_for_unbind(codec);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 29c88de5508b..7bb7845d5e43 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -409,6 +409,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 			snd_soc_component_get_dapm(component);
 	struct hdac_device *hdev = &hda_pvt->codec->core;
 	struct hda_codec *hcodec = hda_pvt->codec;
+	struct hda_codec_driver *driver = hda_codec_to_driver(hcodec);
 	struct hdac_ext_link *hlink;
 	hda_codec_patch_t patch;
 	int ret;
@@ -484,15 +485,23 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 		goto error_pm;
 	}
 
-	patch = (hda_codec_patch_t)hcodec->preset->driver_data;
-	if (patch) {
-		ret = patch(hcodec);
+	if (driver->ops && driver->ops->probe) {
+		ret = driver->ops->probe(hcodec, hcodec->preset);
 		if (ret < 0) {
-			dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret);
+			dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret);
 			goto error_regmap;
 		}
 	} else {
-		dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__);
+		patch = (hda_codec_patch_t)hcodec->preset->driver_data;
+		if (patch) {
+			ret = patch(hcodec);
+			if (ret < 0) {
+				dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret);
+				goto error_regmap;
+			}
+		} else {
+			dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__);
+		}
 	}
 
 	ret = snd_hda_codec_parse_pcms(hcodec);
@@ -531,7 +540,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 	return 0;
 
 error_patch:
-	if (hcodec->patch_ops.free)
+	if (driver->ops && driver->ops->remove)
+		driver->ops->remove(hcodec);
+	else if (hcodec->patch_ops.free)
 		hcodec->patch_ops.free(hcodec);
 error_regmap:
 	snd_hdac_regmap_exit(hdev);
@@ -548,6 +559,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
 		      snd_soc_component_get_drvdata(component);
 	struct hdac_device *hdev = &hda_pvt->codec->core;
 	struct hda_codec *codec = hda_pvt->codec;
+	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 	struct hdac_ext_link *hlink = NULL;
 
 	hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
@@ -559,7 +571,9 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
 	pm_runtime_disable(&hdev->dev);
 	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 
-	if (codec->patch_ops.free)
+	if (driver->ops && driver->ops->remove)
+		driver->ops->remove(codec);
+	else if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
 
 	snd_hda_codec_cleanup_for_unbind(codec);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 10/27] ALSA: hda/generic: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (8 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 09/27] ALSA: hda: Introduce hda_codec_driver ops Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 11/27] ALSA: hda/realtek: " Takashi Iwai
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the generic HD-audio codec driver to use the new hda_codec_ops
probe.  No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/generic.c | 43 +++++++++++++++++++++++---------------
 sound/hda/codecs/generic.h |  3 ++-
 2 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c
index 873fd4b7f451..82c31b93424c 100644
--- a/sound/hda/codecs/generic.c
+++ b/sound/hda/codecs/generic.c
@@ -4946,7 +4946,7 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
  * @nid: audio widget
  * @on: power on/off flag
  *
- * Set this in patch_ops.stream_pm.  Only valid with power_save_node flag.
+ * Set this in hda_codec_ops.stream_pm.  Only valid with power_save_node flag.
  */
 void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
 {
@@ -5230,7 +5230,7 @@ static const char * const follower_pfxs[] = {
  * snd_hda_gen_build_controls - Build controls from the parsed results
  * @codec: the HDA codec
  *
- * Pass this to build_controls patch_ops.
+ * Pass this to build_controls hda_codec_ops.
  */
 int snd_hda_gen_build_controls(struct hda_codec *codec)
 {
@@ -5743,7 +5743,7 @@ static void setup_pcm_stream(struct hda_pcm_stream *str,
  * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
  * @codec: the HDA codec
  *
- * Pass this to build_pcms patch_ops.
+ * Pass this to build_pcms hda_codec_ops.
  */
 int snd_hda_gen_build_pcms(struct hda_codec *codec)
 {
@@ -6032,7 +6032,7 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec)
  * snd_hda_gen_init - initialize the generic spec
  * @codec: the HDA codec
  *
- * This can be put as patch_ops init function.
+ * This can be put as hda_codec_ops init function.
  */
 int snd_hda_gen_init(struct hda_codec *codec)
 {
@@ -6070,26 +6070,26 @@ int snd_hda_gen_init(struct hda_codec *codec)
 EXPORT_SYMBOL_GPL(snd_hda_gen_init);
 
 /**
- * snd_hda_gen_free - free the generic spec
+ * snd_hda_gen_remove - free the generic spec
  * @codec: the HDA codec
  *
- * This can be put as patch_ops free function.
+ * This can be put as hda_codec_ops remove function.
  */
-void snd_hda_gen_free(struct hda_codec *codec)
+void snd_hda_gen_remove(struct hda_codec *codec)
 {
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
 	snd_hda_gen_spec_free(codec->spec);
 	kfree(codec->spec);
 	codec->spec = NULL;
 }
-EXPORT_SYMBOL_GPL(snd_hda_gen_free);
+EXPORT_SYMBOL_GPL(snd_hda_gen_remove);
 
 /**
  * snd_hda_gen_check_power_status - check the loopback power save state
  * @codec: the HDA codec
  * @nid: NID to inspect
  *
- * This can be put as patch_ops check_power_status function.
+ * This can be put as hda_codec_ops check_power_status function.
  */
 int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
@@ -6112,11 +6112,8 @@ static const struct hda_codec_ops generic_patch_ops = {
 	.check_power_status = snd_hda_gen_check_power_status,
 };
 
-/*
- * snd_hda_parse_generic_codec - Generic codec parser
- * @codec: the HDA codec
- */
-static int snd_hda_parse_generic_codec(struct hda_codec *codec)
+static int snd_hda_gen_probe(struct hda_codec *codec,
+			     const struct hda_device_id *id)
 {
 	struct hda_gen_spec *spec;
 	int err;
@@ -6139,19 +6136,31 @@ static int snd_hda_parse_generic_codec(struct hda_codec *codec)
 	return 0;
 
 error:
-	snd_hda_gen_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops generic_codec_ops = {
+	.probe = snd_hda_gen_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = snd_hda_gen_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 static const struct hda_device_id snd_hda_id_generic[] = {
-	HDA_CODEC_ENTRY(0x1af40021, "Generic", snd_hda_parse_generic_codec), /* QEMU */
-	HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
+	HDA_CODEC_ID(0x1af40021, "Generic"), /* QEMU */
+	HDA_CODEC_ID(HDA_CODEC_ID_GENERIC, "Generic"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
 
 static struct hda_codec_driver generic_driver = {
 	.id = snd_hda_id_generic,
+	.ops = &generic_codec_ops,
 };
 
 module_hda_codec_driver(generic_driver);
diff --git a/sound/hda/codecs/generic.h b/sound/hda/codecs/generic.h
index 9612afaa61c2..00a92fc55846 100644
--- a/sound/hda/codecs/generic.h
+++ b/sound/hda/codecs/generic.h
@@ -311,7 +311,8 @@ enum {
 int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
 
 int snd_hda_gen_init(struct hda_codec *codec);
-void snd_hda_gen_free(struct hda_codec *codec);
+void snd_hda_gen_remove(struct hda_codec *codec);
+#define snd_hda_gen_free	snd_hda_gen_remove
 
 int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
 struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 11/27] ALSA: hda/realtek: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (9 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 10/27] ALSA: hda/generic: Rewrite to new probe method Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-31  3:20   ` ALC887-VD line-in not visible Arthur Marsh
  2025-07-09 16:04 ` [PATCH 12/27] ALSA: hda/cmedia: Rewrite to new probe method Takashi Iwai
                   ` (16 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the Realtek codec drivers to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/realtek/alc260.c   |  20 ++++-
 sound/hda/codecs/realtek/alc262.c   |  20 ++++-
 sound/hda/codecs/realtek/alc268.c   |  22 +++++-
 sound/hda/codecs/realtek/alc269.c   | 111 +++++++++++++++-------------
 sound/hda/codecs/realtek/alc662.c   |  42 +++++++----
 sound/hda/codecs/realtek/alc680.c   |  20 ++++-
 sound/hda/codecs/realtek/alc861.c   |  22 +++++-
 sound/hda/codecs/realtek/alc861vd.c |  22 +++++-
 sound/hda/codecs/realtek/alc880.c   |  24 ++++--
 sound/hda/codecs/realtek/alc882.c   |  48 +++++++-----
 sound/hda/codecs/realtek/realtek.c  |  17 +----
 sound/hda/codecs/realtek/realtek.h  |   4 -
 12 files changed, 244 insertions(+), 128 deletions(-)

diff --git a/sound/hda/codecs/realtek/alc260.c b/sound/hda/codecs/realtek/alc260.c
index ebe20eaec58a..8bd47079dccb 100644
--- a/sound/hda/codecs/realtek/alc260.c
+++ b/sound/hda/codecs/realtek/alc260.c
@@ -211,7 +211,7 @@ static const struct hda_model_fixup alc260_fixup_models[] = {
 
 /*
  */
-static int patch_alc260(struct hda_codec *codec)
+static int alc260_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -252,15 +252,28 @@ static int patch_alc260(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc260_codec_ops = {
+	.probe = alc260_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc260[] = {
-	HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
+	HDA_CODEC_ID(0x10ec0260, "ALC260"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260);
@@ -271,6 +284,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc260_driver = {
 	.id = snd_hda_id_alc260,
+	.ops = &alc260_codec_ops,
 };
 
 module_hda_codec_driver(alc260_driver);
diff --git a/sound/hda/codecs/realtek/alc262.c b/sound/hda/codecs/realtek/alc262.c
index ffe61f447667..3ec06cf5d2a6 100644
--- a/sound/hda/codecs/realtek/alc262.c
+++ b/sound/hda/codecs/realtek/alc262.c
@@ -126,7 +126,7 @@ static const struct hda_model_fixup alc262_fixup_models[] = {
 
 /*
  */
-static int patch_alc262(struct hda_codec *codec)
+static int alc262_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -175,15 +175,28 @@ static int patch_alc262(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc262_codec_ops = {
+	.probe = alc262_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc262[] = {
-	HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
+	HDA_CODEC_ID(0x10ec0262, "ALC262"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262);
@@ -194,6 +207,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc262_driver = {
 	.id = snd_hda_id_alc262,
+	.ops = &alc262_codec_ops,
 };
 
 module_hda_codec_driver(alc262_driver);
diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c
index d018f9982feb..e489cdc98eb8 100644
--- a/sound/hda/codecs/realtek/alc268.c
+++ b/sound/hda/codecs/realtek/alc268.c
@@ -101,7 +101,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 
 /*
  */
-static int patch_alc268(struct hda_codec *codec)
+static int alc268_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int i, err;
@@ -151,16 +151,29 @@ static int patch_alc268(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc268_codec_ops = {
+	.probe = alc268_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc268[] = {
-	HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
-	HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
+	HDA_CODEC_ID(0x10ec0267, "ALC267"),
+	HDA_CODEC_ID(0x10ec0268, "ALC268"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc268);
@@ -171,6 +184,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc268_driver = {
 	.id = snd_hda_id_alc268,
+	.ops = &alc268_codec_ops,
 };
 
 module_hda_codec_driver(alc268_driver);
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 325ba08e2981..b393338808d5 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -992,7 +992,7 @@ static int alc269_resume(struct hda_codec *codec)
 		msleep(150);
 	}
 
-	codec->patch_ops.init(codec);
+	snd_hda_codec_init(codec);
 
 	if (spec->codec_variant == ALC269_TYPE_ALC269VB)
 		alc269vb_toggle_power_output(codec, 1);
@@ -7841,19 +7841,19 @@ static void alc269_fill_coef(struct hda_codec *codec)
 	alc_update_coef_idx(codec, 0x4, 0, 1<<11);
 }
 
-static void alc269_free(struct hda_codec *codec)
+static void alc269_remove(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
 
 	if (spec)
 		hda_component_manager_free(&spec->comps, &comp_master_ops);
 
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 }
 
 /*
  */
-static int patch_alc269(struct hda_codec *codec)
+static int alc269_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -7867,9 +7867,6 @@ static int patch_alc269(struct hda_codec *codec)
 	codec->power_save_node = 0;
 	spec->en_3kpull_low = true;
 
-	codec->patch_ops.suspend = alc269_suspend;
-	codec->patch_ops.resume = alc269_resume;
-	codec->patch_ops.free = alc269_free;
 	spec->shutup = alc_default_shutup;
 	spec->init_hook = alc_default_init;
 
@@ -8067,56 +8064,69 @@ static int patch_alc269(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	alc269_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc269_codec_ops = {
+	.probe = alc269_probe,
+	.remove = alc269_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = alc269_suspend,
+	.resume = alc269_resume,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc269[] = {
-	HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0230, "ALC236", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0287, "ALC287", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0289, "ALC289", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
-	HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269),
-	HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269),
+	HDA_CODEC_ID(0x10ec0215, "ALC215"),
+	HDA_CODEC_ID(0x10ec0221, "ALC221"),
+	HDA_CODEC_ID(0x10ec0222, "ALC222"),
+	HDA_CODEC_ID(0x10ec0225, "ALC225"),
+	HDA_CODEC_ID(0x10ec0230, "ALC236"),
+	HDA_CODEC_ID(0x10ec0231, "ALC231"),
+	HDA_CODEC_ID(0x10ec0233, "ALC233"),
+	HDA_CODEC_ID(0x10ec0234, "ALC234"),
+	HDA_CODEC_ID(0x10ec0235, "ALC233"),
+	HDA_CODEC_ID(0x10ec0236, "ALC236"),
+	HDA_CODEC_ID(0x10ec0245, "ALC245"),
+	HDA_CODEC_ID(0x10ec0255, "ALC255"),
+	HDA_CODEC_ID(0x10ec0256, "ALC256"),
+	HDA_CODEC_ID(0x10ec0257, "ALC257"),
+	HDA_CODEC_ID(0x10ec0269, "ALC269"),
+	HDA_CODEC_ID(0x10ec0270, "ALC270"),
+	HDA_CODEC_ID(0x10ec0274, "ALC274"),
+	HDA_CODEC_ID(0x10ec0275, "ALC275"),
+	HDA_CODEC_ID(0x10ec0276, "ALC276"),
+	HDA_CODEC_ID(0x10ec0280, "ALC280"),
+	HDA_CODEC_ID(0x10ec0282, "ALC282"),
+	HDA_CODEC_ID(0x10ec0283, "ALC283"),
+	HDA_CODEC_ID(0x10ec0284, "ALC284"),
+	HDA_CODEC_ID(0x10ec0285, "ALC285"),
+	HDA_CODEC_ID(0x10ec0286, "ALC286"),
+	HDA_CODEC_ID(0x10ec0287, "ALC287"),
+	HDA_CODEC_ID(0x10ec0288, "ALC288"),
+	HDA_CODEC_ID(0x10ec0289, "ALC289"),
+	HDA_CODEC_ID(0x10ec0290, "ALC290"),
+	HDA_CODEC_ID(0x10ec0292, "ALC292"),
+	HDA_CODEC_ID(0x10ec0293, "ALC293"),
+	HDA_CODEC_ID(0x10ec0294, "ALC294"),
+	HDA_CODEC_ID(0x10ec0295, "ALC295"),
+	HDA_CODEC_ID(0x10ec0298, "ALC298"),
+	HDA_CODEC_ID(0x10ec0299, "ALC299"),
+	HDA_CODEC_ID(0x10ec0300, "ALC300"),
+	HDA_CODEC_ID(0x10ec0623, "ALC623"),
+	HDA_CODEC_ID(0x10ec0700, "ALC700"),
+	HDA_CODEC_ID(0x10ec0701, "ALC701"),
+	HDA_CODEC_ID(0x10ec0703, "ALC703"),
+	HDA_CODEC_ID(0x10ec0711, "ALC711"),
+	HDA_CODEC_ID(0x19e58326, "HW8326"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc269);
@@ -8128,6 +8138,7 @@ MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
 
 static struct hda_codec_driver alc269_driver = {
 	.id = snd_hda_id_alc269,
+	.ops = &alc269_codec_ops,
 };
 
 module_hda_codec_driver(alc269_driver);
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
index 94e4a313e5e2..5073165d1f3c 100644
--- a/sound/hda/codecs/realtek/alc662.c
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -994,7 +994,7 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
 
 /*
  */
-static int patch_alc662(struct hda_codec *codec)
+static int alc662_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -1067,26 +1067,39 @@ static int patch_alc662(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc662_codec_ops = {
+	.probe = alc662_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc662[] = {
-	HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
-	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
-	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
-	HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
+	HDA_CODEC_ID(0x10ec0272, "ALC272"),
+	HDA_CODEC_ID_REV(0x10ec0662, 0x100101, "ALC662 rev1"),
+	HDA_CODEC_ID_REV(0x10ec0662, 0x100300, "ALC662 rev3"),
+	HDA_CODEC_ID(0x10ec0663, "ALC663"),
+	HDA_CODEC_ID(0x10ec0665, "ALC665"),
+	HDA_CODEC_ID(0x10ec0667, "ALC667"),
+	HDA_CODEC_ID(0x10ec0668, "ALC668"),
+	HDA_CODEC_ID(0x10ec0670, "ALC670"),
+	HDA_CODEC_ID(0x10ec0671, "ALC671"),
+	HDA_CODEC_ID(0x10ec0867, "ALC891"),
+	HDA_CODEC_ID(0x10ec0892, "ALC892"),
+	HDA_CODEC_ID(0x10ec0897, "ALC897"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc662);
@@ -1097,6 +1110,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc662_driver = {
 	.id = snd_hda_id_alc662,
+	.ops = &alc662_codec_ops,
 };
 
 module_hda_codec_driver(alc662_driver);
diff --git a/sound/hda/codecs/realtek/alc680.c b/sound/hda/codecs/realtek/alc680.c
index baf19ee3bc2f..8aab1026243c 100644
--- a/sound/hda/codecs/realtek/alc680.c
+++ b/sound/hda/codecs/realtek/alc680.c
@@ -14,7 +14,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
 
 /*
  */
-static int patch_alc680(struct hda_codec *codec)
+static int alc680_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	int err;
 
@@ -26,18 +26,31 @@ static int patch_alc680(struct hda_codec *codec)
 	/* automatic parse from the BIOS config */
 	err = alc680_parse_auto_config(codec);
 	if (err < 0) {
-		alc_free(codec);
+		snd_hda_gen_remove(codec);
 		return err;
 	}
 
 	return 0;
 }
 
+static const struct hda_codec_ops alc680_codec_ops = {
+	.probe = alc680_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc680[] = {
-	HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
+	HDA_CODEC_ID(0x10ec0680, "ALC680"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc680);
@@ -48,6 +61,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc680_driver = {
 	.id = snd_hda_id_alc680,
+	.ops = &alc680_codec_ops,
 };
 
 module_hda_codec_driver(alc680_driver);
diff --git a/sound/hda/codecs/realtek/alc861.c b/sound/hda/codecs/realtek/alc861.c
index 0eb70b44dc05..270037c6504a 100644
--- a/sound/hda/codecs/realtek/alc861.c
+++ b/sound/hda/codecs/realtek/alc861.c
@@ -88,7 +88,7 @@ static const struct hda_quirk alc861_fixup_tbl[] = {
 
 /*
  */
-static int patch_alc861(struct hda_codec *codec)
+static int alc861_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -124,16 +124,29 @@ static int patch_alc861(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc861_codec_ops = {
+	.probe = alc861_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc861[] = {
-	HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
-	HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
+	HDA_CODEC_ID_REV(0x10ec0861, 0x100340, "ALC660"),
+	HDA_CODEC_ID(0x10ec0861, "ALC861"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861);
@@ -144,6 +157,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc861_driver = {
 	.id = snd_hda_id_alc861,
+	.ops = &alc861_codec_ops,
 };
 
 module_hda_codec_driver(alc861_driver);
diff --git a/sound/hda/codecs/realtek/alc861vd.c b/sound/hda/codecs/realtek/alc861vd.c
index ebf274ad730b..44264e0d6e56 100644
--- a/sound/hda/codecs/realtek/alc861vd.c
+++ b/sound/hda/codecs/realtek/alc861vd.c
@@ -62,7 +62,7 @@ static const struct hda_quirk alc861vd_fixup_tbl[] = {
 
 /*
  */
-static int patch_alc861vd(struct hda_codec *codec)
+static int alc861vd_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -98,16 +98,29 @@ static int patch_alc861vd(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc861vd_codec_ops = {
+	.probe = alc861vd_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc861vd[] = {
-	HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
-	HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
+	HDA_CODEC_ID(0x10ec0660, "ALC660-VD"),
+	HDA_CODEC_ID(0x10ec0862, "ALC861-VD"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861vd);
@@ -118,6 +131,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc861vd_driver = {
 	.id = snd_hda_id_alc861vd,
+	.ops = &alc861vd_codec_ops,
 };
 
 module_hda_codec_driver(alc861vd_driver);
diff --git a/sound/hda/codecs/realtek/alc880.c b/sound/hda/codecs/realtek/alc880.c
index 2e828ab96dc5..bf1bdf11ec2d 100644
--- a/sound/hda/codecs/realtek/alc880.c
+++ b/sound/hda/codecs/realtek/alc880.c
@@ -434,9 +434,9 @@ static const struct hda_model_fixup alc880_fixup_models[] = {
 
 
 /*
- * OK, here we have finally the patch for ALC880
+ * OK, here we have finally the probe for ALC880
  */
-static int patch_alc880(struct hda_codec *codec)
+static int alc880_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -449,8 +449,6 @@ static int patch_alc880(struct hda_codec *codec)
 	spec->gen.need_dac_fix = 1;
 	spec->gen.beep_nid = 0x01;
 
-	codec->patch_ops.unsol_event = alc880_unsol_event;
-
 	alc_pre_init(codec);
 
 	snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
@@ -473,15 +471,28 @@ static int patch_alc880(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc880_codec_ops = {
+	.probe = alc880_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = alc880_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc880[] = {
-	HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
+	HDA_CODEC_ID(0x10ec0880, "ALC880"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880);
@@ -492,6 +503,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc880_driver = {
 	.id = snd_hda_id_alc880,
+	.ops = &alc880_codec_ops,
 };
 
 module_hda_codec_driver(alc880_driver);
diff --git a/sound/hda/codecs/realtek/alc882.c b/sound/hda/codecs/realtek/alc882.c
index 6af2f7fcc6bb..529fecd5baa0 100644
--- a/sound/hda/codecs/realtek/alc882.c
+++ b/sound/hda/codecs/realtek/alc882.c
@@ -757,7 +757,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 
 /*
  */
-static int patch_alc882(struct hda_codec *codec)
+static int alc882_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct alc_spec *spec;
 	int err;
@@ -809,29 +809,42 @@ static int patch_alc882(struct hda_codec *codec)
 	return 0;
 
  error:
-	alc_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops alc882_codec_ops = {
+	.probe = alc882_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = alc_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = alc_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.resume = alc_resume,
+	.suspend = alc_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_alc882[] = {
-	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
-	HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
-	HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
+	HDA_CODEC_ID_REV(0x10ec0662, 0x100002, "ALC662 rev2"),
+	HDA_CODEC_ID(0x10ec0882, "ALC882"),
+	HDA_CODEC_ID(0x10ec0883, "ALC883"),
+	HDA_CODEC_ID_REV(0x10ec0885, 0x100101, "ALC889A"),
+	HDA_CODEC_ID_REV(0x10ec0885, 0x100103, "ALC889A"),
+	HDA_CODEC_ID(0x10ec0885, "ALC885"),
+	HDA_CODEC_ID(0x10ec0887, "ALC887"),
+	HDA_CODEC_ID_REV(0x10ec0888, 0x100101, "ALC1200"),
+	HDA_CODEC_ID(0x10ec0888, "ALC888"),
+	HDA_CODEC_ID(0x10ec0889, "ALC889"),
+	HDA_CODEC_ID(0x10ec0899, "ALC898"),
+	HDA_CODEC_ID(0x10ec0900, "ALC1150"),
+	HDA_CODEC_ID(0x10ec0b00, "ALCS1200A"),
+	HDA_CODEC_ID(0x10ec1168, "ALC1220"),
+	HDA_CODEC_ID(0x10ec1220, "ALC1220"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc882);
@@ -842,6 +855,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
 
 static struct hda_codec_driver alc882_driver = {
 	.id = snd_hda_id_alc882,
+	.ops = &alc882_codec_ops,
 };
 
 module_hda_codec_driver(alc882_driver);
diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c
index 4ab49e76c304..66b2efb9acb3 100644
--- a/sound/hda/codecs/realtek/realtek.c
+++ b/sound/hda/codecs/realtek/realtek.c
@@ -862,27 +862,13 @@ int alc_resume(struct hda_codec *codec)
 
 	if (!spec->no_depop_delay)
 		msleep(150); /* to avoid pop noise */
-	codec->patch_ops.init(codec);
+	snd_hda_codec_init(codec);
 	snd_hda_regmap_sync(codec);
 	hda_call_check_power_status(codec, 0x01);
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(alc_resume, "SND_HDA_CODEC_REALTEK");
 
-/*
- */
-const struct hda_codec_ops alc_patch_ops = {
-	.build_controls = alc_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = alc_init,
-	.free = alc_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.resume = alc_resume,
-	.suspend = alc_suspend,
-	.check_power_status = snd_hda_gen_check_power_status,
-};
-EXPORT_SYMBOL_NS_GPL(alc_patch_ops, "SND_HDA_CODEC_REALTEK");
-
 /*
  * Rename codecs appropriately from COEF value or subvendor id
  */
@@ -1082,7 +1068,6 @@ int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
 	/* FIXME: do we need this for all Realtek codec models? */
 	codec->spdif_status_reset = 1;
 	codec->forced_resume = 1;
-	codec->patch_ops = alc_patch_ops;
 	mutex_init(&spec->coef_mutex);
 
 	err = alc_codec_rename_from_preset(codec);
diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h
index ac142f2540e3..ee893da0c486 100644
--- a/sound/hda/codecs/realtek/realtek.h
+++ b/sound/hda/codecs/realtek/realtek.h
@@ -226,15 +226,11 @@ void alc_power_eapd(struct hda_codec *codec);
 int alc_suspend(struct hda_codec *codec);
 int alc_resume(struct hda_codec *codec);
 
-#define alc_free	snd_hda_gen_free
-
 int alc_parse_auto_config(struct hda_codec *codec,
 			  const hda_nid_t *ignore_nids,
 			  const hda_nid_t *ssid_nids);
 int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid);
 
-extern const struct hda_codec_ops alc_patch_ops;
-
 #define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 12/27] ALSA: hda/cmedia: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (10 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 11/27] ALSA: hda/realtek: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 13/27] ALSA: hda/analog: " Takashi Iwai
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the C-Media codec driver to use the new hda_codec_ops probe.

Since the CM9825 uses a completely different probe and codec ops,
factor out to an individual codec driver, snd-hda-codec-cm9825.

Other than that, no functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/Kconfig  |  10 +
 sound/hda/codecs/Makefile |   2 +
 sound/hda/codecs/cm9825.c | 312 ++++++++++++++++++++++++++++++++
 sound/hda/codecs/cmedia.c | 372 +++++---------------------------------
 4 files changed, 365 insertions(+), 331 deletions(-)
 create mode 100644 sound/hda/codecs/cm9825.c

diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
index e8c2efd2efb6..addbc9424336 100644
--- a/sound/hda/codecs/Kconfig
+++ b/sound/hda/codecs/Kconfig
@@ -99,6 +99,16 @@ config SND_HDA_CODEC_CMEDIA
 comment "Set to Y if you want auto-loading the codec driver"
 	depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
 
+config SND_HDA_CODEC_CM9825
+	tristate "Build C-Media CM9825 HD-audio codec support"
+	select SND_HDA_GENERIC
+	help
+	  Say Y or M here to include C-Media CM9825 HD-audio codec support in
+	  snd-hda-intel driver
+
+comment "Set to Y if you want auto-loading the codec driver"
+	depends on SND_HDA=y && SND_HDA_CODEC_CM9825=m
+
 config SND_HDA_CODEC_SI3054
 	tristate "Build Silicon Labs 3054 HD-modem codec support"
 	help
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
index 14e5041aa4f0..e7f03e281999 100644
--- a/sound/hda/codecs/Makefile
+++ b/sound/hda/codecs/Makefile
@@ -3,6 +3,7 @@ subdir-ccflags-y += -I$(src)/../common
 
 snd-hda-codec-generic-y :=	generic.o
 snd-hda-codec-cmedia-y :=	cmedia.o
+snd-hda-codec-cm9825-y :=	cm9825.o
 snd-hda-codec-analog-y :=	analog.o
 snd-hda-codec-ca0110-y :=	ca0110.o
 snd-hda-codec-ca0132-y :=	ca0132.o
@@ -21,6 +22,7 @@ obj-y += side-codecs/
 # codec drivers
 obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
 obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
+obj-$(CONFIG_SND_HDA_CODEC_CM9825) += snd-hda-codec-cm9825.o
 obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
 obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
 obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
new file mode 100644
index 000000000000..5c474ce44348
--- /dev/null
+++ b/sound/hda/codecs/cm9825.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * CM9825 HD-audio codec
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+/* CM9825 Offset Definitions */
+
+#define CM9825_VERB_SET_HPF_1 0x781
+#define CM9825_VERB_SET_HPF_2 0x785
+#define CM9825_VERB_SET_PLL 0x7a0
+#define CM9825_VERB_SET_NEG 0x7a1
+#define CM9825_VERB_SET_ADCL 0x7a2
+#define CM9825_VERB_SET_DACL 0x7a3
+#define CM9825_VERB_SET_MBIAS 0x7a4
+#define CM9825_VERB_SET_VNEG 0x7a8
+#define CM9825_VERB_SET_D2S 0x7a9
+#define CM9825_VERB_SET_DACTRL 0x7aa
+#define CM9825_VERB_SET_PDNEG 0x7ac
+#define CM9825_VERB_SET_VDO 0x7ad
+#define CM9825_VERB_SET_CDALR 0x7b0
+#define CM9825_VERB_SET_MTCBA 0x7b1
+#define CM9825_VERB_SET_OTP 0x7b2
+#define CM9825_VERB_SET_OCP 0x7b3
+#define CM9825_VERB_SET_GAD 0x7b4
+#define CM9825_VERB_SET_TMOD 0x7b5
+#define CM9825_VERB_SET_SNR 0x7b6
+
+struct cmi_spec {
+	struct hda_gen_spec gen;
+	const struct hda_verb *chip_d0_verbs;
+	const struct hda_verb *chip_d3_verbs;
+	const struct hda_verb *chip_hp_present_verbs;
+	const struct hda_verb *chip_hp_remove_verbs;
+	struct hda_codec *codec;
+	struct delayed_work unsol_hp_work;
+	int quirk;
+};
+
+static const struct hda_verb cm9825_std_d3_verbs[] = {
+	/* chip sleep verbs */
+	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
+	{0x43, CM9825_VERB_SET_PLL, 0x01},	/* PLL set */
+	{0x43, CM9825_VERB_SET_NEG, 0xc2},	/* NEG set */
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
+	{0x43, CM9825_VERB_SET_DACL, 0x02},	/* DACL */
+	{0x43, CM9825_VERB_SET_VNEG, 0x50},	/* VOL NEG */
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
+	{0x43, CM9825_VERB_SET_PDNEG, 0x04},	/* SEL OSC */
+	{0x43, CM9825_VERB_SET_CDALR, 0xf6},	/* Class D */
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},	/* OTP set */
+	{}
+};
+
+static const struct hda_verb cm9825_std_d0_verbs[] = {
+	/* chip init verbs */
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},	/* EAPD set */
+	{0x43, CM9825_VERB_SET_SNR, 0x30},	/* SNR set */
+	{0x43, CM9825_VERB_SET_PLL, 0x00},	/* PLL set */
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
+	{0x43, CM9825_VERB_SET_DACL, 0x02},	/* DACL */
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
+	{0x43, CM9825_VERB_SET_VNEG, 0x56},	/* VOL NEG */
+	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},	/* DACTRL set */
+	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},	/* SEL OSC */
+	{0x43, CM9825_VERB_SET_VDO, 0x80},	/* VDO set */
+	{0x43, CM9825_VERB_SET_CDALR, 0xf4},	/* Class D */
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},	/* OTP set */
+	{0x43, CM9825_VERB_SET_MTCBA, 0x61},	/* SR set */
+	{0x43, CM9825_VERB_SET_OCP, 0x33},	/* OTP set */
+	{0x43, CM9825_VERB_SET_GAD, 0x07},	/* ADC -3db */
+	{0x43, CM9825_VERB_SET_TMOD, 0x26},	/* Class D clk */
+	{0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
+		AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d},	/* Gain set */
+	{0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
+		AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d},	/* Gain set */
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},	/* HPF set */
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},	/* HPF set */
+	{}
+};
+
+static const struct hda_verb cm9825_hp_present_verbs[] = {
+	{0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},	/* PIN off */
+	{0x43, CM9825_VERB_SET_ADCL, 0x88},	/* ADC */
+	{0x43, CM9825_VERB_SET_DACL, 0xaa},	/* DACL */
+	{0x43, CM9825_VERB_SET_MBIAS, 0x10},	/* MBIAS */
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},	/* depop */
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},	/* DACTRL set */
+	{0x43, CM9825_VERB_SET_VDO, 0xc4},	/* VDO set */
+	{}
+};
+
+static const struct hda_verb cm9825_hp_remove_verbs[] = {
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
+	{0x43, CM9825_VERB_SET_DACL, 0x56},	/* DACL */
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
+	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
+	{0x43, CM9825_VERB_SET_DACTRL, 0xe0},	/* DACTRL set */
+	{0x43, CM9825_VERB_SET_VDO, 0x80},	/* VDO set */
+	{0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},	/* PIN on */
+	{}
+};
+
+static void cm9825_unsol_hp_delayed(struct work_struct *work)
+{
+	struct cmi_spec *spec =
+	    container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
+	struct hda_jack_tbl *jack;
+	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+	bool hp_jack_plugin = false;
+	int err = 0;
+
+	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
+
+	codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
+		  (int)hp_jack_plugin, hp_pin);
+
+	if (!hp_jack_plugin) {
+		err =
+		    snd_hda_codec_write(spec->codec, 0x42, 0,
+					AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+		if (err)
+			codec_dbg(spec->codec, "codec_write err %d\n", err);
+
+		snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
+	} else {
+		snd_hda_sequence_write(spec->codec,
+				       spec->chip_hp_present_verbs);
+	}
+
+	jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
+	if (jack) {
+		jack->block_report = 0;
+		snd_hda_jack_report_sync(spec->codec);
+	}
+}
+
+static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+	struct cmi_spec *spec = codec->spec;
+	struct hda_jack_tbl *tbl;
+
+	/* Delay enabling the HP amp, to let the mic-detection
+	 * state machine run.
+	 */
+
+	codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
+
+	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+	if (tbl)
+		tbl->block_report = 1;
+	schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
+}
+
+static void cm9825_setup_unsol(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+
+	snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
+}
+
+static int cm9825_init(struct hda_codec *codec)
+{
+	snd_hda_gen_init(codec);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+	return 0;
+}
+
+static void cm9825_remove(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	cancel_delayed_work_sync(&spec->unsol_hp_work);
+	snd_hda_gen_remove(codec);
+}
+
+static int cm9825_suspend(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	cancel_delayed_work_sync(&spec->unsol_hp_work);
+
+	snd_hda_sequence_write(codec, spec->chip_d3_verbs);
+
+	return 0;
+}
+
+static int cm9825_resume(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+	hda_nid_t hp_pin = 0;
+	bool hp_jack_plugin = false;
+	int err;
+
+	err =
+	    snd_hda_codec_write(spec->codec, 0x42, 0,
+				AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
+	if (err)
+		codec_dbg(codec, "codec_write err %d\n", err);
+
+	msleep(150);		/* for depop noise */
+
+	snd_hda_codec_init(codec);
+
+	hp_pin = spec->gen.autocfg.hp_pins[0];
+	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
+
+	codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
+		  (int)hp_jack_plugin, hp_pin);
+
+	if (!hp_jack_plugin) {
+		err =
+		    snd_hda_codec_write(spec->codec, 0x42, 0,
+					AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+
+		if (err)
+			codec_dbg(codec, "codec_write err %d\n", err);
+
+		snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
+	}
+
+	snd_hda_regmap_sync(codec);
+	hda_call_check_power_status(codec, 0x01);
+
+	return 0;
+}
+
+static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+	struct cmi_spec *spec;
+	struct auto_pin_cfg *cfg;
+	int err;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
+	codec->spec = spec;
+	spec->codec = codec;
+	cfg = &spec->gen.autocfg;
+	snd_hda_gen_spec_init(&spec->gen);
+	spec->chip_d0_verbs = cm9825_std_d0_verbs;
+	spec->chip_d3_verbs = cm9825_std_d3_verbs;
+	spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
+	spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
+
+	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
+
+	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+	if (err < 0)
+		goto error;
+	err = snd_hda_gen_parse_auto_config(codec, cfg);
+	if (err < 0)
+		goto error;
+
+	cm9825_setup_unsol(codec);
+
+	return 0;
+
+ error:
+	cm9825_remove(codec);
+
+	codec_info(codec, "Enter err %d\n", err);
+
+	return err;
+}
+
+static const struct hda_codec_ops cm9825_codec_ops = {
+	.probe = cm9825_probe,
+	.remove = cm9825_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = cm9825_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = cm9825_suspend,
+	.resume = cm9825_resume,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_cm9825[] = {
+	HDA_CODEC_ID(0x13f69825, "CM9825"),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CM9825 HD-audio codec");
+
+static struct hda_codec_driver cm9825_driver = {
+	.id = snd_hda_id_cm9825,
+	.ops = &cm9825_codec_ops,
+};
+
+module_hda_codec_driver(cm9825_driver);
diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c
index c88da2f8233e..15e5a1118a6e 100644
--- a/sound/hda/codecs/cmedia.c
+++ b/sound/hda/codecs/cmedia.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Universal Interface for Intel High Definition Audio Codec
+ * Universal codec driver for Intel High Definition Audio Codec
  *
- * HD audio interface patch for C-Media CMI9880
+ * HD audio codec driver for C-Media CMI9880
  *
  * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
  */
@@ -17,293 +17,11 @@
 #include "hda_jack.h"
 #include "generic.h"
 
-/* CM9825 Offset Definitions */
-
-#define CM9825_VERB_SET_HPF_1 0x781
-#define CM9825_VERB_SET_HPF_2 0x785
-#define CM9825_VERB_SET_PLL 0x7a0
-#define CM9825_VERB_SET_NEG 0x7a1
-#define CM9825_VERB_SET_ADCL 0x7a2
-#define CM9825_VERB_SET_DACL 0x7a3
-#define CM9825_VERB_SET_MBIAS 0x7a4
-#define CM9825_VERB_SET_VNEG 0x7a8
-#define CM9825_VERB_SET_D2S 0x7a9
-#define CM9825_VERB_SET_DACTRL 0x7aa
-#define CM9825_VERB_SET_PDNEG 0x7ac
-#define CM9825_VERB_SET_VDO 0x7ad
-#define CM9825_VERB_SET_CDALR 0x7b0
-#define CM9825_VERB_SET_MTCBA 0x7b1
-#define CM9825_VERB_SET_OTP 0x7b2
-#define CM9825_VERB_SET_OCP 0x7b3
-#define CM9825_VERB_SET_GAD 0x7b4
-#define CM9825_VERB_SET_TMOD 0x7b5
-#define CM9825_VERB_SET_SNR 0x7b6
-
-struct cmi_spec {
-	struct hda_gen_spec gen;
-	const struct hda_verb *chip_d0_verbs;
-	const struct hda_verb *chip_d3_verbs;
-	const struct hda_verb *chip_hp_present_verbs;
-	const struct hda_verb *chip_hp_remove_verbs;
-	struct hda_codec *codec;
-	struct delayed_work unsol_hp_work;
-	int quirk;
-};
-
-static const struct hda_verb cm9825_std_d3_verbs[] = {
-	/* chip sleep verbs */
-	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
-	{0x43, CM9825_VERB_SET_PLL, 0x01},	/* PLL set */
-	{0x43, CM9825_VERB_SET_NEG, 0xc2},	/* NEG set */
-	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
-	{0x43, CM9825_VERB_SET_DACL, 0x02},	/* DACL */
-	{0x43, CM9825_VERB_SET_VNEG, 0x50},	/* VOL NEG */
-	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
-	{0x43, CM9825_VERB_SET_PDNEG, 0x04},	/* SEL OSC */
-	{0x43, CM9825_VERB_SET_CDALR, 0xf6},	/* Class D */
-	{0x43, CM9825_VERB_SET_OTP, 0xcd},	/* OTP set */
-	{}
-};
-
-static const struct hda_verb cm9825_std_d0_verbs[] = {
-	/* chip init verbs */
-	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},	/* EAPD set */
-	{0x43, CM9825_VERB_SET_SNR, 0x30},	/* SNR set */
-	{0x43, CM9825_VERB_SET_PLL, 0x00},	/* PLL set */
-	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
-	{0x43, CM9825_VERB_SET_DACL, 0x02},	/* DACL */
-	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
-	{0x43, CM9825_VERB_SET_VNEG, 0x56},	/* VOL NEG */
-	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
-	{0x43, CM9825_VERB_SET_DACTRL, 0x00},	/* DACTRL set */
-	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},	/* SEL OSC */
-	{0x43, CM9825_VERB_SET_VDO, 0x80},	/* VDO set */
-	{0x43, CM9825_VERB_SET_CDALR, 0xf4},	/* Class D */
-	{0x43, CM9825_VERB_SET_OTP, 0xcd},	/* OTP set */
-	{0x43, CM9825_VERB_SET_MTCBA, 0x61},	/* SR set */
-	{0x43, CM9825_VERB_SET_OCP, 0x33},	/* OTP set */
-	{0x43, CM9825_VERB_SET_GAD, 0x07},	/* ADC -3db */
-	{0x43, CM9825_VERB_SET_TMOD, 0x26},	/* Class D clk */
-	{0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
-		AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d},	/* Gain set */
-	{0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
-		AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d},	/* Gain set */
-	{0x43, CM9825_VERB_SET_HPF_1, 0x40},	/* HPF set */
-	{0x43, CM9825_VERB_SET_HPF_2, 0x40},	/* HPF set */
-	{}
-};
-
-static const struct hda_verb cm9825_hp_present_verbs[] = {
-	{0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},	/* PIN off */
-	{0x43, CM9825_VERB_SET_ADCL, 0x88},	/* ADC */
-	{0x43, CM9825_VERB_SET_DACL, 0xaa},	/* DACL */
-	{0x43, CM9825_VERB_SET_MBIAS, 0x10},	/* MBIAS */
-	{0x43, CM9825_VERB_SET_D2S, 0xf2},	/* depop */
-	{0x43, CM9825_VERB_SET_DACTRL, 0x00},	/* DACTRL set */
-	{0x43, CM9825_VERB_SET_VDO, 0xc4},	/* VDO set */
-	{}
-};
-
-static const struct hda_verb cm9825_hp_remove_verbs[] = {
-	{0x43, CM9825_VERB_SET_ADCL, 0x00},	/* ADC */
-	{0x43, CM9825_VERB_SET_DACL, 0x56},	/* DACL */
-	{0x43, CM9825_VERB_SET_MBIAS, 0x00},	/* MBIAS */
-	{0x43, CM9825_VERB_SET_D2S, 0x62},	/* depop */
-	{0x43, CM9825_VERB_SET_DACTRL, 0xe0},	/* DACTRL set */
-	{0x43, CM9825_VERB_SET_VDO, 0x80},	/* VDO set */
-	{0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},	/* PIN on */
-	{}
-};
-
-static void cm9825_unsol_hp_delayed(struct work_struct *work)
+static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
-	struct cmi_spec *spec =
-	    container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
-	struct hda_jack_tbl *jack;
-	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
-	bool hp_jack_plugin = false;
-	int err = 0;
-
-	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
-
-	codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
-		  (int)hp_jack_plugin, hp_pin);
-
-	if (!hp_jack_plugin) {
-		err =
-		    snd_hda_codec_write(spec->codec, 0x42, 0,
-					AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
-		if (err)
-			codec_dbg(spec->codec, "codec_write err %d\n", err);
-
-		snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
-	} else {
-		snd_hda_sequence_write(spec->codec,
-				       spec->chip_hp_present_verbs);
-	}
-
-	jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
-	if (jack) {
-		jack->block_report = 0;
-		snd_hda_jack_report_sync(spec->codec);
-	}
-}
-
-static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
-{
-	struct cmi_spec *spec = codec->spec;
-	struct hda_jack_tbl *tbl;
-
-	/* Delay enabling the HP amp, to let the mic-detection
-	 * state machine run.
-	 */
-
-	codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
-
-	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
-	if (tbl)
-		tbl->block_report = 1;
-	schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
-}
-
-static void cm9825_setup_unsol(struct hda_codec *codec)
-{
-	struct cmi_spec *spec = codec->spec;
-
-	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
-
-	snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
-}
-
-static int cm9825_init(struct hda_codec *codec)
-{
-	snd_hda_gen_init(codec);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-	return 0;
-}
-
-static void cm9825_free(struct hda_codec *codec)
-{
-	struct cmi_spec *spec = codec->spec;
-
-	cancel_delayed_work_sync(&spec->unsol_hp_work);
-	snd_hda_gen_free(codec);
-}
-
-static int cm9825_suspend(struct hda_codec *codec)
-{
-	struct cmi_spec *spec = codec->spec;
-
-	cancel_delayed_work_sync(&spec->unsol_hp_work);
-
-	snd_hda_sequence_write(codec, spec->chip_d3_verbs);
-
-	return 0;
-}
-
-static int cm9825_resume(struct hda_codec *codec)
-{
-	struct cmi_spec *spec = codec->spec;
-	hda_nid_t hp_pin = 0;
-	bool hp_jack_plugin = false;
-	int err;
-
-	err =
-	    snd_hda_codec_write(spec->codec, 0x42, 0,
-				AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
-	if (err)
-		codec_dbg(codec, "codec_write err %d\n", err);
-
-	msleep(150);		/* for depop noise */
-
-	codec->patch_ops.init(codec);
-
-	hp_pin = spec->gen.autocfg.hp_pins[0];
-	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
-
-	codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
-		  (int)hp_jack_plugin, hp_pin);
-
-	if (!hp_jack_plugin) {
-		err =
-		    snd_hda_codec_write(spec->codec, 0x42, 0,
-					AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
-
-		if (err)
-			codec_dbg(codec, "codec_write err %d\n", err);
-
-		snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
-	}
-
-	snd_hda_regmap_sync(codec);
-	hda_call_check_power_status(codec, 0x01);
-
-	return 0;
-}
-
-/*
- * stuff for auto-parser
- */
-static const struct hda_codec_ops cmi_auto_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = snd_hda_gen_init,
-	.free = snd_hda_gen_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-};
-
-static int patch_cm9825(struct hda_codec *codec)
-{
-	struct cmi_spec *spec;
-	struct auto_pin_cfg *cfg;
-	int err;
-
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
-	codec->spec = spec;
-	spec->codec = codec;
-	codec->patch_ops = cmi_auto_patch_ops;
-	codec->patch_ops.init = cm9825_init;
-	codec->patch_ops.suspend = cm9825_suspend;
-	codec->patch_ops.resume = cm9825_resume;
-	codec->patch_ops.free = cm9825_free;
-	codec->patch_ops.check_power_status = snd_hda_gen_check_power_status;
-	cfg = &spec->gen.autocfg;
-	snd_hda_gen_spec_init(&spec->gen);
-	spec->chip_d0_verbs = cm9825_std_d0_verbs;
-	spec->chip_d3_verbs = cm9825_std_d3_verbs;
-	spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
-	spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
-
-	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
-
-	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
-	if (err < 0)
-		goto error;
-	err = snd_hda_gen_parse_auto_config(codec, cfg);
-	if (err < 0)
-		goto error;
-
-	cm9825_setup_unsol(codec);
-
-	return 0;
-
- error:
-	cm9825_free(codec);
-
-	codec_info(codec, "Enter err %d\n", err);
-
-	return err;
-}
-
-static int patch_cmi9880(struct hda_codec *codec)
-{
-	struct cmi_spec *spec;
+	struct hda_gen_spec *spec;
 	struct auto_pin_cfg *cfg;
+	bool is_cmi8888 = id->vendor_id == 0x13f68888;
 	int err;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -311,9 +29,15 @@ static int patch_cmi9880(struct hda_codec *codec)
 		return -ENOMEM;
 
 	codec->spec = spec;
-	codec->patch_ops = cmi_auto_patch_ops;
-	cfg = &spec->gen.autocfg;
-	snd_hda_gen_spec_init(&spec->gen);
+	cfg = &spec->autocfg;
+	snd_hda_gen_spec_init(spec);
+
+	if (is_cmi8888) {
+		/* mask NID 0x10 from the playback volume selection;
+		 * it's a headphone boost volume handled manually below
+		 */
+		spec->out_vol_mask = (1ULL << 0x10);
+	}
 
 	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
 	if (err < 0)
@@ -322,33 +46,6 @@ static int patch_cmi9880(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	return 0;
-
- error:
-	snd_hda_gen_free(codec);
-	return err;
-}
-
-static int patch_cmi8888(struct hda_codec *codec)
-{
-	struct cmi_spec *spec;
-	struct auto_pin_cfg *cfg;
-	int err;
-
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (!spec)
-		return -ENOMEM;
-
-	codec->spec = spec;
-	codec->patch_ops = cmi_auto_patch_ops;
-	cfg = &spec->gen.autocfg;
-	snd_hda_gen_spec_init(&spec->gen);
-
-	/* mask NID 0x10 from the playback volume selection;
-	 * it's a headphone boost volume handled manually below
-	 */
-	spec->gen.out_vol_mask = (1ULL << 0x10);
-
 	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
 	if (err < 0)
 		goto error;
@@ -356,32 +53,44 @@ static int patch_cmi8888(struct hda_codec *codec)
 	if (err < 0)
 		goto error;
 
-	if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
-	    AC_JACK_HP_OUT) {
-		static const struct snd_kcontrol_new amp_kctl =
-			HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
-					 0x10, 0, HDA_OUTPUT);
-		if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
-			err = -ENOMEM;
-			goto error;
+	if (is_cmi8888) {
+		if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
+		    AC_JACK_HP_OUT) {
+			static const struct snd_kcontrol_new amp_kctl =
+				HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
+						 0x10, 0, HDA_OUTPUT);
+			if (!snd_hda_gen_add_kctl(spec, NULL, &amp_kctl)) {
+				err = -ENOMEM;
+				goto error;
+			}
 		}
 	}
 
 	return 0;
 
  error:
-	snd_hda_gen_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops cmedia_codec_ops = {
+	.probe = cmedia_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = snd_hda_gen_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
- * patch entries
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_cmedia[] = {
-	HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888),
-	HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880),
-	HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880),
-	HDA_CODEC_ENTRY(0x13f69825, "CM9825", patch_cm9825),
+	HDA_CODEC_ID(0x13f68888, "CMI8888"),
+	HDA_CODEC_ID(0x13f69880, "CMI9880"),
+	HDA_CODEC_ID(0x434d4980, "CMI9880"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
@@ -391,6 +100,7 @@ MODULE_DESCRIPTION("C-Media HD-audio codec");
 
 static struct hda_codec_driver cmedia_driver = {
 	.id = snd_hda_id_cmedia,
+	.ops = &cmedia_codec_ops,
 };
 
 module_hda_codec_driver(cmedia_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 13/27] ALSA: hda/analog: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (11 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 12/27] ALSA: hda/cmedia: Rewrite to new probe method Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 14/27] ALSA: hda/ca0110: " Takashi Iwai
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the Analog Device codec driver to use the new hda_codec_ops
probe.  The probe function had to be unified and branched with the
model type specified via driver_data instead.

Other than that, no functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/analog.c | 221 +++++++++++++++++++-------------------
 1 file changed, 111 insertions(+), 110 deletions(-)

diff --git a/sound/hda/codecs/analog.c b/sound/hda/codecs/analog.c
index 3557e06c6d2b..33aaeb44c4dc 100644
--- a/sound/hda/codecs/analog.c
+++ b/sound/hda/codecs/analog.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ * HD audio codec driver for AD1882, AD1884, AD1981HD, AD1983, AD1984,
  *   AD1986A, AD1988
  *
  * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
@@ -18,9 +18,18 @@
 #include "hda_jack.h"
 #include "generic.h"
 
+enum {
+	MODEL_AD1882,
+	MODEL_AD1884,
+	MODEL_AD1981,
+	MODEL_AD1983,
+	MODEL_AD1986A,
+	MODEL_AD1988,
+};
 
 struct ad198x_spec {
 	struct hda_gen_spec gen;
+	int model;
 
 	/* for auto parser */
 	int smux_paths[4];
@@ -111,7 +120,7 @@ static void ad198x_power_eapd(struct hda_codec *codec)
 	}
 }
 
-static int ad198x_suspend(struct hda_codec *codec)
+static int ad_codec_suspend(struct hda_codec *codec)
 {
 	snd_hda_shutup_pins(codec);
 	ad198x_power_eapd(codec);
@@ -137,7 +146,7 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled)
  * Automatic parse of I/O pins from the BIOS configuration
  */
 
-static int ad198x_auto_build_controls(struct hda_codec *codec)
+static int ad_codec_build_controls(struct hda_codec *codec)
 {
 	int err;
 
@@ -150,17 +159,6 @@ static int ad198x_auto_build_controls(struct hda_codec *codec)
 	return 0;
 }
 
-static const struct hda_codec_ops ad198x_auto_patch_ops = {
-	.build_controls = ad198x_auto_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = snd_hda_gen_init,
-	.free = snd_hda_gen_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.check_power_status = snd_hda_gen_check_power_status,
-	.suspend = ad198x_suspend,
-};
-
-
 static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -198,7 +196,6 @@ static int alloc_ad_spec(struct hda_codec *codec)
 		return -ENOMEM;
 	codec->spec = spec;
 	snd_hda_gen_spec_init(&spec->gen);
-	codec->patch_ops = ad198x_auto_patch_ops;
 	return 0;
 }
 
@@ -375,10 +372,10 @@ static const struct hda_model_fixup ad1986a_fixup_models[] = {
 
 /*
  */
-static int patch_ad1986a(struct hda_codec *codec)
+static int ad1986a_probe(struct hda_codec *codec)
 {
 	int err;
-	struct ad198x_spec *spec;
+	struct ad198x_spec *spec = codec->spec;
 	static const hda_nid_t preferred_pairs[] = {
 		0x1a, 0x03,
 		0x1b, 0x03,
@@ -388,11 +385,6 @@ static int patch_ad1986a(struct hda_codec *codec)
 		0
 	};
 
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
 	/* AD1986A has the inverted EAPD implementation */
 	codec->inv_eapd = 1;
 
@@ -418,10 +410,8 @@ static int patch_ad1986a(struct hda_codec *codec)
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = ad198x_parse_auto_config(codec, false);
-	if (err < 0) {
-		snd_hda_gen_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
@@ -507,18 +497,13 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_ad1983(struct hda_codec *codec)
+static int ad1983_probe(struct hda_codec *codec)
 {
 	static const hda_nid_t conn_0c[] = { 0x08 };
 	static const hda_nid_t conn_0d[] = { 0x09 };
-	struct ad198x_spec *spec;
+	struct ad198x_spec *spec = codec->spec;
 	int err;
 
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
 	spec->gen.mixer_nid = 0x0e;
 	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
@@ -529,15 +514,11 @@ static int patch_ad1983(struct hda_codec *codec)
 
 	err = ad198x_parse_auto_config(codec, false);
 	if (err < 0)
-		goto error;
+		return err;
 	err = ad1983_add_spdif_mux_ctl(codec);
 	if (err < 0)
-		goto error;
+		return err;
 	return 0;
-
- error:
-	snd_hda_gen_free(codec);
-	return err;
 }
 
 
@@ -597,16 +578,11 @@ static const struct hda_quirk ad1981_fixup_tbl[] = {
 	{}
 };
 
-static int patch_ad1981(struct hda_codec *codec)
+static int ad1981_probe(struct hda_codec *codec)
 {
-	struct ad198x_spec *spec;
+	struct ad198x_spec *spec = codec->spec;
 	int err;
 
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return -ENOMEM;
-	spec = codec->spec;
-
 	spec->gen.mixer_nid = 0x0e;
 	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
@@ -616,18 +592,14 @@ static int patch_ad1981(struct hda_codec *codec)
 
 	err = ad198x_parse_auto_config(codec, false);
 	if (err < 0)
-		goto error;
+		return err;
 	err = ad1983_add_spdif_mux_ctl(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
-
- error:
-	snd_hda_gen_free(codec);
-	return err;
 }
 
 
@@ -776,7 +748,7 @@ static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
 	.put = ad1988_auto_smux_enum_put,
 };
 
-static int ad1988_auto_init(struct hda_codec *codec)
+static int ad_codec_init(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
 	int i, err;
@@ -784,6 +756,8 @@ static int ad1988_auto_init(struct hda_codec *codec)
 	err = snd_hda_gen_init(codec);
 	if (err < 0)
 		return err;
+	if (spec->model != MODEL_AD1988)
+		return 0;
 	if (!spec->gen.autocfg.dig_outs)
 		return 0;
 
@@ -854,8 +828,6 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
 	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
 		return -ENOMEM;
 
-	codec->patch_ops.init = ad1988_auto_init;
-
 	return 0;
 }
 
@@ -889,16 +861,11 @@ static const struct hda_model_fixup ad1988_fixup_models[] = {
 	{}
 };
 
-static int patch_ad1988(struct hda_codec *codec)
+static int ad1988_probe(struct hda_codec *codec)
 {
-	struct ad198x_spec *spec;
+	struct ad198x_spec *spec = codec->spec;
 	int err;
 
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
 	spec->gen.mixer_nid = 0x20;
 	spec->gen.mixer_merge_nid = 0x21;
 	spec->gen.beep_nid = 0x10;
@@ -909,18 +876,14 @@ static int patch_ad1988(struct hda_codec *codec)
 
 	err = ad198x_parse_auto_config(codec, true);
 	if (err < 0)
-		goto error;
+		return err;
 	err = ad1988_add_spdif_mux_ctl(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
-
- error:
-	snd_hda_gen_free(codec);
-	return err;
 }
 
 
@@ -1069,16 +1032,11 @@ static const struct hda_quirk ad1884_fixup_tbl[] = {
 };
 
 
-static int patch_ad1884(struct hda_codec *codec)
+static int ad1884_probe(struct hda_codec *codec)
 {
-	struct ad198x_spec *spec;
+	struct ad198x_spec *spec = codec->spec;
 	int err;
 
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
 	spec->gen.mixer_nid = 0x20;
 	spec->gen.mixer_merge_nid = 0x21;
 	spec->gen.beep_nid = 0x10;
@@ -1089,18 +1047,14 @@ static int patch_ad1884(struct hda_codec *codec)
 
 	err = ad198x_parse_auto_config(codec, true);
 	if (err < 0)
-		goto error;
+		return err;
 	err = ad1983_add_spdif_mux_ctl(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
-
- error:
-	snd_hda_gen_free(codec);
-	return err;
 }
 
 /*
@@ -1115,53 +1069,99 @@ static int patch_ad1884(struct hda_codec *codec)
  * port-G - rear clfe-out (6stack)
  */
 
-static int patch_ad1882(struct hda_codec *codec)
+static int ad1882_probe(struct hda_codec *codec)
 {
-	struct ad198x_spec *spec;
+	struct ad198x_spec *spec = codec->spec;
 	int err;
 
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
 	spec->gen.mixer_nid = 0x20;
 	spec->gen.mixer_merge_nid = 0x21;
 	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 	err = ad198x_parse_auto_config(codec, true);
 	if (err < 0)
-		goto error;
+		return err;
 	err = ad1988_add_spdif_mux_ctl(codec);
 	if (err < 0)
-		goto error;
+		return err;
 	return 0;
-
- error:
-	snd_hda_gen_free(codec);
-	return err;
 }
 
-
 /*
- * patch entries
+ * driver entries
  */
+static int ad_codec_probe(struct hda_codec *codec,
+			  const struct hda_device_id *id)
+{
+	struct ad198x_spec *spec;
+	int err;
+
+	err = alloc_ad_spec(codec);
+	if (err < 0)
+		return -ENOMEM;
+	spec = codec->spec;
+	spec->model = id->driver_data;
+
+	switch (spec->model) {
+	case MODEL_AD1882:
+		err = ad1882_probe(codec);
+		break;
+	case MODEL_AD1884:
+		err = ad1884_probe(codec);
+		break;
+	case MODEL_AD1981:
+		err = ad1981_probe(codec);
+		break;
+	case MODEL_AD1983:
+		err = ad1983_probe(codec);
+		break;
+	case MODEL_AD1986A:
+		err = ad1986a_probe(codec);
+		break;
+	case MODEL_AD1988:
+		err = ad1988_probe(codec);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	if (err < 0) {
+		snd_hda_gen_remove(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct hda_codec_ops ad_codec_ops = {
+	.probe = ad_codec_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = ad_codec_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = ad_codec_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = ad_codec_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 static const struct hda_device_id snd_hda_id_analog[] = {
-	HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
-	HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
-	HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
-	HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
-	HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
-	HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
-	HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
-	HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
-	HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
-	HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
-	HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
-	HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
-	HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
-	HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
-	HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
+	HDA_CODEC_ID_MODEL(0x11d4184a, "AD1884A", MODEL_AD1884),
+	HDA_CODEC_ID_MODEL(0x11d41882, "AD1882", MODEL_AD1882),
+	HDA_CODEC_ID_MODEL(0x11d41883, "AD1883", MODEL_AD1884),
+	HDA_CODEC_ID_MODEL(0x11d41884, "AD1884", MODEL_AD1884),
+	HDA_CODEC_ID_MODEL(0x11d4194a, "AD1984A", MODEL_AD1884),
+	HDA_CODEC_ID_MODEL(0x11d4194b, "AD1984B", MODEL_AD1884),
+	HDA_CODEC_ID_MODEL(0x11d41981, "AD1981", MODEL_AD1981),
+	HDA_CODEC_ID_MODEL(0x11d41983, "AD1983", MODEL_AD1983),
+	HDA_CODEC_ID_MODEL(0x11d41984, "AD1984", MODEL_AD1884),
+	HDA_CODEC_ID_MODEL(0x11d41986, "AD1986A", MODEL_AD1986A),
+	HDA_CODEC_ID_MODEL(0x11d41988, "AD1988", MODEL_AD1988),
+	HDA_CODEC_ID_MODEL(0x11d4198b, "AD1988B", MODEL_AD1988),
+	HDA_CODEC_ID_MODEL(0x11d4882a, "AD1882A", MODEL_AD1882),
+	HDA_CODEC_ID_MODEL(0x11d4989a, "AD1989A", MODEL_AD1988),
+	HDA_CODEC_ID_MODEL(0x11d4989b, "AD1989B", MODEL_AD1988),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
@@ -1171,6 +1171,7 @@ MODULE_DESCRIPTION("Analog Devices HD-audio codec");
 
 static struct hda_codec_driver analog_driver = {
 	.id = snd_hda_id_analog,
+	.ops = &ad_codec_ops,
 };
 
 module_hda_codec_driver(analog_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 14/27] ALSA: hda/ca0110: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (12 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 13/27] ALSA: hda/analog: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 15/27] ALSA: hda/cirrus: Split to cs420x and cs421x drivers Takashi Iwai
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the CA0110 codec driver to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/ca0110.c | 35 +++++++++++++++++------------------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/sound/hda/codecs/ca0110.c b/sound/hda/codecs/ca0110.c
index 0353544435b9..c75a9ff9460d 100644
--- a/sound/hda/codecs/ca0110.c
+++ b/sound/hda/codecs/ca0110.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for Creative X-Fi CA0110-IBG chip
+ * HD audio codec driver for Creative X-Fi CA0110-IBG chip
  *
  * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
  */
@@ -15,15 +15,6 @@
 #include "hda_jack.h"
 #include "generic.h"
 
-
-static const struct hda_codec_ops ca0110_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = snd_hda_gen_init,
-	.free = snd_hda_gen_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-};
-
 static int ca0110_parse_auto_config(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec = codec->spec;
@@ -39,8 +30,7 @@ static int ca0110_parse_auto_config(struct hda_codec *codec)
 	return 0;
 }
 
-
-static int patch_ca0110(struct hda_codec *codec)
+static int ca0110_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct hda_gen_spec *spec;
 	int err;
@@ -50,7 +40,6 @@ static int patch_ca0110(struct hda_codec *codec)
 		return -ENOMEM;
 	snd_hda_gen_spec_init(spec);
 	codec->spec = spec;
-	codec->patch_ops = ca0110_patch_ops;
 
 	spec->multi_cap_vol = 1;
 	codec->bus->core.needs_damn_long_delay = 1;
@@ -62,18 +51,27 @@ static int patch_ca0110(struct hda_codec *codec)
 	return 0;
 
  error:
-	snd_hda_gen_free(codec);
+	snd_hda_gen_remove(codec);
 	return err;
 }
 
 
+static const struct hda_codec_ops ca0110_codec_ops = {
+	.probe = ca0110_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = snd_hda_gen_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+};
+
 /*
- * patch entries
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_ca0110[] = {
-	HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110),
-	HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110),
-	HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110),
+	HDA_CODEC_ID(0x1102000a, "CA0110-IBG"),
+	HDA_CODEC_ID(0x1102000b, "CA0110-IBG"),
+	HDA_CODEC_ID(0x1102000d, "SB0880 X-Fi"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110);
@@ -83,6 +81,7 @@ MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
 
 static struct hda_codec_driver ca0110_driver = {
 	.id = snd_hda_id_ca0110,
+	.ops = &ca0110_codec_ops,
 };
 
 module_hda_codec_driver(ca0110_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 15/27] ALSA: hda/cirrus: Split to cs420x and cs421x drivers
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (13 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 14/27] ALSA: hda/ca0110: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 16/27] ALSA: hda/cs8409: Rewrite to new probe method Takashi Iwai
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Since the codec ops for CS420x and CS421x are fairly independent,
split the cirrus codec driver into two drivers, snd-hda-codec-cs420x
and snd-hda-code-cs421x.  Together with the split, convert to the new
hda_codec_ops probe.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/cirrus/Kconfig               |  20 +-
 sound/hda/codecs/cirrus/Makefile              |   6 +-
 .../hda/codecs/cirrus/{cirrus.c => cs420x.c}  | 526 +---------------
 sound/hda/codecs/cirrus/cs421x.c              | 590 ++++++++++++++++++
 4 files changed, 643 insertions(+), 499 deletions(-)
 rename sound/hda/codecs/cirrus/{cirrus.c => cs420x.c} (61%)
 create mode 100644 sound/hda/codecs/cirrus/cs421x.c

diff --git a/sound/hda/codecs/cirrus/Kconfig b/sound/hda/codecs/cirrus/Kconfig
index f6cefb65c5f8..b3a5968e9a02 100644
--- a/sound/hda/codecs/cirrus/Kconfig
+++ b/sound/hda/codecs/cirrus/Kconfig
@@ -1,14 +1,24 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-config SND_HDA_CODEC_CIRRUS
-	tristate "Build Cirrus Logic codec support"
+config SND_HDA_CODEC_CS420X
+	tristate "Build Cirrus Logic CS420x codec support"
 	select SND_HDA_GENERIC
 	help
-	  Say Y or M here to include Cirrus Logic codec support in
-	  snd-hda-intel driver, such as CS4206.
+	  Say Y or M here to include Cirrus Logic CS420x codec support in
+	  snd-hda-intel driver
 
 comment "Set to Y if you want auto-loading the codec driver"
-	depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
+	depends on SND_HDA=y && SND_HDA_CODEC_CS420X=m
+
+config SND_HDA_CODEC_CS421X
+	tristate "Build Cirrus Logic CS421x codec support"
+	select SND_HDA_GENERIC
+	help
+	  Say Y or M here to include Cirrus Logic CS421x codec support in
+	  snd-hda-intel driver
+
+comment "Set to Y if you want auto-loading the codec driver"
+	depends on SND_HDA=y && SND_HDA_CODEC_CS421X=m
 
 config SND_HDA_CODEC_CS8409
 	tristate "Build Cirrus Logic HDA bridge support"
diff --git a/sound/hda/codecs/cirrus/Makefile b/sound/hda/codecs/cirrus/Makefile
index fa40c893fb09..dda1873ebcf5 100644
--- a/sound/hda/codecs/cirrus/Makefile
+++ b/sound/hda/codecs/cirrus/Makefile
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-ccflags-y += -I$(src)/../../common
 
-snd-hda-codec-cirrus-y :=	cirrus.o
+snd-hda-codec-cs420x-y :=	cs420x.o
+snd-hda-codec-cs421x-y :=	cs421x.o
 snd-hda-codec-cs8409-y :=	cs8409.o cs8409-tables.o
 
-obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
+obj-$(CONFIG_SND_HDA_CODEC_CS420X) += snd-hda-codec-cs420x.o
+obj-$(CONFIG_SND_HDA_CODEC_CS421X) += snd-hda-codec-cs421x.o
 obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
diff --git a/sound/hda/codecs/cirrus/cirrus.c b/sound/hda/codecs/cirrus/cs420x.c
similarity index 61%
rename from sound/hda/codecs/cirrus/cirrus.c
rename to sound/hda/codecs/cirrus/cs420x.c
index 81ea66c4e9d3..823220d5cada 100644
--- a/sound/hda/codecs/cirrus/cirrus.c
+++ b/sound/hda/codecs/cirrus/cs420x.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for Cirrus Logic CS420x chip
+ * Cirrus Logic CS420x HD-audio codec
  *
  * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
  */
@@ -17,9 +17,6 @@
 #include "hda_jack.h"
 #include "../generic.h"
 
-/*
- */
-
 struct cs_spec {
 	struct hda_gen_spec gen;
 
@@ -29,10 +26,6 @@ struct cs_spec {
 	unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
 	unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
 
-	/* CS421x */
-	unsigned int spdif_detect:1;
-	unsigned int spdif_present:1;
-	unsigned int sense_b:1;
 	hda_nid_t vendor_nid;
 
 	/* for MBP SPDIF control */
@@ -56,13 +49,6 @@ enum {
 	CS420X_APPLE = CS420X_GPIO_13,
 };
 
-/* CS421x boards */
-enum {
-	CS421X_CDB4210,
-	CS421X_SENSE_B,
-	CS421X_STUMPY,
-};
-
 /* Vendor-specific processing widget */
 #define CS420X_VENDOR_NID	0x11
 #define CS_DIG_OUT1_PIN_NID	0x10
@@ -105,28 +91,6 @@ enum {
 /* Cirrus Logic CS4208 */
 #define CS4208_VENDOR_NID	0x24
 
-/*
- * Cirrus Logic CS4210
- *
- * 1 DAC => HP(sense) / Speakers,
- * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
- * 1 SPDIF OUT => SPDIF Trasmitter(sense)
- */
-#define CS4210_DAC_NID		0x02
-#define CS4210_ADC_NID		0x03
-#define CS4210_VENDOR_NID	0x0B
-#define CS421X_DMIC_PIN_NID	0x09 /* Port E */
-#define CS421X_SPDIF_PIN_NID	0x0A /* Port H */
-
-#define CS421X_IDX_DEV_CFG	0x01
-#define CS421X_IDX_ADC_CFG	0x02
-#define CS421X_IDX_DAC_CFG	0x03
-#define CS421X_IDX_SPK_CTL	0x04
-
-/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
-#define CS4213_VENDOR_NID	0x09
-
-
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
 	struct cs_spec *spec = codec->spec;
@@ -158,9 +122,6 @@ static void cs_automute(struct hda_codec *codec)
 {
 	struct cs_spec *spec = codec->spec;
 
-	/* mute HPs if spdif jack (SENSE_B) is present */
-	spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
-
 	snd_hda_gen_update_outputs(codec);
 
 	if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
@@ -331,16 +292,6 @@ static int cs_build_controls(struct hda_codec *codec)
 	return 0;
 }
 
-#define cs_free		snd_hda_gen_free
-
-static const struct hda_codec_ops cs_patch_ops = {
-	.build_controls = cs_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = cs_init,
-	.free = cs_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-};
-
 static int cs_parse_auto_config(struct hda_codec *codec)
 {
 	struct cs_spec *spec = codec->spec;
@@ -584,17 +535,10 @@ static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
 	return spec;
 }
 
-static int patch_cs420x(struct hda_codec *codec)
+static int cs420x_probe(struct hda_codec *codec)
 {
-	struct cs_spec *spec;
 	int err;
 
-	spec = cs_alloc_spec(codec, CS420X_VENDOR_NID);
-	if (!spec)
-		return -ENOMEM;
-
-	codec->patch_ops = cs_patch_ops;
-	spec->gen.automute_hook = cs_automute;
 	codec->single_adc_amp = 1;
 
 	snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
@@ -603,15 +547,11 @@ static int patch_cs420x(struct hda_codec *codec)
 
 	err = cs_parse_auto_config(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
-
- error:
-	cs_free(codec);
-	return err;
 }
 
 /*
@@ -766,17 +706,11 @@ static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
 	snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
 }
 
-static int patch_cs4208(struct hda_codec *codec)
+static int cs4208_probe(struct hda_codec *codec)
 {
-	struct cs_spec *spec;
+	struct cs_spec *spec = codec->spec;
 	int err;
 
-	spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
-	if (!spec)
-		return -ENOMEM;
-
-	codec->patch_ops = cs_patch_ops;
-	spec->gen.automute_hook = cs_automute;
 	/* exclude NID 0x10 (HP) from output volumes due to different steps */
 	spec->gen.out_vol_mask = 1ULL << 0x10;
 
@@ -792,452 +726,60 @@ static int patch_cs4208(struct hda_codec *codec)
 
 	err = cs_parse_auto_config(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
-
- error:
-	cs_free(codec);
-	return err;
 }
 
-/*
- * Cirrus Logic CS4210
- *
- * 1 DAC => HP(sense) / Speakers,
- * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
- * 1 SPDIF OUT => SPDIF Trasmitter(sense)
- */
-
-/* CS4210 board names */
-static const struct hda_model_fixup cs421x_models[] = {
-	{ .id = CS421X_CDB4210, .name = "cdb4210" },
-	{ .id = CS421X_STUMPY, .name = "stumpy" },
-	{}
-};
-
-static const struct hda_quirk cs421x_fixup_tbl[] = {
-	/* Test Intel board + CDB2410  */
-	SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
-	{} /* terminator */
-};
-
-/* CS4210 board pinconfigs */
-/* Default CS4210 (CDB4210)*/
-static const struct hda_pintbl cdb4210_pincfgs[] = {
-	{ 0x05, 0x0321401f },
-	{ 0x06, 0x90170010 },
-	{ 0x07, 0x03813031 },
-	{ 0x08, 0xb7a70037 },
-	{ 0x09, 0xb7a6003e },
-	{ 0x0a, 0x034510f0 },
-	{} /* terminator */
-};
-
-/* Stumpy ChromeBox */
-static const struct hda_pintbl stumpy_pincfgs[] = {
-	{ 0x05, 0x022120f0 },
-	{ 0x06, 0x901700f0 },
-	{ 0x07, 0x02a120f0 },
-	{ 0x08, 0x77a70037 },
-	{ 0x09, 0x77a6003e },
-	{ 0x0a, 0x434510f0 },
-	{} /* terminator */
-};
-
-/* Setup GPIO/SENSE for each board (if used) */
-static void cs421x_fixup_sense_b(struct hda_codec *codec,
-				 const struct hda_fixup *fix, int action)
-{
-	struct cs_spec *spec = codec->spec;
-
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
-		spec->sense_b = 1;
-}
-
-static const struct hda_fixup cs421x_fixups[] = {
-	[CS421X_CDB4210] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = cdb4210_pincfgs,
-		.chained = true,
-		.chain_id = CS421X_SENSE_B,
-	},
-	[CS421X_SENSE_B] = {
-		.type = HDA_FIXUP_FUNC,
-		.v.func = cs421x_fixup_sense_b,
-	},
-	[CS421X_STUMPY] = {
-		.type = HDA_FIXUP_PINS,
-		.v.pins = stumpy_pincfgs,
-	},
-};
-
-static const struct hda_verb cs421x_coef_init_verbs[] = {
-	{0x0B, AC_VERB_SET_PROC_STATE, 1},
-	{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
-	/*
-	 *  Disable Coefficient Index Auto-Increment(DAI)=1,
-	 *  PDREF=0
-	 */
-	{0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
-	/* ADC SZCMode = Digital Soft Ramp */
-	{0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
-	{0x0B, AC_VERB_SET_PROC_COEF,
-	 (0x0002 /* DAC SZCMode = Digital Soft Ramp */
-	  | 0x0004 /* Mute DAC on FIFO error */
-	  | 0x0008 /* Enable DAC High Pass Filter */
-	  )},
-	{} /* terminator */
-};
-
-/* Errata: CS4210 rev A1 Silicon
- *
- * http://www.cirrus.com/en/pubs/errata/
- *
- * Description:
- * 1. Performance degredation is present in the ADC.
- * 2. Speaker output is not completely muted upon HP detect.
- * 3. Noise is present when clipping occurs on the amplified
- *    speaker outputs.
- *
- * Workaround:
- * The following verb sequence written to the registers during
- * initialization will correct the issues listed above.
- */
-
-static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
-	{0x0B, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
-	{0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
-	{0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
-	{0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
-	{0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
-
-	{0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
-	{0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
-
-	{} /* terminator */
-};
-
-/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
-static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
-
-static int cs421x_boost_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.min = 0;
-	uinfo->value.integer.max = 3;
-	return 0;
-}
-
-static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-
-	ucontrol->value.integer.value[0] =
-		cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
-	return 0;
-}
-
-static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-
-	unsigned int vol = ucontrol->value.integer.value[0];
-	unsigned int coef =
-		cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
-	unsigned int original_coef = coef;
-
-	coef &= ~0x0003;
-	coef |= (vol & 0x0003);
-	if (original_coef != coef) {
-		cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
-		return 1;
-	}
-
-	return 0;
-}
-
-static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
-
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-			SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-	.name = "Speaker Boost Playback Volume",
-	.info = cs421x_boost_vol_info,
-	.get = cs421x_boost_vol_get,
-	.put = cs421x_boost_vol_put,
-	.tlv = { .p = cs421x_speaker_boost_db_scale },
-};
-
-static void cs4210_pinmux_init(struct hda_codec *codec)
-{
-	struct cs_spec *spec = codec->spec;
-	unsigned int def_conf, coef;
-
-	/* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
-	coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
-
-	if (spec->gpio_mask)
-		coef |= 0x0008; /* B1,B2 are GPIOs */
-	else
-		coef &= ~0x0008;
-
-	if (spec->sense_b)
-		coef |= 0x0010; /* B2 is SENSE_B, not inverted  */
-	else
-		coef &= ~0x0010;
-
-	cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
-
-	if ((spec->gpio_mask || spec->sense_b) &&
-	    is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
-
-		/*
-		 *  GPIO or SENSE_B forced - disconnect the DMIC pin.
-		 */
-		def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
-		def_conf &= ~AC_DEFCFG_PORT_CONN;
-		def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
-		snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
-	}
-}
-
-static void cs4210_spdif_automute(struct hda_codec *codec,
-				  struct hda_jack_callback *tbl)
-{
-	struct cs_spec *spec = codec->spec;
-	bool spdif_present = false;
-	hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
-
-	/* detect on spdif is specific to CS4210 */
-	if (!spec->spdif_detect ||
-	    spec->vendor_nid != CS4210_VENDOR_NID)
-		return;
-
-	spdif_present = snd_hda_jack_detect(codec, spdif_pin);
-	if (spdif_present == spec->spdif_present)
-		return;
-
-	spec->spdif_present = spdif_present;
-	/* SPDIF TX on/off */
-	snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
-
-	cs_automute(codec);
-}
-
-static void parse_cs421x_digital(struct hda_codec *codec)
-{
-	struct cs_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-	int i;
-
-	for (i = 0; i < cfg->dig_outs; i++) {
-		hda_nid_t nid = cfg->dig_out_pins[i];
-
-		if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-			spec->spdif_detect = 1;
-			snd_hda_jack_detect_enable_callback(codec, nid,
-							    cs4210_spdif_automute);
-		}
-	}
-}
-
-static int cs421x_init(struct hda_codec *codec)
-{
-	struct cs_spec *spec = codec->spec;
-
-	if (spec->vendor_nid == CS4210_VENDOR_NID) {
-		snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
-		snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
-		cs4210_pinmux_init(codec);
-	}
-
-	snd_hda_gen_init(codec);
-
-	if (spec->gpio_mask) {
-		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
-				    spec->gpio_mask);
-		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
-				    spec->gpio_dir);
-		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-				    spec->gpio_data);
-	}
-
-	init_input_coef(codec);
-
-	cs4210_spdif_automute(codec, NULL);
-
-	return 0;
-}
-
-static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
-{
-	unsigned int caps;
-
-	/* set the upper-limit for mixer amp to 0dB */
-	caps = query_amp_caps(codec, dac, HDA_OUTPUT);
-	caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
-	caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
-		<< AC_AMPCAP_NUM_STEPS_SHIFT;
-	snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
-}
-
-static int cs421x_parse_auto_config(struct hda_codec *codec)
-{
-	struct cs_spec *spec = codec->spec;
-	hda_nid_t dac = CS4210_DAC_NID;
-	int err;
-
-	fix_volume_caps(codec, dac);
-
-	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
-	if (err < 0)
-		return err;
-
-	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-	if (err < 0)
-		return err;
-
-	parse_cs421x_digital(codec);
-
-	if (spec->gen.autocfg.speaker_outs &&
-	    spec->vendor_nid == CS4210_VENDOR_NID) {
-		if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
-					  &cs421x_speaker_boost_ctl))
-			return -ENOMEM;
-	}
-
-	return 0;
-}
-
-/*
- *	Manage PDREF, when transitioning to D3hot
- *	(DAC,ADC) -> D3, PDREF=1, AFG->D3
- */
-static int cs421x_suspend(struct hda_codec *codec)
-{
-	struct cs_spec *spec = codec->spec;
-	unsigned int coef;
-
-	snd_hda_shutup_pins(codec);
-
-	snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
-			    AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
-	snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
-			    AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
-
-	if (spec->vendor_nid == CS4210_VENDOR_NID) {
-		coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
-		coef |= 0x0004; /* PDREF */
-		cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
-	}
-
-	return 0;
-}
-
-static const struct hda_codec_ops cs421x_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = cs421x_init,
-	.free = cs_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.suspend = cs421x_suspend,
-};
-
-static int patch_cs4210(struct hda_codec *codec)
+static int cs_codec_probe(struct hda_codec *codec,
+			  const struct hda_device_id *id)
 {
 	struct cs_spec *spec;
 	int err;
 
-	spec = cs_alloc_spec(codec, CS4210_VENDOR_NID);
+	spec = cs_alloc_spec(codec, id->driver_data);
 	if (!spec)
 		return -ENOMEM;
-
-	codec->patch_ops = cs421x_patch_ops;
 	spec->gen.automute_hook = cs_automute;
 
-	snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
-			   cs421x_fixups);
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-	/*
-	 *  Update the GPIO/DMIC/SENSE_B pinmux before the configuration
-	 *   is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
-	 *   is disabled.
-	 */
-	cs4210_pinmux_init(codec);
-
-	err = cs421x_parse_auto_config(codec);
+	if (spec->vendor_nid == CS4208_VENDOR_NID)
+		err = cs4208_probe(codec);
+	else
+		err = cs420x_probe(codec);
 	if (err < 0)
-		goto error;
-
-	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-	return 0;
-
- error:
-	cs_free(codec);
+		snd_hda_gen_remove(codec);
 	return err;
 }
 
-static int patch_cs4213(struct hda_codec *codec)
-{
-	struct cs_spec *spec;
-	int err;
-
-	spec = cs_alloc_spec(codec, CS4213_VENDOR_NID);
-	if (!spec)
-		return -ENOMEM;
-
-	codec->patch_ops = cs421x_patch_ops;
-
-	err = cs421x_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	cs_free(codec);
-	return err;
-}
+static const struct hda_codec_ops cs_codec_ops = {
+	.probe = cs_codec_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = cs_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = cs_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
 
 /*
- * patch entries
+ * driver entries
  */
-static const struct hda_device_id snd_hda_id_cirrus[] = {
-	HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
-	HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
-	HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
-	HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
-	HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
+static const struct hda_device_id snd_hda_id_cs420x[] = {
+	HDA_CODEC_ID_MODEL(0x10134206, "CS4206", CS420X_VENDOR_NID),
+	HDA_CODEC_ID_MODEL(0x10134207, "CS4207", CS420X_VENDOR_NID),
+	HDA_CODEC_ID_MODEL(0x10134208, "CS4208", CS4208_VENDOR_NID),
 	{} /* terminator */
 };
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs420x);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
+MODULE_DESCRIPTION("Cirrus Logic CS420x HD-audio codec");
 
-static struct hda_codec_driver cirrus_driver = {
-	.id = snd_hda_id_cirrus,
+static struct hda_codec_driver cs420x_driver = {
+	.id = snd_hda_id_cs420x,
+	.ops = &cs_codec_ops,
 };
 
-module_hda_codec_driver(cirrus_driver);
+module_hda_codec_driver(cs420x_driver);
diff --git a/sound/hda/codecs/cirrus/cs421x.c b/sound/hda/codecs/cirrus/cs421x.c
new file mode 100644
index 000000000000..a93e2e0bb391
--- /dev/null
+++ b/sound/hda/codecs/cirrus/cs421x.c
@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cirrus Logic CS421x HD-audio codec
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <linux/pci.h>
+#include <sound/tlv.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "../generic.h"
+
+struct cs_spec {
+	struct hda_gen_spec gen;
+
+	unsigned int gpio_mask;
+	unsigned int gpio_dir;
+	unsigned int gpio_data;
+	unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
+	unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
+
+	/* CS421x */
+	unsigned int spdif_detect:1;
+	unsigned int spdif_present:1;
+	unsigned int sense_b:1;
+	hda_nid_t vendor_nid;
+
+	/* for MBP SPDIF control */
+	int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol);
+};
+
+/* CS421x boards */
+enum {
+	CS421X_CDB4210,
+	CS421X_SENSE_B,
+	CS421X_STUMPY,
+};
+
+/* Vendor-specific processing widget */
+#define CS_DIG_OUT1_PIN_NID	0x10
+#define CS_DIG_OUT2_PIN_NID	0x15
+#define CS_DMIC1_PIN_NID	0x0e
+#define CS_DMIC2_PIN_NID	0x12
+
+/* coef indices */
+#define IDX_SPDIF_STAT		0x0000
+#define IDX_SPDIF_CTL		0x0001
+#define IDX_ADC_CFG		0x0002
+/* SZC bitmask, 4 modes below:
+ * 0 = immediate,
+ * 1 = digital immediate, analog zero-cross
+ * 2 = digtail & analog soft-ramp
+ * 3 = digital soft-ramp, analog zero-cross
+ */
+#define   CS_COEF_ADC_SZC_MASK		(3 << 0)
+#define   CS_COEF_ADC_MIC_SZC_MODE	(3 << 0) /* SZC setup for mic */
+#define   CS_COEF_ADC_LI_SZC_MODE	(3 << 0) /* SZC setup for line-in */
+/* PGA mode: 0 = differential, 1 = signle-ended */
+#define   CS_COEF_ADC_MIC_PGA_MODE	(1 << 5) /* PGA setup for mic */
+#define   CS_COEF_ADC_LI_PGA_MODE	(1 << 6) /* PGA setup for line-in */
+#define IDX_DAC_CFG		0x0003
+/* SZC bitmask, 4 modes below:
+ * 0 = Immediate
+ * 1 = zero-cross
+ * 2 = soft-ramp
+ * 3 = soft-ramp on zero-cross
+ */
+#define   CS_COEF_DAC_HP_SZC_MODE	(3 << 0) /* nid 0x02 */
+#define   CS_COEF_DAC_LO_SZC_MODE	(3 << 2) /* nid 0x03 */
+#define   CS_COEF_DAC_SPK_SZC_MODE	(3 << 4) /* nid 0x04 */
+
+#define IDX_BEEP_CFG		0x0004
+/* 0x0008 - test reg key */
+/* 0x0009 - 0x0014 -> 12 test regs */
+/* 0x0015 - visibility reg */
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Transmitter(sense)
+ */
+#define CS4210_DAC_NID		0x02
+#define CS4210_ADC_NID		0x03
+#define CS4210_VENDOR_NID	0x0B
+#define CS421X_DMIC_PIN_NID	0x09 /* Port E */
+#define CS421X_SPDIF_PIN_NID	0x0A /* Port H */
+
+#define CS421X_IDX_DEV_CFG	0x01
+#define CS421X_IDX_ADC_CFG	0x02
+#define CS421X_IDX_DAC_CFG	0x03
+#define CS421X_IDX_SPK_CTL	0x04
+
+/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
+#define CS4213_VENDOR_NID	0x09
+
+
+static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
+{
+	struct cs_spec *spec = codec->spec;
+
+	snd_hda_codec_write(codec, spec->vendor_nid, 0,
+			    AC_VERB_SET_COEF_INDEX, idx);
+	return snd_hda_codec_read(codec, spec->vendor_nid, 0,
+				  AC_VERB_GET_PROC_COEF, 0);
+}
+
+static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
+				      unsigned int coef)
+{
+	struct cs_spec *spec = codec->spec;
+
+	snd_hda_codec_write(codec, spec->vendor_nid, 0,
+			    AC_VERB_SET_COEF_INDEX, idx);
+	snd_hda_codec_write(codec, spec->vendor_nid, 0,
+			    AC_VERB_SET_PROC_COEF, coef);
+}
+
+/*
+ * auto-mute and auto-mic switching
+ * CS421x auto-output redirecting
+ * HP/SPK/SPDIF
+ */
+
+static void cs_automute(struct hda_codec *codec)
+{
+	struct cs_spec *spec = codec->spec;
+
+	/* mute HPs if spdif jack (SENSE_B) is present */
+	spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
+
+	snd_hda_gen_update_outputs(codec);
+
+	if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
+		if (spec->gen.automute_speaker)
+			spec->gpio_data = spec->gen.hp_jack_present ?
+				spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
+		else
+			spec->gpio_data =
+				spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+		snd_hda_codec_write(codec, 0x01, 0,
+				    AC_VERB_SET_GPIO_DATA, spec->gpio_data);
+	}
+}
+
+static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int val;
+
+	val = snd_hda_codec_get_pincfg(codec, nid);
+	return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
+}
+
+static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
+{
+	struct cs_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return NULL;
+	codec->spec = spec;
+	spec->vendor_nid = vendor_nid;
+	codec->power_save_node = 1;
+	snd_hda_gen_spec_init(&spec->gen);
+
+	return spec;
+}
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Transmitter(sense)
+ */
+
+/* CS4210 board names */
+static const struct hda_model_fixup cs421x_models[] = {
+	{ .id = CS421X_CDB4210, .name = "cdb4210" },
+	{ .id = CS421X_STUMPY, .name = "stumpy" },
+	{}
+};
+
+static const struct hda_quirk cs421x_fixup_tbl[] = {
+	/* Test Intel board + CDB2410  */
+	SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
+	{} /* terminator */
+};
+
+/* CS4210 board pinconfigs */
+/* Default CS4210 (CDB4210)*/
+static const struct hda_pintbl cdb4210_pincfgs[] = {
+	{ 0x05, 0x0321401f },
+	{ 0x06, 0x90170010 },
+	{ 0x07, 0x03813031 },
+	{ 0x08, 0xb7a70037 },
+	{ 0x09, 0xb7a6003e },
+	{ 0x0a, 0x034510f0 },
+	{} /* terminator */
+};
+
+/* Stumpy ChromeBox */
+static const struct hda_pintbl stumpy_pincfgs[] = {
+	{ 0x05, 0x022120f0 },
+	{ 0x06, 0x901700f0 },
+	{ 0x07, 0x02a120f0 },
+	{ 0x08, 0x77a70037 },
+	{ 0x09, 0x77a6003e },
+	{ 0x0a, 0x434510f0 },
+	{} /* terminator */
+};
+
+/* Setup GPIO/SENSE for each board (if used) */
+static void cs421x_fixup_sense_b(struct hda_codec *codec,
+				 const struct hda_fixup *fix, int action)
+{
+	struct cs_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+		spec->sense_b = 1;
+}
+
+static const struct hda_fixup cs421x_fixups[] = {
+	[CS421X_CDB4210] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = cdb4210_pincfgs,
+		.chained = true,
+		.chain_id = CS421X_SENSE_B,
+	},
+	[CS421X_SENSE_B] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cs421x_fixup_sense_b,
+	},
+	[CS421X_STUMPY] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = stumpy_pincfgs,
+	},
+};
+
+static const struct hda_verb cs421x_coef_init_verbs[] = {
+	{0x0B, AC_VERB_SET_PROC_STATE, 1},
+	{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
+	/*
+	 *  Disable Coefficient Index Auto-Increment(DAI)=1,
+	 *  PDREF=0
+	 */
+	{0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
+	/* ADC SZCMode = Digital Soft Ramp */
+	{0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
+	{0x0B, AC_VERB_SET_PROC_COEF,
+	 (0x0002 /* DAC SZCMode = Digital Soft Ramp */
+	  | 0x0004 /* Mute DAC on FIFO error */
+	  | 0x0008 /* Enable DAC High Pass Filter */
+	  )},
+	{} /* terminator */
+};
+
+/* Errata: CS4210 rev A1 Silicon
+ *
+ * http://www.cirrus.com/en/pubs/errata/
+ *
+ * Description:
+ * 1. Performance degredation is present in the ADC.
+ * 2. Speaker output is not completely muted upon HP detect.
+ * 3. Noise is present when clipping occurs on the amplified
+ *    speaker outputs.
+ *
+ * Workaround:
+ * The following verb sequence written to the registers during
+ * initialization will correct the issues listed above.
+ */
+
+static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
+	{0x0B, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
+	{0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
+	{0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
+	{0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
+	{0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
+
+	{0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
+	{0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
+
+	{} /* terminator */
+};
+
+/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
+static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
+
+static int cs421x_boost_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.min = 0;
+	uinfo->value.integer.max = 3;
+	return 0;
+}
+
+static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] =
+		cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
+	return 0;
+}
+
+static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	unsigned int vol = ucontrol->value.integer.value[0];
+	unsigned int coef =
+		cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
+	unsigned int original_coef = coef;
+
+	coef &= ~0x0003;
+	coef |= (vol & 0x0003);
+	if (original_coef != coef) {
+		cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
+
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+	.name = "Speaker Boost Playback Volume",
+	.info = cs421x_boost_vol_info,
+	.get = cs421x_boost_vol_get,
+	.put = cs421x_boost_vol_put,
+	.tlv = { .p = cs421x_speaker_boost_db_scale },
+};
+
+static void cs4210_pinmux_init(struct hda_codec *codec)
+{
+	struct cs_spec *spec = codec->spec;
+	unsigned int def_conf, coef;
+
+	/* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
+	coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+
+	if (spec->gpio_mask)
+		coef |= 0x0008; /* B1,B2 are GPIOs */
+	else
+		coef &= ~0x0008;
+
+	if (spec->sense_b)
+		coef |= 0x0010; /* B2 is SENSE_B, not inverted  */
+	else
+		coef &= ~0x0010;
+
+	cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+	if ((spec->gpio_mask || spec->sense_b) &&
+	    is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
+
+		/*
+		 *  GPIO or SENSE_B forced - disconnect the DMIC pin.
+		 */
+		def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
+		def_conf &= ~AC_DEFCFG_PORT_CONN;
+		def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
+		snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
+	}
+}
+
+static void cs4210_spdif_automute(struct hda_codec *codec,
+				  struct hda_jack_callback *tbl)
+{
+	struct cs_spec *spec = codec->spec;
+	bool spdif_present = false;
+	hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
+
+	/* detect on spdif is specific to CS4210 */
+	if (!spec->spdif_detect ||
+	    spec->vendor_nid != CS4210_VENDOR_NID)
+		return;
+
+	spdif_present = snd_hda_jack_detect(codec, spdif_pin);
+	if (spdif_present == spec->spdif_present)
+		return;
+
+	spec->spdif_present = spdif_present;
+	/* SPDIF TX on/off */
+	snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
+
+	cs_automute(codec);
+}
+
+static void parse_cs421x_digital(struct hda_codec *codec)
+{
+	struct cs_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+	int i;
+
+	for (i = 0; i < cfg->dig_outs; i++) {
+		hda_nid_t nid = cfg->dig_out_pins[i];
+
+		if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+			spec->spdif_detect = 1;
+			snd_hda_jack_detect_enable_callback(codec, nid,
+							    cs4210_spdif_automute);
+		}
+	}
+}
+
+static int cs421x_init(struct hda_codec *codec)
+{
+	struct cs_spec *spec = codec->spec;
+
+	if (spec->vendor_nid == CS4210_VENDOR_NID) {
+		snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
+		snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
+		cs4210_pinmux_init(codec);
+	}
+
+	snd_hda_gen_init(codec);
+
+	if (spec->gpio_mask) {
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+				    spec->gpio_mask);
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+				    spec->gpio_dir);
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_data);
+	}
+
+	cs4210_spdif_automute(codec, NULL);
+
+	return 0;
+}
+
+static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
+{
+	unsigned int caps;
+
+	/* set the upper-limit for mixer amp to 0dB */
+	caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+	caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
+	caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
+		<< AC_AMPCAP_NUM_STEPS_SHIFT;
+	snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
+}
+
+static int cs421x_parse_auto_config(struct hda_codec *codec)
+{
+	struct cs_spec *spec = codec->spec;
+	hda_nid_t dac = CS4210_DAC_NID;
+	int err;
+
+	fix_volume_caps(codec, dac);
+
+	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+	if (err < 0)
+		return err;
+
+	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+	if (err < 0)
+		return err;
+
+	parse_cs421x_digital(codec);
+
+	if (spec->gen.autocfg.speaker_outs &&
+	    spec->vendor_nid == CS4210_VENDOR_NID) {
+		if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+					  &cs421x_speaker_boost_ctl))
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/*
+ *	Manage PDREF, when transitioning to D3hot
+ *	(DAC,ADC) -> D3, PDREF=1, AFG->D3
+ */
+static int cs421x_suspend(struct hda_codec *codec)
+{
+	struct cs_spec *spec = codec->spec;
+	unsigned int coef;
+
+	snd_hda_shutup_pins(codec);
+
+	snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
+			    AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
+	snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
+			    AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
+
+	if (spec->vendor_nid == CS4210_VENDOR_NID) {
+		coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+		coef |= 0x0004; /* PDREF */
+		cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+	}
+
+	return 0;
+}
+
+static int cs421x_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+	struct cs_spec *spec;
+	int err;
+
+	spec = cs_alloc_spec(codec, id->driver_data);
+	if (!spec)
+		return -ENOMEM;
+
+	spec->gen.automute_hook = cs_automute;
+
+	if (spec->vendor_nid == CS4210_VENDOR_NID) {
+		snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
+				   cs421x_fixups);
+		snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+		/*
+		 *  Update the GPIO/DMIC/SENSE_B pinmux before the configuration
+		 *   is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
+		 *   is disabled.
+		 */
+		cs4210_pinmux_init(codec);
+	}
+
+	err = cs421x_parse_auto_config(codec);
+	if (err < 0)
+		goto error;
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+	return 0;
+
+ error:
+	snd_hda_gen_remove(codec);
+	return err;
+}
+
+static const struct hda_codec_ops cs421x_codec_ops = {
+	.probe = cs421x_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = cs421x_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = cs421x_suspend,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
+ */
+static const struct hda_device_id snd_hda_id_cs421x[] = {
+	HDA_CODEC_ID_MODEL(0x10134210, "CS4210", CS4210_VENDOR_NID),
+	HDA_CODEC_ID_MODEL(0x10134213, "CS4213", CS4213_VENDOR_NID),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs421x);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cirrus Logic CS421x HD-audio codec");
+
+static struct hda_codec_driver cs421x_driver = {
+	.id = snd_hda_id_cs421x,
+	.ops = &cs421x_codec_ops,
+};
+
+module_hda_codec_driver(cs421x_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 16/27] ALSA: hda/cs8409: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (14 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 15/27] ALSA: hda/cirrus: Split to cs420x and cs421x drivers Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-10 10:25   ` Richard Fitzgerald
  2025-07-09 16:04 ` [PATCH 17/27] ALSA: hda/conexant: " Takashi Iwai
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the CS8409 codec driver to use the new hda_codec_ops probe.
The Dolphin support needs an override of unsol_event callback, and
redirect via spec->unsol_event function pointer for now.

Other than that, no functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/cirrus/cs8409-tables.c |  2 +-
 sound/hda/codecs/cirrus/cs8409.c        | 55 +++++++++++++------------
 sound/hda/codecs/cirrus/cs8409.h        |  4 +-
 3 files changed, 33 insertions(+), 28 deletions(-)

diff --git a/sound/hda/codecs/cirrus/cs8409-tables.c b/sound/hda/codecs/cirrus/cs8409-tables.c
index 5fe49f13c0da..8c703b714a71 100644
--- a/sound/hda/codecs/cirrus/cs8409-tables.c
+++ b/sound/hda/codecs/cirrus/cs8409-tables.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * cs8409-tables.c  --  HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * cs8409-tables.c  --  HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip
  *
  * Copyright (C) 2021 Cirrus Logic, Inc. and
  *                    Cirrus Logic International Semiconductor Ltd.
diff --git a/sound/hda/codecs/cirrus/cs8409.c b/sound/hda/codecs/cirrus/cs8409.c
index 5ec1126b2a55..e32b462cdc5e 100644
--- a/sound/hda/codecs/cirrus/cs8409.c
+++ b/sound/hda/codecs/cirrus/cs8409.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip
  *
  * Copyright (C) 2021 Cirrus Logic, Inc. and
  *                    Cirrus Logic International Semiconductor Ltd.
@@ -954,7 +954,7 @@ static void cs42l42_suspend(struct sub_codec *cs42l42)
 	snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
 }
 
-static void cs8409_free(struct hda_codec *codec)
+static void cs8409_remove(struct hda_codec *codec)
 {
 	struct cs8409_spec *spec = codec->spec;
 
@@ -962,7 +962,7 @@ static void cs8409_free(struct hda_codec *codec)
 	cancel_delayed_work_sync(&spec->i2c_clk_work);
 	cs8409_disable_i2c_clock(codec);
 
-	snd_hda_gen_free(codec);
+	snd_hda_gen_remove(codec);
 }
 
 /******************************************************************************
@@ -1007,6 +1007,16 @@ static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned in
 	}
 }
 
+static void cs8409_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	struct cs8409_spec *spec = codec->spec;
+
+	if (spec->unsol_event)
+		spec->unsol_event(codec, res);
+	else
+		cs8409_cs42l42_jack_unsol_event(codec, res);
+}
+
 /* Manage PDREF, when transition to D3hot */
 static int cs8409_cs42l42_suspend(struct hda_codec *codec)
 {
@@ -1076,15 +1086,6 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
 	cs8409_enable_ur(codec, 1);
 }
 
-static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
-	.build_controls = cs8409_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = cs8409_init,
-	.free = cs8409_free,
-	.unsol_event = cs8409_cs42l42_jack_unsol_event,
-	.suspend = cs8409_cs42l42_suspend,
-};
-
 static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
 				    unsigned int *res)
 {
@@ -1134,7 +1135,6 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
 		spec->scodecs[CS8409_CODEC0] = &cs8409_cs42l42_codec;
 		spec->num_scodecs = 1;
 		spec->scodecs[CS8409_CODEC0]->codec = codec;
-		codec->patch_ops = cs8409_cs42l42_patch_ops;
 
 		spec->gen.suppress_auto_mute = 1;
 		spec->gen.no_primary_hp = 1;
@@ -1304,15 +1304,6 @@ static void dolphin_hw_init(struct hda_codec *codec)
 	cs8409_enable_ur(codec, 1);
 }
 
-static const struct hda_codec_ops cs8409_dolphin_patch_ops = {
-	.build_controls = cs8409_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = cs8409_init,
-	.free = cs8409_free,
-	.unsol_event = dolphin_jack_unsol_event,
-	.suspend = cs8409_cs42l42_suspend,
-};
-
 static int dolphin_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
 			     unsigned int *res)
 {
@@ -1371,7 +1362,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac
 		spec->num_scodecs = 2;
 		spec->gen.suppress_vmaster = 1;
 
-		codec->patch_ops = cs8409_dolphin_patch_ops;
+		spec->unsol_event = dolphin_jack_unsol_event;
 
 		/* GPIO 1,5 out, 0,4 in */
 		spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio |
@@ -1444,7 +1435,7 @@ void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int ac
 	}
 }
 
-static int patch_cs8409(struct hda_codec *codec)
+static int cs8409_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	int err;
 
@@ -1461,7 +1452,7 @@ static int patch_cs8409(struct hda_codec *codec)
 
 	err = cs8409_parse_auto_config(codec);
 	if (err < 0) {
-		cs8409_free(codec);
+		cs8409_remove(codec);
 		return err;
 	}
 
@@ -1469,14 +1460,26 @@ static int patch_cs8409(struct hda_codec *codec)
 	return 0;
 }
 
+static const struct hda_codec_ops cs8409_codec_ops = {
+	.probe = cs8409_probe,
+	.remove = cs8409_remove,
+	.build_controls = cs8409_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = cs8409_init,
+	.unsol_event = cs8409_unsol_event,
+	.suspend = cs8409_cs42l42_suspend,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 static const struct hda_device_id snd_hda_id_cs8409[] = {
-	HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409),
+	HDA_CODEC_ID(0x10138409, "CS8409"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs8409);
 
 static struct hda_codec_driver cs8409_driver = {
 	.id = snd_hda_id_cs8409,
+	.ops = &cs8409_codec_ops,
 };
 module_hda_codec_driver(cs8409_driver);
 
diff --git a/sound/hda/codecs/cirrus/cs8409.h b/sound/hda/codecs/cirrus/cs8409.h
index 35072cd009dc..7fe56f4a73bc 100644
--- a/sound/hda/codecs/cirrus/cs8409.h
+++ b/sound/hda/codecs/cirrus/cs8409.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
- * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ * HD audio codec driver for Cirrus Logic CS8409 HDA bridge chip
  *
  * Copyright (C) 2021 Cirrus Logic, Inc. and
  *                    Cirrus Logic International Semiconductor Ltd.
@@ -345,6 +345,8 @@ struct cs8409_spec {
 	/* verb exec op override */
 	int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
 			 unsigned int *res);
+	/* unsol_event op override */
+	void (*unsol_event)(struct hda_codec *codec, unsigned int res);
 };
 
 extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 17/27] ALSA: hda/conexant: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (15 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 16/27] ALSA: hda/cs8409: Rewrite to new probe method Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 18/27] ALSA: hda/senary: " Takashi Iwai
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the Conexant codec driver to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/conexant.c | 104 ++++++++++++++++++------------------
 1 file changed, 53 insertions(+), 51 deletions(-)

diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
index b7710a81fd87..c881bf213ebe 100644
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for Conexant HDA audio codec
+ * HD audio codec driver for Conexant HDA audio codec
  *
  * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
  * 		      Takashi Iwai <tiwai@suse.de>
@@ -185,7 +185,7 @@ static void cx_fixup_headset_recog(struct hda_codec *codec)
 		snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
 }
 
-static int cx_auto_init(struct hda_codec *codec)
+static int cx_init(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
 	snd_hda_gen_init(codec);
@@ -210,10 +210,10 @@ static void cx_auto_shutdown(struct hda_codec *codec)
 	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
 }
 
-static void cx_auto_free(struct hda_codec *codec)
+static void cx_remove(struct hda_codec *codec)
 {
 	cx_auto_shutdown(codec);
-	snd_hda_gen_free(codec);
+	snd_hda_gen_remove(codec);
 }
 
 static void cx_process_headset_plugin(struct hda_codec *codec)
@@ -258,22 +258,12 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_
 		cx_process_headset_plugin(codec);
 }
 
-static int cx_auto_suspend(struct hda_codec *codec)
+static int cx_suspend(struct hda_codec *codec)
 {
 	cx_auto_shutdown(codec);
 	return 0;
 }
 
-static const struct hda_codec_ops cx_auto_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = cx_auto_init,
-	.free = cx_auto_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.suspend = cx_auto_suspend,
-	.check_power_status = snd_hda_gen_check_power_status,
-};
-
 /*
  * pin fix-up
  */
@@ -1178,7 +1168,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)
 	spec->gen.dac_min_mute = true;
 }
 
-static int patch_conexant_auto(struct hda_codec *codec)
+static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct conexant_spec *spec;
 	int err;
@@ -1190,7 +1180,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
 		return -ENOMEM;
 	snd_hda_gen_spec_init(&spec->gen);
 	codec->spec = spec;
-	codec->patch_ops = cx_auto_patch_ops;
 
 	/* init cx11880/sn6140 flag and reset headset_present_flag */
 	switch (codec->core.vendor_id) {
@@ -1276,47 +1265,59 @@ static int patch_conexant_auto(struct hda_codec *codec)
 	return 0;
 
  error:
-	cx_auto_free(codec);
+	cx_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops cx_codec_ops = {
+	.probe = cx_probe,
+	.remove = cx_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = cx_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = cx_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  */
 
 static const struct hda_device_id snd_hda_id_conexant[] = {
-	HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
-	HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
+	HDA_CODEC_ID(0x14f11f86, "CX11880"),
+	HDA_CODEC_ID(0x14f11f87, "SN6140"),
+	HDA_CODEC_ID(0x14f12008, "CX8200"),
+	HDA_CODEC_ID(0x14f120d0, "CX11970"),
+	HDA_CODEC_ID(0x14f120d1, "SN6180"),
+	HDA_CODEC_ID(0x14f15045, "CX20549 (Venice)"),
+	HDA_CODEC_ID(0x14f15047, "CX20551 (Waikiki)"),
+	HDA_CODEC_ID(0x14f15051, "CX20561 (Hermosa)"),
+	HDA_CODEC_ID(0x14f15066, "CX20582 (Pebble)"),
+	HDA_CODEC_ID(0x14f15067, "CX20583 (Pebble HSF)"),
+	HDA_CODEC_ID(0x14f15068, "CX20584"),
+	HDA_CODEC_ID(0x14f15069, "CX20585"),
+	HDA_CODEC_ID(0x14f1506c, "CX20588"),
+	HDA_CODEC_ID(0x14f1506e, "CX20590"),
+	HDA_CODEC_ID(0x14f15097, "CX20631"),
+	HDA_CODEC_ID(0x14f15098, "CX20632"),
+	HDA_CODEC_ID(0x14f150a1, "CX20641"),
+	HDA_CODEC_ID(0x14f150a2, "CX20642"),
+	HDA_CODEC_ID(0x14f150ab, "CX20651"),
+	HDA_CODEC_ID(0x14f150ac, "CX20652"),
+	HDA_CODEC_ID(0x14f150b8, "CX20664"),
+	HDA_CODEC_ID(0x14f150b9, "CX20665"),
+	HDA_CODEC_ID(0x14f150f1, "CX21722"),
+	HDA_CODEC_ID(0x14f150f2, "CX20722"),
+	HDA_CODEC_ID(0x14f150f3, "CX21724"),
+	HDA_CODEC_ID(0x14f150f4, "CX20724"),
+	HDA_CODEC_ID(0x14f1510f, "CX20751/2"),
+	HDA_CODEC_ID(0x14f15110, "CX20751/2"),
+	HDA_CODEC_ID(0x14f15111, "CX20753/4"),
+	HDA_CODEC_ID(0x14f15113, "CX20755"),
+	HDA_CODEC_ID(0x14f15114, "CX20756"),
+	HDA_CODEC_ID(0x14f15115, "CX20757"),
+	HDA_CODEC_ID(0x14f151d7, "CX20952"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
@@ -1326,6 +1327,7 @@ MODULE_DESCRIPTION("Conexant HD-audio codec");
 
 static struct hda_codec_driver conexant_driver = {
 	.id = snd_hda_id_conexant,
+	.ops = &cx_codec_ops,
 };
 
 module_hda_codec_driver(conexant_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 18/27] ALSA: hda/senary: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (16 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 17/27] ALSA: hda/conexant: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 19/27] ALSA: hda/si3054: " Takashi Iwai
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the Senary codec driver to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/senarytech.c | 46 ++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/sound/hda/codecs/senarytech.c b/sound/hda/codecs/senarytech.c
index 9a253ad19f4d..9aa1e9bcd9ec 100644
--- a/sound/hda/codecs/senarytech.c
+++ b/sound/hda/codecs/senarytech.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for Senary HDA audio codec
+ * HD audio codec driver for Senary HDA audio codec
  *
  * Initially based on conexant.c
  */
@@ -129,7 +129,7 @@ static void senary_init_gpio_led(struct hda_codec *codec)
 	}
 }
 
-static int senary_auto_init(struct hda_codec *codec)
+static int senary_init(struct hda_codec *codec)
 {
 	snd_hda_gen_init(codec);
 	senary_init_gpio_led(codec);
@@ -138,7 +138,7 @@ static int senary_auto_init(struct hda_codec *codec)
 	return 0;
 }
 
-static void senary_auto_shutdown(struct hda_codec *codec)
+static void senary_shutdown(struct hda_codec *codec)
 {
 	struct senary_spec *spec = codec->spec;
 
@@ -148,29 +148,19 @@ static void senary_auto_shutdown(struct hda_codec *codec)
 	senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
 }
 
-static void senary_auto_free(struct hda_codec *codec)
+static void senary_remove(struct hda_codec *codec)
 {
-	senary_auto_shutdown(codec);
-	snd_hda_gen_free(codec);
+	senary_shutdown(codec);
+	snd_hda_gen_remove(codec);
 }
 
-static int senary_auto_suspend(struct hda_codec *codec)
+static int senary_suspend(struct hda_codec *codec)
 {
-	senary_auto_shutdown(codec);
+	senary_shutdown(codec);
 	return 0;
 }
 
-static const struct hda_codec_ops senary_auto_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = senary_auto_init,
-	.free = senary_auto_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.suspend = senary_auto_suspend,
-	.check_power_status = snd_hda_gen_check_power_status,
-};
-
-static int patch_senary_auto(struct hda_codec *codec)
+static int senary_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct senary_spec *spec;
 	int err;
@@ -182,7 +172,6 @@ static int patch_senary_auto(struct hda_codec *codec)
 		return -ENOMEM;
 	snd_hda_gen_spec_init(&spec->gen);
 	codec->spec = spec;
-	codec->patch_ops = senary_auto_patch_ops;
 
 	senary_auto_parse_eapd(codec);
 	spec->gen.own_eapd_ctl = 1;
@@ -221,15 +210,27 @@ static int patch_senary_auto(struct hda_codec *codec)
 	return 0;
 
  error:
-	senary_auto_free(codec);
+	senary_remove(codec);
 	return err;
 }
 
+static const struct hda_codec_ops senary_codec_ops = {
+	.probe = senary_probe,
+	.remove = senary_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = senary_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = senary_suspend,
+	.check_power_status = snd_hda_gen_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
 /*
  */
 
 static const struct hda_device_id snd_hda_id_senary[] = {
-	HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto),
+	HDA_CODEC_ID(0x1fa86186, "SN6186"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary);
@@ -239,6 +240,7 @@ MODULE_DESCRIPTION("Senarytech HD-audio codec");
 
 static struct hda_codec_driver senary_driver = {
 	.id = snd_hda_id_senary,
+	.ops = &senary_codec_ops,
 };
 
 module_hda_codec_driver(senary_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 19/27] ALSA: hda/si3054: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (17 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 18/27] ALSA: hda/senary: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 20/27] ALSA: hda/via: " Takashi Iwai
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the SI3054 codec driver to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/si3054.c | 53 +++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 27 deletions(-)

diff --git a/sound/hda/codecs/si3054.c b/sound/hda/codecs/si3054.c
index 763eae80a148..87cf9da9f3bf 100644
--- a/sound/hda/codecs/si3054.c
+++ b/sound/hda/codecs/si3054.c
@@ -2,7 +2,7 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for Silicon Labs 3054/5 modem codec
+ * HD audio codec driver for Silicon Labs 3054/5 modem codec
  *
  * Copyright (c) 2005 Sasha Khapyorsky <sashak@alsa-project.org>
  *                    Takashi Iwai <tiwai@suse.de>
@@ -246,50 +246,48 @@ static int si3054_init(struct hda_codec *codec)
 	return 0;
 }
 
-static void si3054_free(struct hda_codec *codec)
+static void si3054_remove(struct hda_codec *codec)
 {
 	kfree(codec->spec);
 }
 
-
 /*
  */
 
-static const struct hda_codec_ops si3054_patch_ops = {
-	.build_controls = si3054_build_controls,
-	.build_pcms = si3054_build_pcms,
-	.init = si3054_init,
-	.free = si3054_free,
-};
-
-static int patch_si3054(struct hda_codec *codec)
+static int si3054_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
-	struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-	if (spec == NULL)
+	codec->spec = kzalloc(sizeof(struct si3054_spec), GFP_KERNEL);
+	if (!codec->spec)
 		return -ENOMEM;
-	codec->spec = spec;
-	codec->patch_ops = si3054_patch_ops;
 	return 0;
 }
 
+static const struct hda_codec_ops si3054_codec_ops = {
+	.probe = si3054_probe,
+	.remove = si3054_remove,
+	.build_controls = si3054_build_controls,
+	.build_pcms = si3054_build_pcms,
+	.init = si3054_init,
+};
+
 /*
- * patch entries
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_si3054[] = {
-	HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054),
-	HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054),
+	HDA_CODEC_ID(0x163c3055, "Si3054"),
+	HDA_CODEC_ID(0x163c3155, "Si3054"),
+	HDA_CODEC_ID(0x11c13026, "Si3054"),
+	HDA_CODEC_ID(0x11c13055, "Si3054"),
+	HDA_CODEC_ID(0x11c13155, "Si3054"),
+	HDA_CODEC_ID(0x10573055, "Si3054"),
+	HDA_CODEC_ID(0x10573057, "Si3054"),
+	HDA_CODEC_ID(0x10573155, "Si3054"),
 	/* VIA HDA on Clevo m540 */
-	HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054),
+	HDA_CODEC_ID(0x11063288, "Si3054"),
 	/* Asus A8J Modem (SM56) */
-	HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054),
+	HDA_CODEC_ID(0x15433155, "Si3054"),
 	/* LG LW20 modem */
-	HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054),
+	HDA_CODEC_ID(0x18540018, "Si3054"),
 	{}
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054);
@@ -299,6 +297,7 @@ MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
 
 static struct hda_codec_driver si3054_driver = {
 	.id = snd_hda_id_si3054,
+	.ops = &si3054_codec_ops,
 };
 
 module_hda_codec_driver(si3054_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 20/27] ALSA: hda/via: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (18 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 19/27] ALSA: hda/si3054: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 21/27] ALSA: hda/sigmatel: " Takashi Iwai
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the VIA codec driver to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/via.c | 445 +++++++++++++++++------------------------
 1 file changed, 186 insertions(+), 259 deletions(-)

diff --git a/sound/hda/codecs/via.c b/sound/hda/codecs/via.c
index e3ce563f866b..6becea9bb810 100644
--- a/sound/hda/codecs/via.c
+++ b/sound/hda/codecs/via.c
@@ -2,7 +2,7 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
+ * HD audio codec driver for VIA VT17xx/VT18xx/VT20xx codec
  *
  *  (C) 2006-2009 VIA Technology, Inc.
  *  (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
@@ -52,8 +52,10 @@
 enum VIA_HDA_CODEC {
 	UNKNOWN = -1,
 	VT1708,
+	VT1709,
 	VT1709_10CH,
 	VT1709_6CH,
+	VT1708B,
 	VT1708B_8CH,
 	VT1708B_4CH,
 	VT1708S,
@@ -66,6 +68,7 @@ enum VIA_HDA_CODEC {
 	VT1802,
 	VT1705CF,
 	VT1808,
+	VT3476,
 	CODEC_TYPES,
 };
 
@@ -95,8 +98,6 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
 				  struct snd_pcm_substream *substream,
 				  int action);
 
-static const struct hda_codec_ops via_patch_ops; /* defined below */
-
 static struct via_spec *via_new_spec(struct hda_codec *codec)
 {
 	struct via_spec *spec;
@@ -118,7 +119,6 @@ static struct via_spec *via_new_spec(struct hda_codec *codec)
 	spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
 	codec->power_save_node = 1;
 	spec->gen.power_down_unused = 1;
-	codec->patch_ops = via_patch_ops;
 	return spec;
 }
 
@@ -373,10 +373,10 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
 	vt1708_update_hp_work(codec);
 }
 
-static void via_free(struct hda_codec *codec)
+static void via_remove(struct hda_codec *codec)
 {
 	vt1708_stop_hp_work(codec);
-	snd_hda_gen_free(codec);
+	snd_hda_gen_remove(codec);
 }
 
 static int via_suspend(struct hda_codec *codec)
@@ -395,7 +395,7 @@ static int via_resume(struct hda_codec *codec)
 {
 	/* some delay here to make jack detection working (bko#98921) */
 	msleep(10);
-	codec->patch_ops.init(codec);
+	snd_hda_codec_init(codec);
 	snd_hda_regmap_sync(codec);
 	return 0;
 }
@@ -411,20 +411,6 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 /*
  */
 
-static int via_init(struct hda_codec *codec);
-
-static const struct hda_codec_ops via_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = via_init,
-	.free = via_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.suspend = via_suspend,
-	.resume = via_resume,
-	.check_power_status = via_check_power_status,
-};
-
-
 static const struct hda_verb vt1708_init_verbs[] = {
 	/* power down jack detect function */
 	{0x1, 0xf81, 0x1},
@@ -541,19 +527,21 @@ static int via_init(struct hda_codec *codec)
 	return 0;
 }
 
-static int vt1708_build_controls(struct hda_codec *codec)
+static int via_build_controls(struct hda_codec *codec)
 {
 	/* In order not to create "Phantom Jack" controls,
 	   temporary enable jackpoll */
 	int err;
 	int old_interval = codec->jackpoll_interval;
-	codec->jackpoll_interval = msecs_to_jiffies(100);
+	if (old_interval)
+		codec->jackpoll_interval = msecs_to_jiffies(100);
 	err = snd_hda_gen_build_controls(codec);
-	codec->jackpoll_interval = old_interval;
+	if (old_interval)
+		codec->jackpoll_interval = old_interval;
 	return err;
 }
 
-static int vt1708_build_pcms(struct hda_codec *codec)
+static int via_build_pcms(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
 	int i, err;
@@ -580,19 +568,11 @@ static int vt1708_build_pcms(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_vt1708(struct hda_codec *codec)
+static int probe_vt1708(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
-	/* override some patch_ops */
-	codec->patch_ops.build_controls = vt1708_build_controls;
-	codec->patch_ops.build_pcms = vt1708_build_pcms;
 	spec->gen.mixer_nid = 0x17;
 
 	/* set jackpoll_interval while parsing the codec */
@@ -611,81 +591,47 @@ static int patch_vt1708(struct hda_codec *codec)
 
 	err = snd_hda_add_verbs(codec, vt1708_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
 	err = via_parse_auto_config(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* add jack detect on/off control */
-	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {
-		err = -ENOMEM;
-		goto error;
-	}
+	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl))
+		return -ENOMEM;
 
 	/* clear jackpoll_interval again; it's set dynamically */
 	codec->jackpoll_interval = 0;
 
 	return 0;
-
- error:
-	via_free(codec);
-	return err;
 }
 
-static int patch_vt1709(struct hda_codec *codec)
+static int probe_vt1709(struct hda_codec *codec)
 {
-	struct via_spec *spec;
-	int err;
-
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
+	struct via_spec *spec = codec->spec;
 
 	spec->gen.mixer_nid = 0x18;
 
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
-static int patch_vt1708S(struct hda_codec *codec);
-static int patch_vt1708B(struct hda_codec *codec)
+static int probe_vt1708S(struct hda_codec *codec);
+static int probe_vt1708B(struct hda_codec *codec)
 {
-	struct via_spec *spec;
-	int err;
+	struct via_spec *spec = codec->spec;
 
 	if (get_codec_type(codec) == VT1708BCE)
-		return patch_vt1708S(codec);
-
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
+		return probe_vt1708S(codec);
 
 	spec->gen.mixer_nid = 0x16;
 
 	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
-/* Patch for VT1708S */
+/* Support for VT1708S */
 static const struct hda_verb vt1708S_init_verbs[] = {
 	/* Enable Mic Boost Volume backdoor */
 	{0x1, 0xf98, 0x1},
@@ -706,16 +652,11 @@ static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
 				  (0 << AC_AMPCAP_MUTE_SHIFT));
 }
 
-static int patch_vt1708S(struct hda_codec *codec)
+static int probe_vt1708S(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x16;
 	override_mic_boost(codec, 0x1a, 0, 3, 40);
 	override_mic_boost(codec, 0x1e, 0, 3, 40);
@@ -729,21 +670,12 @@ static int patch_vt1708S(struct hda_codec *codec)
 
 	err = snd_hda_add_verbs(codec, vt1708S_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
-	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
-/* Patch for VT1702 */
+/* Support for VT1702 */
 
 static const struct hda_verb vt1702_init_verbs[] = {
 	/* mixer enable */
@@ -753,16 +685,11 @@ static const struct hda_verb vt1702_init_verbs[] = {
 	{ }
 };
 
-static int patch_vt1702(struct hda_codec *codec)
+static int probe_vt1702(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x1a;
 
 	/* limit AA path volume to 0 dB */
@@ -774,21 +701,13 @@ static int patch_vt1702(struct hda_codec *codec)
 
 	err = snd_hda_add_verbs(codec, vt1702_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
-/* Patch for VT1718S */
+/* Support for VT1718S */
 
 static const struct hda_verb vt1718S_init_verbs[] = {
 	/* Enable MW0 adjust Gain 5 */
@@ -836,16 +755,11 @@ static int add_secret_dac_path(struct hda_codec *codec)
 }
 
 
-static int patch_vt1718S(struct hda_codec *codec)
+static int probe_vt1718S(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x21;
 	override_mic_boost(codec, 0x2b, 0, 3, 40);
 	override_mic_boost(codec, 0x29, 0, 3, 40);
@@ -853,21 +767,13 @@ static int patch_vt1718S(struct hda_codec *codec)
 
 	err = snd_hda_add_verbs(codec, vt1718S_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
-/* Patch for VT1716S */
+/* Support for VT1716S */
 
 static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
 			    struct snd_ctl_elem_info *uinfo)
@@ -933,41 +839,30 @@ static const struct hda_verb vt1716S_init_verbs[] = {
 	{ }
 };
 
-static int patch_vt1716S(struct hda_codec *codec)
+static int probe_vt1716S(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x16;
 	override_mic_boost(codec, 0x1a, 0, 3, 40);
 	override_mic_boost(codec, 0x1e, 0, 3, 40);
 
 	err = snd_hda_add_verbs(codec, vt1716S_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
 	err = via_parse_auto_config(codec);
 	if (err < 0)
-		goto error;
+		return err;
 
 	if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||
 	    !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||
-	    !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {
-		err = -ENOMEM;
-		goto error;
-	}
+	    !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer))
+		return -ENOMEM;
 
 	return 0;
-
- error:
-	via_free(codec);
-	return err;
 }
 
 /* for vt2002P */
@@ -1055,17 +950,12 @@ static void fix_vt1802_connections(struct hda_codec *codec)
 	snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
 }
 
-/* patch for vt2002P */
-static int patch_vt2002P(struct hda_codec *codec)
+/* Support for vt2002P */
+static int probe_vt2002P(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x21;
 	override_mic_boost(codec, 0x2b, 0, 3, 40);
 	override_mic_boost(codec, 0x29, 0, 3, 40);
@@ -1081,18 +971,10 @@ static int patch_vt2002P(struct hda_codec *codec)
 	else
 		err = snd_hda_add_verbs(codec, vt2002P_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
 /* for vt1812 */
@@ -1105,17 +987,11 @@ static const struct hda_verb vt1812_init_verbs[] = {
 	{ }
 };
 
-/* patch for vt1812 */
-static int patch_vt1812(struct hda_codec *codec)
+static int probe_vt1812(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x21;
 	override_mic_boost(codec, 0x2b, 0, 3, 40);
 	override_mic_boost(codec, 0x29, 0, 3, 40);
@@ -1123,21 +999,13 @@ static int patch_vt1812(struct hda_codec *codec)
 
 	err = snd_hda_add_verbs(codec, vt1812_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
-
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
+	return via_parse_auto_config(codec);
 }
 
-/* patch for vt3476 */
+/* Support for vt3476 */
 
 static const struct hda_verb vt3476_init_verbs[] = {
 	/* Enable DMic 8/16/32K */
@@ -1149,96 +1017,155 @@ static const struct hda_verb vt3476_init_verbs[] = {
 	{ }
 };
 
-static int patch_vt3476(struct hda_codec *codec)
+static int probe_vt3476(struct hda_codec *codec)
 {
-	struct via_spec *spec;
+	struct via_spec *spec = codec->spec;
 	int err;
 
-	/* create a codec specific record */
-	spec = via_new_spec(codec);
-	if (spec == NULL)
-		return -ENOMEM;
-
 	spec->gen.mixer_nid = 0x3f;
 	add_secret_dac_path(codec);
 
 	err = snd_hda_add_verbs(codec, vt3476_init_verbs);
 	if (err < 0)
-		goto error;
+		return err;
 
 	/* automatic parse from the BIOS config */
-	err = via_parse_auto_config(codec);
-	if (err < 0)
-		goto error;
+	return via_parse_auto_config(codec);
 
-	return 0;
-
- error:
-	via_free(codec);
-	return err;
 }
 
 /*
- * patch entries
+ * common driver probe
+ */
+static int via_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = via_new_spec(codec);
+	if (!spec)
+		return -ENOMEM;
+
+	switch (id->driver_data) {
+	case VT1708:
+		err = probe_vt1708(codec);
+		break;
+	case VT1709:
+		err = probe_vt1709(codec);
+		break;
+	case VT1708B:
+		err = probe_vt1708B(codec);
+		break;
+	case VT1708S:
+		err = probe_vt1708S(codec);
+		break;
+	case VT1702:
+		err = probe_vt1702(codec);
+		break;
+	case VT1718S:
+		err = probe_vt1718S(codec);
+		break;
+	case VT1716S:
+		err = probe_vt1716S(codec);
+		break;
+	case VT2002P:
+		err = probe_vt2002P(codec);
+		break;
+	case VT1812:
+		err = probe_vt1812(codec);
+		break;
+	case VT3476:
+		err = probe_vt3476(codec);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	if (err < 0) {
+		via_remove(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct hda_codec_ops via_codec_ops = {
+	.probe = via_probe,
+	.remove = via_remove,
+	.build_controls = via_build_controls,
+	.build_pcms = via_build_pcms,
+	.init = via_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = via_suspend,
+	.resume = via_resume,
+	.check_power_status = via_check_power_status,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
+
+/*
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_via[] = {
-	HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708),
-	HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708),
-	HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708),
-	HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708),
-	HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709),
-	HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B),
-	HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702),
-	HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S),
-	HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S),
-	HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S),
-	HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S),
-	HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S),
-	HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S),
-	HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P),
-	HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P),
-	HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812),
-	HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S),
-	HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P),
-	HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P),
-	HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476),
-	HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476),
-	HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476),
+	HDA_CODEC_ID_MODEL(0x11061708, "VT1708", VT1708),
+	HDA_CODEC_ID_MODEL(0x11061709, "VT1708", VT1708),
+	HDA_CODEC_ID_MODEL(0x1106170a, "VT1708", VT1708),
+	HDA_CODEC_ID_MODEL(0x1106170b, "VT1708", VT1708),
+	HDA_CODEC_ID_MODEL(0x1106e710, "VT1709 10-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e711, "VT1709 10-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e712, "VT1709 10-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e713, "VT1709 10-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e714, "VT1709 6-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e715, "VT1709 6-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e716, "VT1709 6-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e717, "VT1709 6-Ch", VT1709),
+	HDA_CODEC_ID_MODEL(0x1106e720, "VT1708B 8-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e721, "VT1708B 8-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e722, "VT1708B 8-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e723, "VT1708B 8-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e724, "VT1708B 4-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e725, "VT1708B 4-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e726, "VT1708B 4-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x1106e727, "VT1708B 4-Ch", VT1708B),
+	HDA_CODEC_ID_MODEL(0x11060397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11061397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11062397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11063397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11064397, "VT1705", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11065397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11066397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11067397, "VT1708S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11060398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11061398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11062398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11063398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11064398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11065398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11066398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11067398, "VT1702", VT1702),
+	HDA_CODEC_ID_MODEL(0x11060428, "VT1718S", VT1718S),
+	HDA_CODEC_ID_MODEL(0x11064428, "VT1718S", VT1718S),
+	HDA_CODEC_ID_MODEL(0x11060441, "VT2020", VT1718S),
+	HDA_CODEC_ID_MODEL(0x11064441, "VT1828S", VT1718S),
+	HDA_CODEC_ID_MODEL(0x11060433, "VT1716S", VT1716S),
+	HDA_CODEC_ID_MODEL(0x1106a721, "VT1716S", VT1716S),
+	HDA_CODEC_ID_MODEL(0x11060438, "VT2002P", VT2002P),
+	HDA_CODEC_ID_MODEL(0x11064438, "VT2002P", VT2002P),
+	HDA_CODEC_ID_MODEL(0x11060448, "VT1812", VT1812),
+	HDA_CODEC_ID_MODEL(0x11060440, "VT1818S", VT1708S),
+	HDA_CODEC_ID_MODEL(0x11060446, "VT1802", VT2002P),
+	HDA_CODEC_ID_MODEL(0x11068446, "VT1802", VT2002P),
+	HDA_CODEC_ID_MODEL(0x11064760, "VT1705CF", VT3476),
+	HDA_CODEC_ID_MODEL(0x11064761, "VT1708SCE", VT3476),
+	HDA_CODEC_ID_MODEL(0x11064762, "VT1808", VT3476),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via);
 
 static struct hda_codec_driver via_driver = {
 	.id = snd_hda_id_via,
+	.ops = &via_codec_ops,
 };
 
 MODULE_LICENSE("GPL");
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 21/27] ALSA: hda/sigmatel: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (19 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 20/27] ALSA: hda/via: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 22/27] ALSA: hda/ca0132: " Takashi Iwai
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the Sigmatel/IDT codec driver to use the new hda_codec_ops
probe.  No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/sigmatel.c | 398 ++++++++++++++++++------------------
 1 file changed, 203 insertions(+), 195 deletions(-)

diff --git a/sound/hda/codecs/sigmatel.c b/sound/hda/codecs/sigmatel.c
index 56274ff49b0b..ecbee408d771 100644
--- a/sound/hda/codecs/sigmatel.c
+++ b/sound/hda/codecs/sigmatel.c
@@ -2,7 +2,7 @@
 /*
  * Universal Interface for Intel High Definition Audio Codec
  *
- * HD audio interface patch for SigmaTel STAC92xx
+ * HD audio codec driver for SigmaTel STAC92xx
  *
  * Copyright (c) 2005 Embedded Alley Solutions, Inc.
  * Matt Porter <mporter@embeddedalley.com>
@@ -4391,8 +4391,6 @@ static int stac_init(struct hda_codec *codec)
 	return 0;
 }
 
-#define stac_free	snd_hda_gen_free
-
 #ifdef CONFIG_SND_PROC_FS
 static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
 			       struct hda_codec *codec, hda_nid_t nid)
@@ -4454,15 +4452,6 @@ static int stac_suspend(struct hda_codec *codec)
 	return 0;
 }
 
-static const struct hda_codec_ops stac_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = stac_init,
-	.free = stac_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.suspend = stac_suspend,
-};
-
 static int alloc_stac_spec(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
@@ -4474,19 +4463,14 @@ static int alloc_stac_spec(struct hda_codec *codec)
 	codec->spec = spec;
 	codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
 	spec->gen.dac_min_mute = true;
-	codec->patch_ops = stac_patch_ops;
 	return 0;
 }
 
-static int patch_stac9200(struct hda_codec *codec)
+static int probe_stac9200(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	spec->linear_tone_beep = 1;
 	spec->gen.own_eapd_ctl = 1;
@@ -4500,25 +4484,19 @@ static int patch_stac9200(struct hda_codec *codec)
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
 }
 
-static int patch_stac925x(struct hda_codec *codec)
+static int probe_stac925x(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	spec->linear_tone_beep = 1;
 	spec->gen.own_eapd_ctl = 1;
@@ -4530,26 +4508,20 @@ static int patch_stac925x(struct hda_codec *codec)
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
 }
 
-static int patch_stac92hd73xx(struct hda_codec *codec)
+static int probe_stac92hd73xx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 	int num_dacs;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	/* enable power_save_node only for new 92HD89xx chips, as it causes
 	 * click noises on old 92HD73xx chips.
@@ -4604,10 +4576,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
 		snd_hda_add_verbs(codec, stac92hd73xx_core_init);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	/* Don't GPIO-mute speakers if there are no internal speakers, because
 	 * the GPIO might be necessary for Headphone
@@ -4646,15 +4616,11 @@ static void stac_setup_gpio(struct hda_codec *codec)
 	}
 }
 
-static int patch_stac92hd83xxx(struct hda_codec *codec)
+static int probe_stac92hd83xxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	/* longer delay needed for D3 */
 	codec->core.power_caps &= ~AC_PWRST_EPSS;
 
@@ -4679,10 +4645,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
 	stac_setup_gpio(codec);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	codec->proc_widget_hook = stac92hd_proc_hook;
 
@@ -4695,15 +4659,11 @@ static const hda_nid_t stac92hd95_pwr_nids[] = {
 	0x0a, 0x0b, 0x0c, 0x0d
 };
 
-static int patch_stac92hd95(struct hda_codec *codec)
+static int probe_stac92hd95(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	/* longer delay needed for D3 */
 	codec->core.power_caps &= ~AC_PWRST_EPSS;
 
@@ -4725,10 +4685,8 @@ static int patch_stac92hd95(struct hda_codec *codec)
 	stac_setup_gpio(codec);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	codec->proc_widget_hook = stac92hd_proc_hook;
 
@@ -4737,16 +4695,12 @@ static int patch_stac92hd95(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_stac92hd71bxx(struct hda_codec *codec)
+static int probe_stac92hd71bxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	const hda_nid_t *unmute_nids = stac92hd71bxx_unmute_nids;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	/* disabled power_save_node since it causes noises on a Dell machine */
 	/* codec->power_save_node = 1; */
@@ -4809,10 +4763,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 	stac_setup_gpio(codec);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	codec->proc_widget_hook = stac92hd7x_proc_hook;
 
@@ -4821,15 +4773,11 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_stac922x(struct hda_codec *codec)
+static int probe_stac922x(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	spec->linear_tone_beep = 1;
 	spec->gen.own_eapd_ctl = 1;
@@ -4848,10 +4796,8 @@ static int patch_stac922x(struct hda_codec *codec)
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
@@ -4863,15 +4809,11 @@ static const char * const stac927x_spdif_labels[] = {
 	"Analog Mux 2", "Analog Mux 3", NULL
 };
 
-static int patch_stac927x(struct hda_codec *codec)
+static int probe_stac927x(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	spec->linear_tone_beep = 1;
 	spec->gen.own_eapd_ctl = 1;
@@ -4897,10 +4839,8 @@ static int patch_stac927x(struct hda_codec *codec)
 		snd_hda_add_verbs(codec, stac927x_core_init);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	codec->proc_widget_hook = stac927x_proc_hook;
 
@@ -4921,15 +4861,11 @@ static int patch_stac927x(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_stac9205(struct hda_codec *codec)
+static int probe_stac9205(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	spec->linear_tone_beep = 1;
 	spec->gen.own_eapd_ctl = 1;
@@ -4955,10 +4891,8 @@ static int patch_stac9205(struct hda_codec *codec)
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
+	if (err < 0)
 		return err;
-	}
 
 	codec->proc_widget_hook = stac9205_proc_hook;
 
@@ -5008,15 +4942,11 @@ static const struct hda_quirk stac9872_fixup_tbl[] = {
 	{} /* terminator */
 };
 
-static int patch_stac9872(struct hda_codec *codec)
+static int probe_stac9872(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
 	int err;
 
-	err = alloc_stac_spec(codec);
-	if (err < 0)
-		return err;
-
 	spec = codec->spec;
 	spec->linear_tone_beep = 1;
 	spec->gen.own_eapd_ctl = 1;
@@ -5028,125 +4958,202 @@ static int patch_stac9872(struct hda_codec *codec)
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = stac_parse_auto_config(codec);
-	if (err < 0) {
-		stac_free(codec);
-		return -EINVAL;
-	}
+	if (err < 0)
+		return err;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
 	return 0;
 }
 
+/*
+ * common driver probe
+ */
+
+enum {
+	MODEL_STAC9200,
+	MODEL_STAC9205,
+	MODEL_STAC922X,
+	MODEL_STAC925X,
+	MODEL_STAC927X,
+	MODEL_STAC9872,
+	MODEL_STAC92HD71BXX,
+	MODEL_STAC92HD73XX,
+	MODEL_STAC92HD83XXX,
+	MODEL_STAC92HD95,
+};
+
+static int stac_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+	int err;
+
+	err = alloc_stac_spec(codec);
+	if (err < 0)
+		return err;
+
+	switch (id->driver_data) {
+	case MODEL_STAC9200:
+		err = probe_stac9200(codec);
+		break;
+	case MODEL_STAC9205:
+		err = probe_stac9205(codec);
+		break;
+	case MODEL_STAC922X:
+		err = probe_stac922x(codec);
+		break;
+	case MODEL_STAC925X:
+		err = probe_stac925x(codec);
+		break;
+	case MODEL_STAC927X:
+		err = probe_stac927x(codec);
+		break;
+	case MODEL_STAC9872:
+		err = probe_stac9872(codec);
+		break;
+	case MODEL_STAC92HD71BXX:
+		err = probe_stac92hd71bxx(codec);
+		break;
+	case MODEL_STAC92HD73XX:
+		err = probe_stac92hd73xx(codec);
+		break;
+	case MODEL_STAC92HD83XXX:
+		err = probe_stac92hd83xxx(codec);
+		break;
+	case MODEL_STAC92HD95:
+		err = probe_stac92hd95(codec);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	if (err < 0) {
+		snd_hda_gen_remove(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct hda_codec_ops stac_codec_ops = {
+	.probe = stac_probe,
+	.remove = snd_hda_gen_remove,
+	.build_controls = snd_hda_gen_build_controls,
+	.build_pcms = snd_hda_gen_build_pcms,
+	.init = stac_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = stac_suspend,
+	.stream_pm = snd_hda_gen_stream_pm,
+};
 
 /*
- * patch entries
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_sigmatel[] = {
-	HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200),
-	HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x),
-	HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x),
-	HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x),
-	HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x),
-	HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x),
-	HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
-	HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847632, "STAC9202",  patch_stac925x),
-	HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x),
-	HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x),
-	HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x),
-	HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x),
-	HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x),
-	HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x),
-	HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x),
+	HDA_CODEC_ID_MODEL(0x83847690, "STAC9200", MODEL_STAC9200),
+	HDA_CODEC_ID_MODEL(0x83847882, "STAC9220 A1", MODEL_STAC922X),
+	HDA_CODEC_ID_MODEL(0x83847680, "STAC9221 A1", MODEL_STAC922X),
+	HDA_CODEC_ID_MODEL(0x83847880, "STAC9220 A2", MODEL_STAC922X),
+	HDA_CODEC_ID_MODEL(0x83847681, "STAC9220D/9223D A2", MODEL_STAC922X),
+	HDA_CODEC_ID_MODEL(0x83847682, "STAC9221 A2", MODEL_STAC922X),
+	HDA_CODEC_ID_MODEL(0x83847683, "STAC9221D A2", MODEL_STAC922X),
+	HDA_CODEC_ID_MODEL(0x83847618, "STAC9227", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847619, "STAC9227", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847638, "STAC92HD700", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847616, "STAC9228", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847617, "STAC9228", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847614, "STAC9229", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847615, "STAC9229", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847620, "STAC9274", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847621, "STAC9274D", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847622, "STAC9273X", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847623, "STAC9273D", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847624, "STAC9272X", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847625, "STAC9272D", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847626, "STAC9271X", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847627, "STAC9271D", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847628, "STAC9274X5NH", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847629, "STAC9274D5NH", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847632, "STAC9202",  MODEL_STAC925X),
+	HDA_CODEC_ID_MODEL(0x83847633, "STAC9202D", MODEL_STAC925X),
+	HDA_CODEC_ID_MODEL(0x83847634, "STAC9250", MODEL_STAC925X),
+	HDA_CODEC_ID_MODEL(0x83847635, "STAC9250D", MODEL_STAC925X),
+	HDA_CODEC_ID_MODEL(0x83847636, "STAC9251", MODEL_STAC925X),
+	HDA_CODEC_ID_MODEL(0x83847637, "STAC9250D", MODEL_STAC925X),
+	HDA_CODEC_ID_MODEL(0x83847645, "92HD206X", MODEL_STAC927X),
+	HDA_CODEC_ID_MODEL(0x83847646, "92HD206D", MODEL_STAC927X),
 	/* The following does not take into account .id=0x83847661 when subsys =
 	 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
 	 * currently not fully supported.
 	 */
-	HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872),
-	HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872),
-	HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872),
-	HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205),
-	HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205),
-	HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95),
-	HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx),
-	HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx),
-	HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx),
-	HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx),
+	HDA_CODEC_ID_MODEL(0x83847661, "CXD9872RD/K", MODEL_STAC9872),
+	HDA_CODEC_ID_MODEL(0x83847662, "STAC9872AK", MODEL_STAC9872),
+	HDA_CODEC_ID_MODEL(0x83847664, "CXD9872AKD", MODEL_STAC9872),
+	HDA_CODEC_ID_MODEL(0x83847698, "STAC9205", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a0, "STAC9205", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a1, "STAC9205D", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a2, "STAC9204", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a3, "STAC9204D", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a4, "STAC9255", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a5, "STAC9255D", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a6, "STAC9254", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x838476a7, "STAC9254D", MODEL_STAC9205),
+	HDA_CODEC_ID_MODEL(0x111d7603, "92HD75B3X5", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d7604, "92HD83C1X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76d4, "92HD83C1C5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d7605, "92HD81B1X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76d5, "92HD81B1C5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76d1, "92HD87B1/3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76d9, "92HD87B2/4", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d7666, "92HD88B3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d7667, "92HD88B1", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d7668, "92HD88B2", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d7669, "92HD88B4", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d7608, "92HD75B2X5", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d7674, "92HD73D1X5", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d7675, "92HD73C1X5", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d7676, "92HD73E1X5", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d7695, "92HD95", MODEL_STAC92HD95),
+	HDA_CODEC_ID_MODEL(0x111d76b0, "92HD71B8X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b1, "92HD71B8X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b2, "92HD71B7X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b3, "92HD71B7X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b4, "92HD71B6X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b5, "92HD71B6X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b6, "92HD71B5X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76b7, "92HD71B5X", MODEL_STAC92HD71BXX),
+	HDA_CODEC_ID_MODEL(0x111d76c0, "92HD89C3", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c1, "92HD89C2", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c2, "92HD89C1", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c3, "92HD89B3", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c4, "92HD89B2", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c5, "92HD89B1", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c6, "92HD89E3", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c7, "92HD89E2", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c8, "92HD89E1", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76c9, "92HD89D3", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76ca, "92HD89D2", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76cb, "92HD89D1", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76cc, "92HD89F3", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76cd, "92HD89F2", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76ce, "92HD89F1", MODEL_STAC92HD73XX),
+	HDA_CODEC_ID_MODEL(0x111d76df, "92HD93BXX", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76e0, "92HD91BXX", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76e3, "92HD98BXX", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76e5, "92HD99BXX", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76e7, "92HD90BXX", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76e8, "92HD66B1X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76e9, "92HD66B2X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76ea, "92HD66B3X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76eb, "92HD66C1X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76ec, "92HD66C2X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76ed, "92HD66C3X5", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76ee, "92HD66B1X3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76ef, "92HD66B2X3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76f0, "92HD66B3X3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76f1, "92HD66C1X3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76f2, "92HD66C2X3", MODEL_STAC92HD83XXX),
+	HDA_CODEC_ID_MODEL(0x111d76f3, "92HD66C3/65", MODEL_STAC92HD83XXX),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel);
@@ -5156,6 +5163,7 @@ MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
 
 static struct hda_codec_driver sigmatel_driver = {
 	.id = snd_hda_id_sigmatel,
+	.ops = &stac_codec_ops,
 };
 
 module_hda_codec_driver(sigmatel_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 22/27] ALSA: hda/ca0132: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (20 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 21/27] ALSA: hda/sigmatel: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 23/27] ALSA: hda/hdmi: " Takashi Iwai
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the CA0132 codec driver to use the new hda_codec_ops probe.
No functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/ca0132.c      | 103 +++++++++++++++++++++------------
 sound/hda/codecs/ca0132_regs.h |   2 +-
 2 files changed, 68 insertions(+), 37 deletions(-)

diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
index 35a979465c75..6ab59c336ed4 100644
--- a/sound/hda/codecs/ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * HD audio interface patch for Creative CA0132 chip
+ * HD audio codec driver for Creative CA0132 chip
  *
  * Copyright (c) 2011, Creative Technology Ltd.
  *
@@ -9118,7 +9118,7 @@ static void sbz_dsp_startup_check(struct hda_codec *codec)
 		codec_info(codec, "Reloading... Tries left: %d", reload);
 		sbz_exit_chip(codec);
 		spec->dsp_state = DSP_DOWNLOAD_INIT;
-		codec->patch_ops.init(codec);
+		snd_hda_codec_init(codec);
 		failure = 0;
 		for (i = 0; i < 4; i++) {
 			chipio_read(codec, cur_address, &dsp_data_check[i]);
@@ -9694,30 +9694,6 @@ static void dbpro_free(struct hda_codec *codec)
 	kfree(codec->spec);
 }
 
-static int ca0132_suspend(struct hda_codec *codec)
-{
-	struct ca0132_spec *spec = codec->spec;
-
-	cancel_delayed_work_sync(&spec->unsol_hp_work);
-	return 0;
-}
-
-static const struct hda_codec_ops ca0132_patch_ops = {
-	.build_controls = ca0132_build_controls,
-	.build_pcms = ca0132_build_pcms,
-	.init = ca0132_init,
-	.free = ca0132_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.suspend = ca0132_suspend,
-};
-
-static const struct hda_codec_ops dbpro_patch_ops = {
-	.build_controls = dbpro_build_controls,
-	.build_pcms = dbpro_build_pcms,
-	.init = dbpro_init,
-	.free = dbpro_free,
-};
-
 static void ca0132_config(struct hda_codec *codec)
 {
 	struct ca0132_spec *spec = codec->spec;
@@ -9982,12 +9958,23 @@ static void sbz_detect_quirk(struct hda_codec *codec)
 	}
 }
 
-static int patch_ca0132(struct hda_codec *codec)
+static void ca0132_codec_remove(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+		return dbpro_free(codec);
+	else
+		return ca0132_free(codec);
+}
+
+static int ca0132_codec_probe(struct hda_codec *codec,
+			      const struct hda_device_id *id)
 {
 	struct ca0132_spec *spec;
 	int err;
 
-	codec_dbg(codec, "patch_ca0132\n");
+	codec_dbg(codec, "%s\n", __func__);
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (!spec)
@@ -10000,11 +9987,6 @@ static int patch_ca0132(struct hda_codec *codec)
 	if (ca0132_quirk(spec) == QUIRK_SBZ)
 		sbz_detect_quirk(codec);
 
-	if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
-		codec->patch_ops = dbpro_patch_ops;
-	else
-		codec->patch_ops = ca0132_patch_ops;
-
 	codec->pcm_format_first = 1;
 	codec->no_sticky_stream = 1;
 
@@ -10100,15 +10082,63 @@ static int patch_ca0132(struct hda_codec *codec)
 	return 0;
 
  error:
-	ca0132_free(codec);
+	ca0132_codec_remove(codec);
 	return err;
 }
 
+static int ca0132_codec_build_controls(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+		return dbpro_build_controls(codec);
+	else
+		return ca0132_build_controls(codec);
+}
+
+static int ca0132_codec_build_pcms(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+		return dbpro_build_pcms(codec);
+	else
+		return ca0132_build_pcms(codec);
+}
+
+static int ca0132_codec_init(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+		return dbpro_init(codec);
+	else
+		return ca0132_init(codec);
+}
+
+static int ca0132_codec_suspend(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	cancel_delayed_work_sync(&spec->unsol_hp_work);
+	return 0;
+}
+
+static const struct hda_codec_ops ca0132_codec_ops = {
+	.probe = ca0132_codec_probe,
+	.remove = ca0132_codec_remove,
+	.build_controls = ca0132_codec_build_controls,
+	.build_pcms = ca0132_codec_build_pcms,
+	.init = ca0132_codec_init,
+	.unsol_event = snd_hda_jack_unsol_event,
+	.suspend = ca0132_codec_suspend,
+};
+
 /*
- * patch entries
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_ca0132[] = {
-	HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132),
+	HDA_CODEC_ID(0x11020011, "CA0132"),
 	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132);
@@ -10118,6 +10148,7 @@ MODULE_DESCRIPTION("Creative Sound Core3D codec");
 
 static struct hda_codec_driver ca0132_driver = {
 	.id = snd_hda_id_ca0132,
+	.ops = &ca0132_codec_ops,
 };
 
 module_hda_codec_driver(ca0132_driver);
diff --git a/sound/hda/codecs/ca0132_regs.h b/sound/hda/codecs/ca0132_regs.h
index 0ead571fb447..dc0153df3d5c 100644
--- a/sound/hda/codecs/ca0132_regs.h
+++ b/sound/hda/codecs/ca0132_regs.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
- * HD audio interface patch for Creative CA0132 chip.
+ * HD audio codec driver for Creative CA0132 chip.
  * CA0132 registers defines.
  *
  * Copyright (c) 2011, Creative Technology Ltd.
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 23/27] ALSA: hda/hdmi: Rewrite to new probe method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (21 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 22/27] ALSA: hda/ca0132: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-08-17 10:55   ` Mikhail Paulyshka
  2025-07-09 16:04 ` [PATCH 24/27] ALSA: hda: Drop old codec binding method Takashi Iwai
                   ` (4 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Convert the HDMI codec drivers to use the new hda_codec_ops probe.

The Intel and Nvidia-MCP HDMI drivers needed slightly more changes to
deal with the unified callbacks among all models.

Also another non-trivial change is Intel driver's set_power_state
callback.  An additional NULL check of codec->spec is needed there
since the set_power_state() may be called before the probe gets called
(e.g. in ASoC hda codec hda_codec_probe()).

Other than that, no functional changes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/codecs/hdmi/atihdmi.c    |  31 +++--
 sound/hda/codecs/hdmi/hdmi.c       | 130 ++++++++++----------
 sound/hda/codecs/hdmi/hdmi_local.h |  10 +-
 sound/hda/codecs/hdmi/intelhdmi.c  | 185 ++++++++++++++++++-----------
 sound/hda/codecs/hdmi/nvhdmi-mcp.c |  96 +++++++--------
 sound/hda/codecs/hdmi/nvhdmi.c     | 183 ++++++++++++++--------------
 sound/hda/codecs/hdmi/simplehdmi.c |  58 +++++----
 sound/hda/codecs/hdmi/tegrahdmi.c  |  69 ++++++-----
 8 files changed, 424 insertions(+), 338 deletions(-)

diff --git a/sound/hda/codecs/hdmi/atihdmi.c b/sound/hda/codecs/hdmi/atihdmi.c
index e23995cc1b8c..44366f75de33 100644
--- a/sound/hda/codecs/hdmi/atihdmi.c
+++ b/sound/hda/codecs/hdmi/atihdmi.c
@@ -528,19 +528,16 @@ static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
 	.master_unbind = snd_hda_hdmi_acomp_master_unbind,
 };
 
-static int patch_atihdmi(struct hda_codec *codec)
+static int atihdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct hdmi_spec *spec;
 	struct hdmi_spec_per_cvt *per_cvt;
 	int err, cvt_idx;
 
-	err = patch_generic_hdmi(codec);
-
+	err = snd_hda_hdmi_generic_probe(codec);
 	if (err)
 		return err;
 
-	codec->patch_ops.init = atihdmi_init;
-
 	spec = codec->spec;
 
 	spec->static_pcm_mapping = true;
@@ -583,15 +580,26 @@ static int patch_atihdmi(struct hda_codec *codec)
 	return 0;
 }
 
+static const struct hda_codec_ops atihdmi_codec_ops = {
+	.probe = atihdmi_probe,
+	.remove = snd_hda_hdmi_generic_remove,
+	.init = atihdmi_init,
+	.build_pcms = snd_hda_hdmi_generic_build_pcms,
+	.build_controls = snd_hda_hdmi_generic_build_controls,
+	.unsol_event = snd_hda_hdmi_generic_unsol_event,
+	.suspend = snd_hda_hdmi_generic_suspend,
+	.resume	 = snd_hda_hdmi_generic_resume,
+};
+
 /*
- * patch entries
+ * driver entries
  */
 static const struct hda_device_id snd_hda_id_atihdmi[] = {
-HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI",	patch_atihdmi),
-HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI",	patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI",	patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",	patch_atihdmi),
-{} /* terminator */
+	HDA_CODEC_ID(0x1002793c, "RS600 HDMI"),
+	HDA_CODEC_ID(0x10027919, "RS600 HDMI"),
+	HDA_CODEC_ID(0x1002791a, "RS690/780 HDMI"),
+	HDA_CODEC_ID(0x1002aa01, "R6xx HDMI"),
+	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi);
 
@@ -601,6 +609,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
 
 static struct hda_codec_driver atihdmi_driver = {
 	.id = snd_hda_id_atihdmi,
+	.ops = &atihdmi_codec_ops,
 };
 
 module_hda_codec_driver(atihdmi_driver);
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
index 85aaa454072f..b5d840d9892b 100644
--- a/sound/hda/codecs/hdmi/hdmi.c
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -2087,7 +2087,7 @@ void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_spec_free, "SND_HDA_CODEC_HDMI");
 
-void snd_hda_hdmi_generic_free(struct hda_codec *codec)
+void snd_hda_hdmi_generic_remove(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx, pcm_idx;
@@ -2113,7 +2113,7 @@ void snd_hda_hdmi_generic_free(struct hda_codec *codec)
 
 	snd_hda_hdmi_generic_spec_free(codec);
 }
-EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_free, "SND_HDA_CODEC_HDMI");
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_remove, "SND_HDA_CODEC_HDMI");
 
 int snd_hda_hdmi_generic_suspend(struct hda_codec *codec)
 {
@@ -2133,7 +2133,7 @@ int snd_hda_hdmi_generic_resume(struct hda_codec *codec)
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx;
 
-	codec->patch_ops.init(codec);
+	snd_hda_codec_init(codec);
 	snd_hda_regmap_sync(codec);
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
@@ -2144,16 +2144,6 @@ int snd_hda_hdmi_generic_resume(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_resume, "SND_HDA_CODEC_HDMI");
 
-static const struct hda_codec_ops generic_hdmi_patch_ops = {
-	.init			= snd_hda_hdmi_generic_init,
-	.free			= snd_hda_hdmi_generic_free,
-	.build_pcms		= snd_hda_hdmi_generic_build_pcms,
-	.build_controls		= snd_hda_hdmi_generic_build_controls,
-	.unsol_event		= snd_hda_hdmi_generic_unsol_event,
-	.suspend		= snd_hda_hdmi_generic_suspend,
-	.resume			= snd_hda_hdmi_generic_resume,
-};
-
 static const struct hdmi_ops generic_standard_hdmi_ops = {
 	.pin_get_eld				= hdmi_pin_get_eld,
 	.pin_setup_infoframe			= hdmi_pin_setup_infoframe,
@@ -2185,14 +2175,12 @@ int snd_hda_hdmi_generic_alloc(struct hda_codec *codec)
 	codec->spec = spec;
 	hdmi_array_init(spec, 4);
 
-	codec->patch_ops = generic_hdmi_patch_ops;
-
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_alloc, "SND_HDA_CODEC_HDMI");
 
 /* generic HDMI parser */
-int patch_generic_hdmi(struct hda_codec *codec)
+int snd_hda_hdmi_generic_probe(struct hda_codec *codec)
 {
 	int err;
 
@@ -2209,7 +2197,7 @@ int patch_generic_hdmi(struct hda_codec *codec)
 	snd_hda_hdmi_generic_init_per_pins(codec);
 	return 0;
 }
-EXPORT_SYMBOL_NS_GPL(patch_generic_hdmi, "SND_HDA_CODEC_HDMI");
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_generic_probe, "SND_HDA_CODEC_HDMI");
 
 /*
  * generic audio component binding
@@ -2346,65 +2334,83 @@ EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_init, "SND_HDA_CODEC_HDMI");
 /*
  */
 
-static int patch_gf_hdmi(struct hda_codec *codec)
+enum {
+	MODEL_GENERIC,
+	MODEL_GF,
+};
+
+static int generichdmi_probe(struct hda_codec *codec,
+			     const struct hda_device_id *id)
 {
 	int err;
 
-	err = patch_generic_hdmi(codec);
-	if (err)
+	err = snd_hda_hdmi_generic_probe(codec);
+	if (err < 0)
 		return err;
-
 	/*
 	 * Glenfly GPUs have two codecs, stream switches from one codec to
 	 * another, need to do actual clean-ups in codec_cleanup_stream
 	 */
-	codec->no_sticky_stream = 1;
+	if (id->driver_data == MODEL_GF)
+		codec->no_sticky_stream = 1;
+
 	return 0;
 }
 
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_hdmi[] = {
-HDA_CODEC_ENTRY(0x00147a47, "Loongson HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f89, "KX-5000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8a, "KX-6000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8b, "KX-6000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8c, "KX-6000G HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP",	patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI",	patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI",	patch_generic_hdmi),
-/* special ID for generic HDMI */
-HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
-{} /* terminator */
+static const struct hda_codec_ops generichdmi_codec_ops = {
+	.probe = generichdmi_probe,
+	.remove = snd_hda_hdmi_generic_remove,
+	.init = snd_hda_hdmi_generic_init,
+	.build_pcms = snd_hda_hdmi_generic_build_pcms,
+	.build_controls = snd_hda_hdmi_generic_build_controls,
+	.unsol_event = snd_hda_hdmi_generic_unsol_event,
+	.suspend = snd_hda_hdmi_generic_suspend,
+	.resume	 = snd_hda_hdmi_generic_resume,
 };
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
+
+/*
+ */
+static const struct hda_device_id snd_hda_id_generichdmi[] = {
+	HDA_CODEC_ID_MODEL(0x00147a47, "Loongson HDMI",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10951390, "SiI1390 HDMI",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10951392, "SiI1392 HDMI",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x11069f84, "VX11 HDMI/DP",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x11069f85, "VX11 HDMI/DP",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x17e80047, "Chrontel HDMI",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x1d179f86, "ZX-100S HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f87, "ZX-100S HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f88, "KX-5000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f89, "KX-5000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f8a, "KX-6000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f8b, "KX-6000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f8c, "KX-6000G HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f8d, "KX-6000G HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f8e, "KX-7000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f8f, "KX-7000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x1d179f90, "KX-7000 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x67663d82, "Arise 82 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x67663d83, "Arise 83 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x67663d84, "Arise 84 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x67663d85, "Arise 85 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x67663d86, "Arise 86 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x67663d87, "Arise 87 HDMI/DP",	MODEL_GF),
+	HDA_CODEC_ID_MODEL(0x80862801, "Bearlake HDMI",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x80862802, "Cantiga HDMI",		MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x80862803, "Eaglelake HDMI",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x80862880, "CedarTrail HDMI",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x808629fb, "Crestline HDMI",	MODEL_GENERIC),
+	/* special ID for generic HDMI */
+	HDA_CODEC_ID_MODEL(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", MODEL_GENERIC),
+	{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generichdmi);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("HDMI HD-audio codec");
+MODULE_DESCRIPTION("Generic HDMI HD-audio codec");
 
-static struct hda_codec_driver hdmi_driver = {
-	.id = snd_hda_id_hdmi,
+static struct hda_codec_driver generichdmi_driver = {
+	.id = snd_hda_id_generichdmi,
+	.ops = &generichdmi_codec_ops,
 };
 
-module_hda_codec_driver(hdmi_driver);
+module_hda_codec_driver(generichdmi_driver);
diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h
index 96351bebbc1b..0654013f1fda 100644
--- a/sound/hda/codecs/hdmi/hdmi_local.h
+++ b/sound/hda/codecs/hdmi/hdmi_local.h
@@ -237,8 +237,8 @@ union audio_infoframe {
 /* Generic HDMI codec support */
 int snd_hda_hdmi_generic_alloc(struct hda_codec *codec);
 int snd_hda_hdmi_parse_codec(struct hda_codec *codec);
-int patch_generic_hdmi(struct hda_codec *codec);
-void snd_hda_hdmi_generic_free(struct hda_codec *codec);
+int snd_hda_hdmi_generic_probe(struct hda_codec *codec);
+void snd_hda_hdmi_generic_remove(struct hda_codec *codec);
 
 int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec);
 int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec);
@@ -286,9 +286,9 @@ void snd_hda_hdmi_acomp_master_unbind(struct device *dev,
 				      struct drm_audio_component *acomp);
 
 /* Simple / legacy HDMI codec support */
-int patch_simple_hdmi(struct hda_codec *codec,
-		      hda_nid_t cvt_nid, hda_nid_t pin_nid);
-void snd_hda_hdmi_simple_free(struct hda_codec *codec);
+int snd_hda_hdmi_simple_probe(struct hda_codec *codec,
+			      hda_nid_t cvt_nid, hda_nid_t pin_nid);
+void snd_hda_hdmi_simple_remove(struct hda_codec *codec);
 
 int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec);
 int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec);
diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c
index a88ac1f80db6..23237d527430 100644
--- a/sound/hda/codecs/hdmi/intelhdmi.c
+++ b/sound/hda/codecs/hdmi/intelhdmi.c
@@ -18,6 +18,16 @@ IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
 module_param(enable_silent_stream, bool, 0644);
 MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
 
+enum {
+	MODEL_HSW,
+	MODEL_GLK,
+	MODEL_ICL,
+	MODEL_TGL,
+	MODEL_ADLP,
+	MODEL_BYT,
+	MODEL_CPT,
+};
+
 #define INTEL_GET_VENDOR_VERB	0xf81
 #define INTEL_SET_VENDOR_VERB	0x781
 #define INTEL_EN_DP12		0x02	/* enable DP 1.2 features */
@@ -67,9 +77,12 @@ static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
 static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 				unsigned int power_state)
 {
-	if (power_state == AC_PWRST_D0) {
-		intel_haswell_enable_all_pins(codec, false);
-		intel_haswell_fixup_enable_dp12(codec);
+	/* check codec->spec: it can be called before the probe gets called */
+	if (codec->spec) {
+		if (power_state == AC_PWRST_D0) {
+			intel_haswell_enable_all_pins(codec, false);
+			intel_haswell_fixup_enable_dp12(codec);
+		}
 	}
 
 	snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
@@ -456,13 +469,15 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
 	}
 }
 
-static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
+static int i915_hdmi_suspend(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	bool silent_streams = false;
 	int pin_idx, res;
 
 	res = snd_hda_hdmi_generic_suspend(codec);
+	if (spec->silent_stream_type != SILENT_STREAM_KAE)
+		return res;
 
 	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
 		struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -495,12 +510,14 @@ static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
 	return res;
 }
 
-static int i915_adlp_hdmi_resume(struct hda_codec *codec)
+static int i915_hdmi_resume(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx, res;
 
 	res = snd_hda_hdmi_generic_resume(codec);
+	if (spec->silent_stream_type != SILENT_STREAM_KAE)
+		return res;
 
 	/* KAE not programmed at suspend, nothing to do here */
 	if (!codec->no_stream_clean_at_suspend)
@@ -539,8 +556,6 @@ static int i915_adlp_hdmi_resume(struct hda_codec *codec)
 /* precondition and allocation for Intel codecs */
 static int alloc_intel_hdmi(struct hda_codec *codec)
 {
-	int err;
-
 	/* requires i915 binding */
 	if (!codec->bus->core.audio_component) {
 		codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
@@ -549,12 +564,7 @@ static int alloc_intel_hdmi(struct hda_codec *codec)
 		return -ENODEV;
 	}
 
-	err = snd_hda_hdmi_generic_alloc(codec);
-	if (err < 0)
-		return err;
-	/* no need to handle unsol events */
-	codec->patch_ops.unsol_event = NULL;
-	return 0;
+	return snd_hda_hdmi_generic_alloc(codec);
 }
 
 /* parse and post-process for Intel codecs */
@@ -580,11 +590,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
 				 bool send_silent_stream)
 {
 	struct hdmi_spec *spec;
-	int err;
 
-	err = alloc_intel_hdmi(codec);
-	if (err < 0)
-		return err;
 	spec = codec->spec;
 	codec->dp_mst = true;
 	spec->vendor_nid = vendor_nid;
@@ -598,7 +604,6 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
 
 	codec->display_power_control = 1;
 
-	codec->patch_ops.set_power_state = haswell_set_power_state;
 	codec->depop_delay = 0;
 	codec->auto_runtime_pm = 1;
 
@@ -616,13 +621,13 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
 	return parse_intel_hdmi(codec);
 }
 
-static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+static int probe_i915_hsw_hdmi(struct hda_codec *codec)
 {
 	return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
 				     enable_silent_stream);
 }
 
-static int patch_i915_glk_hdmi(struct hda_codec *codec)
+static int probe_i915_glk_hdmi(struct hda_codec *codec)
 {
 	/*
 	 * Silent stream calls audio component .get_power() from
@@ -632,7 +637,7 @@ static int patch_i915_glk_hdmi(struct hda_codec *codec)
 	return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
 }
 
-static int patch_i915_icl_hdmi(struct hda_codec *codec)
+static int probe_i915_icl_hdmi(struct hda_codec *codec)
 {
 	/*
 	 * pin to port mapping table where the value indicate the pin number and
@@ -644,7 +649,7 @@ static int patch_i915_icl_hdmi(struct hda_codec *codec)
 				     enable_silent_stream);
 }
 
-static int patch_i915_tgl_hdmi(struct hda_codec *codec)
+static int probe_i915_tgl_hdmi(struct hda_codec *codec)
 {
 	/*
 	 * pin to port mapping table where the value indicate the pin number and
@@ -656,35 +661,27 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec)
 				     enable_silent_stream);
 }
 
-static int patch_i915_adlp_hdmi(struct hda_codec *codec)
+static int probe_i915_adlp_hdmi(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
 	int res;
 
-	res = patch_i915_tgl_hdmi(codec);
+	res = probe_i915_tgl_hdmi(codec);
 	if (!res) {
 		spec = codec->spec;
 
-		if (spec->silent_stream_type) {
+		if (spec->silent_stream_type)
 			spec->silent_stream_type = SILENT_STREAM_KAE;
-
-			codec->patch_ops.resume = i915_adlp_hdmi_resume;
-			codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
-		}
 	}
 
 	return res;
 }
 
 /* Intel Baytrail and Braswell; with eld notifier */
-static int patch_i915_byt_hdmi(struct hda_codec *codec)
+static int probe_i915_byt_hdmi(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
-	int err;
 
-	err = alloc_intel_hdmi(codec);
-	if (err < 0)
-		return err;
 	spec = codec->spec;
 
 	/* For Valleyview/Cherryview, only the display codec is in the display
@@ -701,51 +698,104 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
 }
 
 /* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
-static int patch_i915_cpt_hdmi(struct hda_codec *codec)
+static int probe_i915_cpt_hdmi(struct hda_codec *codec)
+{
+	return parse_intel_hdmi(codec);
+}
+
+/*
+ * common driver probe
+ */
+static int intelhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	int err;
 
 	err = alloc_intel_hdmi(codec);
 	if (err < 0)
 		return err;
-	return parse_intel_hdmi(codec);
+
+	switch (id->driver_data) {
+	case MODEL_HSW:
+		err = probe_i915_hsw_hdmi(codec);
+		break;
+	case MODEL_GLK:
+		err = probe_i915_glk_hdmi(codec);
+		break;
+	case MODEL_ICL:
+		err = probe_i915_icl_hdmi(codec);
+		break;
+	case MODEL_TGL:
+		err = probe_i915_tgl_hdmi(codec);
+		break;
+	case MODEL_ADLP:
+		err = probe_i915_adlp_hdmi(codec);
+		break;
+	case MODEL_BYT:
+		err = probe_i915_byt_hdmi(codec);
+		break;
+	case MODEL_CPT:
+		err = probe_i915_cpt_hdmi(codec);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	if (err < 0) {
+		snd_hda_hdmi_generic_spec_free(codec);
+		return err;
+	}
+
+	return 0;
 }
 
+static const struct hda_codec_ops intelhdmi_codec_ops = {
+	.probe = intelhdmi_probe,
+	.remove = snd_hda_hdmi_generic_remove,
+	.init = snd_hda_hdmi_generic_init,
+	.build_pcms = snd_hda_hdmi_generic_build_pcms,
+	.build_controls = snd_hda_hdmi_generic_build_controls,
+	.unsol_event = snd_hda_hdmi_generic_unsol_event,
+	.suspend = i915_hdmi_suspend,
+	.resume = i915_hdmi_resume,
+	.set_power_state = haswell_set_power_state,
+};
+
 /*
  * driver entries
  */
 static const struct hda_device_id snd_hda_id_intelhdmi[] = {
-HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",	patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI",	patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",	patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",	patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI",	patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI",	patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",	patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI",	patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI",	patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",	patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI",	patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",	patch_i915_byt_hdmi),
-HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",	patch_i915_byt_hdmi),
-{} /* terminator */
+	HDA_CODEC_ID_MODEL(0x80860054, "IbexPeak HDMI",		MODEL_CPT),
+	HDA_CODEC_ID_MODEL(0x80862800, "Geminilake HDMI",	MODEL_GLK),
+	HDA_CODEC_ID_MODEL(0x80862804, "IbexPeak HDMI",		MODEL_CPT),
+	HDA_CODEC_ID_MODEL(0x80862805, "CougarPoint HDMI",	MODEL_CPT),
+	HDA_CODEC_ID_MODEL(0x80862806, "PantherPoint HDMI",	MODEL_CPT),
+	HDA_CODEC_ID_MODEL(0x80862807, "Haswell HDMI",		MODEL_HSW),
+	HDA_CODEC_ID_MODEL(0x80862808, "Broadwell HDMI",	MODEL_HSW),
+	HDA_CODEC_ID_MODEL(0x80862809, "Skylake HDMI",		MODEL_HSW),
+	HDA_CODEC_ID_MODEL(0x8086280a, "Broxton HDMI",		MODEL_HSW),
+	HDA_CODEC_ID_MODEL(0x8086280b, "Kabylake HDMI",		MODEL_HSW),
+	HDA_CODEC_ID_MODEL(0x8086280c, "Cannonlake HDMI",	MODEL_GLK),
+	HDA_CODEC_ID_MODEL(0x8086280d, "Geminilake HDMI",	MODEL_GLK),
+	HDA_CODEC_ID_MODEL(0x8086280f, "Icelake HDMI",		MODEL_ICL),
+	HDA_CODEC_ID_MODEL(0x80862812, "Tigerlake HDMI",	MODEL_TGL),
+	HDA_CODEC_ID_MODEL(0x80862814, "DG1 HDMI",		MODEL_TGL),
+	HDA_CODEC_ID_MODEL(0x80862815, "Alderlake HDMI",	MODEL_TGL),
+	HDA_CODEC_ID_MODEL(0x80862816, "Rocketlake HDMI",	MODEL_TGL),
+	HDA_CODEC_ID_MODEL(0x80862818, "Raptorlake HDMI",	MODEL_TGL),
+	HDA_CODEC_ID_MODEL(0x80862819, "DG2 HDMI",		MODEL_TGL),
+	HDA_CODEC_ID_MODEL(0x8086281a, "Jasperlake HDMI",	MODEL_ICL),
+	HDA_CODEC_ID_MODEL(0x8086281b, "Elkhartlake HDMI",	MODEL_ICL),
+	HDA_CODEC_ID_MODEL(0x8086281c, "Alderlake-P HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x8086281d, "Meteor Lake HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x8086281e, "Battlemage HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x8086281f, "Raptor Lake P HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x80862820, "Lunar Lake HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x80862822, "Panther Lake HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x80862823, "Wildcat Lake HDMI",	MODEL_ADLP),
+	HDA_CODEC_ID_MODEL(0x80862882, "Valleyview2 HDMI",	MODEL_BYT),
+	HDA_CODEC_ID_MODEL(0x80862883, "Braswell HDMI",		MODEL_BYT),
+	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_intelhdmi);
 
@@ -755,6 +805,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
 
 static struct hda_codec_driver intelhdmi_driver = {
 	.id = snd_hda_id_intelhdmi,
+	.ops = &intelhdmi_codec_ops,
 };
 
 module_hda_codec_driver(intelhdmi_driver);
diff --git a/sound/hda/codecs/hdmi/nvhdmi-mcp.c b/sound/hda/codecs/hdmi/nvhdmi-mcp.c
index 67e187a351d7..fbcea6d1850e 100644
--- a/sound/hda/codecs/hdmi/nvhdmi-mcp.c
+++ b/sound/hda/codecs/hdmi/nvhdmi-mcp.c
@@ -12,6 +12,8 @@
 #include "hda_local.h"
 #include "hdmi_local.h"
 
+enum { MODEL_2CH, MODEL_8CH };
+
 #define Nv_VERB_SET_Channel_Allocation          0xF79
 #define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
 #define Nv_VERB_SET_Audio_Protection_On         0xF98
@@ -45,15 +47,14 @@ static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
 	{} /* terminator */
 };
 
-static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
+static int nvhdmi_mcp_init(struct hda_codec *codec)
 {
-	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
-	return 0;
-}
+	struct hdmi_spec *spec = codec->spec;
 
-static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
-{
-	snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
+	if (spec->multiout.max_channels == 2)
+		snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
+	else
+		snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
 	return 0;
 }
 
@@ -233,31 +234,13 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
 	},
 };
 
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
-	struct hdmi_spec *spec;
-	int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
-				    nvhdmi_master_pin_nid_7x);
-	if (err < 0)
-		return err;
-
-	codec->patch_ops.init = nvhdmi_7x_init_2ch;
-	/* override the PCM rates, etc, as the codec doesn't give full list */
-	spec = codec->spec;
-	spec->pcm_playback.rates = SUPPORTED_RATES;
-	spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
-	spec->pcm_playback.formats = SUPPORTED_FORMATS;
-	spec->nv_dp_workaround = true;
-	return 0;
-}
-
-static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
+static int nvhdmi_mcp_build_pcms(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	int err;
 
 	err = snd_hda_hdmi_simple_build_pcms(codec);
-	if (!err) {
+	if (!err && spec->multiout.max_channels == 8) {
 		struct hda_pcm *info = get_pcm_rec(spec, 0);
 
 		info->own_chmap = true;
@@ -265,7 +248,7 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
 	return err;
 }
 
-static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
+static int nvhdmi_mcp_build_controls(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 	struct hda_pcm *info;
@@ -276,6 +259,9 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
 	if (err < 0)
 		return err;
 
+	if (spec->multiout.max_channels != 8)
+		return 0;
+
 	/* add channel maps */
 	info = get_pcm_rec(spec, 0);
 	err = snd_pcm_add_chmap_ctls(info->pcm,
@@ -316,20 +302,29 @@ static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
 	.mask = 0,
 };
 
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
+static int nvhdmi_mcp_probe(struct hda_codec *codec,
+			    const struct hda_device_id *id)
 {
 	struct hdmi_spec *spec;
 	int err;
 
-	err = patch_nvhdmi_2ch(codec);
+	err = snd_hda_hdmi_simple_probe(codec, nvhdmi_master_con_nid_7x,
+					nvhdmi_master_pin_nid_7x);
 	if (err < 0)
 		return err;
+
+	/* override the PCM rates, etc, as the codec doesn't give full list */
 	spec = codec->spec;
+	spec->pcm_playback.rates = SUPPORTED_RATES;
+	spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
+	spec->pcm_playback.formats = SUPPORTED_FORMATS;
+	spec->nv_dp_workaround = true;
+
+	if (id->driver_data == MODEL_2CH)
+		return 0;
+
 	spec->multiout.max_channels = 8;
 	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
-	codec->patch_ops.init = nvhdmi_7x_init_8ch;
-	codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
-	codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
 
 	switch (codec->preset->vendor_id) {
 	case 0x10de0002:
@@ -353,21 +348,27 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
 	return 0;
 }
 
-/*
- * patch entries
- */
+static const struct hda_codec_ops nvhdmi_mcp_codec_ops = {
+	.probe = nvhdmi_mcp_probe,
+	.remove = snd_hda_hdmi_simple_remove,
+	.build_controls = nvhdmi_mcp_build_pcms,
+	.build_pcms = nvhdmi_mcp_build_controls,
+	.init = nvhdmi_mcp_init,
+	.unsol_event = snd_hda_hdmi_simple_unsol_event,
+};
+
 static const struct hda_device_id snd_hda_id_nvhdmi_mcp[] = {
-HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",	patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",	patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",	patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",	patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",	patch_nvhdmi_2ch),
-{} /* terminator */
+	HDA_CODEC_ID_MODEL(0x10de0001, "MCP73 HDMI",	MODEL_2CH),
+	HDA_CODEC_ID_MODEL(0x10de0002, "MCP77/78 HDMI",	MODEL_8CH),
+	HDA_CODEC_ID_MODEL(0x10de0003, "MCP77/78 HDMI",	MODEL_8CH),
+	HDA_CODEC_ID_MODEL(0x10de0004, "GPU 04 HDMI",	MODEL_8CH),
+	HDA_CODEC_ID_MODEL(0x10de0005, "MCP77/78 HDMI",	MODEL_8CH),
+	HDA_CODEC_ID_MODEL(0x10de0006, "MCP77/78 HDMI",	MODEL_8CH),
+	HDA_CODEC_ID_MODEL(0x10de0007, "MCP79/7A HDMI",	MODEL_8CH),
+	HDA_CODEC_ID_MODEL(0x10de0067, "MCP67 HDMI",	MODEL_2CH),
+	HDA_CODEC_ID_MODEL(0x10de8001, "MCP73 HDMI",	MODEL_2CH),
+	HDA_CODEC_ID_MODEL(0x10de8067, "MCP67/68 HDMI",	MODEL_2CH),
+	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi_mcp);
 
@@ -377,6 +378,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
 
 static struct hda_codec_driver nvhdmi_mcp_driver = {
 	.id = snd_hda_id_nvhdmi_mcp,
+	.ops = &nvhdmi_mcp_codec_ops,
 };
 
 module_hda_codec_driver(nvhdmi_mcp_driver);
diff --git a/sound/hda/codecs/hdmi/nvhdmi.c b/sound/hda/codecs/hdmi/nvhdmi.c
index 2add5f59daf5..b513253b1101 100644
--- a/sound/hda/codecs/hdmi/nvhdmi.c
+++ b/sound/hda/codecs/hdmi/nvhdmi.c
@@ -13,6 +13,11 @@
 #include "hda_local.h"
 #include "hdmi_local.h"
 
+enum {
+	MODEL_GENERIC,
+	MODEL_LEGACY,
+};
+
 /*
  * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
  * - 0x10de0015
@@ -61,7 +66,7 @@ static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
 	.master_unbind = snd_hda_hdmi_acomp_master_unbind,
 };
 
-static int patch_nvhdmi(struct hda_codec *codec)
+static int probe_generic(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
 	int err;
@@ -95,12 +100,12 @@ static int patch_nvhdmi(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_nvhdmi_legacy(struct hda_codec *codec)
+static int probe_legacy(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec;
 	int err;
 
-	err = patch_generic_hdmi(codec);
+	err = snd_hda_hdmi_generic_probe(codec);
 	if (err)
 		return err;
 
@@ -117,93 +122,92 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec)
 	return 0;
 }
 
-/*
- * patch entries
- */
+static int nvhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
+{
+	if (id->driver_data == MODEL_LEGACY)
+		return probe_legacy(codec);
+	else
+		return probe_generic(codec);
+}
+
+static const struct hda_codec_ops nvhdmi_codec_ops = {
+	.probe = nvhdmi_probe,
+	.remove = snd_hda_hdmi_generic_remove,
+	.init = snd_hda_hdmi_generic_init,
+	.build_pcms = snd_hda_hdmi_generic_build_pcms,
+	.build_controls = snd_hda_hdmi_generic_build_controls,
+	.unsol_event = snd_hda_hdmi_generic_unsol_event,
+	.suspend = snd_hda_hdmi_generic_suspend,
+	.resume	 = snd_hda_hdmi_generic_resume,
+};
+
 static const struct hda_device_id snd_hda_id_nvhdmi[] = {
-HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP",	patch_nvhdmi_legacy),
-/* 17 is known to be absent */
-HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP",	patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP",	patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP",	patch_nvhdmi),
-{} /* terminator */
+	HDA_CODEC_ID_MODEL(0x10de0008, "GPU 08 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0009, "GPU 09 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de000a, "GPU 0a HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de000b, "GPU 0b HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de000c, "MCP89 HDMI",		MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de000d, "GPU 0d HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0010, "GPU 10 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0011, "GPU 11 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0012, "GPU 12 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0013, "GPU 13 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0014, "GPU 14 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0015, "GPU 15 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0016, "GPU 16 HDMI/DP",	MODEL_LEGACY),
+	/* 17 is known to be absent */
+	HDA_CODEC_ID_MODEL(0x10de0018, "GPU 18 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0019, "GPU 19 HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de001a, "GPU 1a HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de001b, "GPU 1b HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de001c, "GPU 1c HDMI/DP",	MODEL_LEGACY),
+	HDA_CODEC_ID_MODEL(0x10de0040, "GPU 40 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0041, "GPU 41 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0042, "GPU 42 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0043, "GPU 43 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0044, "GPU 44 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0045, "GPU 45 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0050, "GPU 50 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0051, "GPU 51 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0052, "GPU 52 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0060, "GPU 60 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0061, "GPU 61 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0062, "GPU 62 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0070, "GPU 70 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0071, "GPU 71 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0072, "GPU 72 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0073, "GPU 73 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0074, "GPU 74 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0076, "GPU 76 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de007b, "GPU 7b HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de007c, "GPU 7c HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de007d, "GPU 7d HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de007e, "GPU 7e HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0080, "GPU 80 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0081, "GPU 81 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0082, "GPU 82 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0083, "GPU 83 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0084, "GPU 84 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0090, "GPU 90 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0091, "GPU 91 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0092, "GPU 92 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0093, "GPU 93 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0094, "GPU 94 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0095, "GPU 95 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0097, "GPU 97 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0098, "GPU 98 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de0099, "GPU 99 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de009a, "GPU 9a HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de009d, "GPU 9d HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de009e, "GPU 9e HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de009f, "GPU 9f HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de00a0, "GPU a0 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de00a3, "GPU a3 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de00a4, "GPU a4 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de00a5, "GPU a5 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de00a6, "GPU a6 HDMI/DP",	MODEL_GENERIC),
+	HDA_CODEC_ID_MODEL(0x10de00a7, "GPU a7 HDMI/DP",	MODEL_GENERIC),
+	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi);
 
@@ -213,6 +217,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
 
 static struct hda_codec_driver nvhdmi_driver = {
 	.id = snd_hda_id_nvhdmi,
+	.ops = &nvhdmi_codec_ops,
 };
 
 module_hda_codec_driver(nvhdmi_driver);
diff --git a/sound/hda/codecs/hdmi/simplehdmi.c b/sound/hda/codecs/hdmi/simplehdmi.c
index 87ea997a6d3b..193c8dc882af 100644
--- a/sound/hda/codecs/hdmi/simplehdmi.c
+++ b/sound/hda/codecs/hdmi/simplehdmi.c
@@ -107,7 +107,7 @@ int snd_hda_hdmi_simple_init(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_init, "SND_HDA_CODEC_HDMI");
 
-void snd_hda_hdmi_simple_free(struct hda_codec *codec)
+void snd_hda_hdmi_simple_remove(struct hda_codec *codec)
 {
 	struct hdmi_spec *spec = codec->spec;
 
@@ -115,7 +115,7 @@ void snd_hda_hdmi_simple_free(struct hda_codec *codec)
 	snd_array_free(&spec->cvts);
 	kfree(spec);
 }
-EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_free, "SND_HDA_CODEC_HDMI");
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_remove, "SND_HDA_CODEC_HDMI");
 
 int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo,
 				 struct hda_codec *codec,
@@ -168,16 +168,8 @@ static const struct hda_pcm_stream simple_pcm_playback = {
 	},
 };
 
-static const struct hda_codec_ops simple_hdmi_patch_ops = {
-	.build_controls = snd_hda_hdmi_simple_build_controls,
-	.build_pcms = snd_hda_hdmi_simple_build_pcms,
-	.init = snd_hda_hdmi_simple_init,
-	.free = snd_hda_hdmi_simple_free,
-	.unsol_event = snd_hda_hdmi_simple_unsol_event,
-};
-
-int patch_simple_hdmi(struct hda_codec *codec,
-		      hda_nid_t cvt_nid, hda_nid_t pin_nid)
+int snd_hda_hdmi_simple_probe(struct hda_codec *codec,
+			      hda_nid_t cvt_nid, hda_nid_t pin_nid)
 {
 	struct hdmi_spec *spec;
 	struct hdmi_spec_per_cvt *per_cvt;
@@ -200,35 +192,52 @@ int patch_simple_hdmi(struct hda_codec *codec,
 	per_pin = snd_array_new(&spec->pins);
 	per_cvt = snd_array_new(&spec->cvts);
 	if (!per_pin || !per_cvt) {
-		snd_hda_hdmi_simple_free(codec);
+		snd_hda_hdmi_simple_remove(codec);
 		return -ENOMEM;
 	}
 	per_cvt->cvt_nid = cvt_nid;
 	per_pin->pin_nid = pin_nid;
 	spec->pcm_playback = simple_pcm_playback;
 
-	codec->patch_ops = simple_hdmi_patch_ops;
-
 	return 0;
 }
-EXPORT_SYMBOL_NS_GPL(patch_simple_hdmi, "SND_HDA_CODEC_HDMI");
+EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_simple_probe, "SND_HDA_CODEC_HDMI");
+
+/*
+ * driver entries
+ */
+
+enum { MODEL_VIA };
 
 /* VIA HDMI Implementation */
 #define VIAHDMI_CVT_NID	0x02	/* audio converter1 */
 #define VIAHDMI_PIN_NID	0x03	/* HDMI output pin1 */
 
-static int patch_via_hdmi(struct hda_codec *codec)
+static int simplehdmi_probe(struct hda_codec *codec,
+			    const struct hda_device_id *id)
 {
-	return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
+	switch (id->driver_data) {
+	case MODEL_VIA:
+		return snd_hda_hdmi_simple_probe(codec, VIAHDMI_CVT_NID,
+						 VIAHDMI_PIN_NID);
+	default:
+		return -EINVAL;
+	}
 }
 
-/*
- * patch entries
- */
+static const struct hda_codec_ops simplehdmi_codec_ops = {
+	.probe = simplehdmi_probe,
+	.remove = snd_hda_hdmi_simple_remove,
+	.build_controls = snd_hda_hdmi_simple_build_controls,
+	.build_pcms = snd_hda_hdmi_simple_build_pcms,
+	.init = snd_hda_hdmi_simple_init,
+	.unsol_event = snd_hda_hdmi_simple_unsol_event,
+};
+
 static const struct hda_device_id snd_hda_id_simplehdmi[] = {
-HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",	patch_via_hdmi),
-HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",	patch_via_hdmi),
-{} /* terminator */
+	HDA_CODEC_ID_MODEL(0x11069f80, "VX900 HDMI/DP",	MODEL_VIA),
+	HDA_CODEC_ID_MODEL(0x11069f81, "VX900 HDMI/DP",	MODEL_VIA),
+	{} /* terminator */
 };
 
 MODULE_LICENSE("GPL");
@@ -236,6 +245,7 @@ MODULE_DESCRIPTION("Simple HDMI HD-audio codec support");
 
 static struct hda_codec_driver simplehdmi_driver = {
 	.id = snd_hda_id_simplehdmi,
+	.ops = &simplehdmi_codec_ops,
 };
 
 module_hda_codec_driver(simplehdmi_driver);
diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c
index c13a63788799..f1f745187f68 100644
--- a/sound/hda/codecs/hdmi/tegrahdmi.c
+++ b/sound/hda/codecs/hdmi/tegrahdmi.c
@@ -13,6 +13,11 @@
 #include "hda_local.h"
 #include "hdmi_local.h"
 
+enum {
+	MODEL_TEGRA,
+	MODEL_TEGRA234,
+};
+
 /*
  * The HDA codec on NVIDIA Tegra contains two scratch registers that are
  * accessed using vendor-defined verbs. These registers can be used for
@@ -241,7 +246,6 @@ static int tegra_hdmi_init(struct hda_codec *codec)
 	snd_hda_hdmi_generic_init_per_pins(codec);
 
 	codec->depop_delay = 10;
-	codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
 	spec->chmap.ops.chmap_cea_alloc_validate_get_type =
 		nvhdmi_chmap_cea_alloc_validate_get_type;
 	spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
@@ -254,18 +258,8 @@ static int tegra_hdmi_init(struct hda_codec *codec)
 	return 0;
 }
 
-static int patch_tegra_hdmi(struct hda_codec *codec)
-{
-	int err;
-
-	err = snd_hda_hdmi_generic_alloc(codec);
-	if (err < 0)
-		return err;
-
-	return tegra_hdmi_init(codec);
-}
-
-static int patch_tegra234_hdmi(struct hda_codec *codec)
+static int tegrahdmi_probe(struct hda_codec *codec,
+			   const struct hda_device_id *id)
 {
 	struct hdmi_spec *spec;
 	int err;
@@ -274,31 +268,39 @@ static int patch_tegra234_hdmi(struct hda_codec *codec)
 	if (err < 0)
 		return err;
 
-	codec->dp_mst = true;
-	spec = codec->spec;
-	spec->dyn_pin_out = true;
-	spec->hdmi_intr_trig_ctrl = true;
+	if (id->driver_data == MODEL_TEGRA234) {
+		codec->dp_mst = true;
+		spec = codec->spec;
+		spec->dyn_pin_out = true;
+		spec->hdmi_intr_trig_ctrl = true;
+	}
 
 	return tegra_hdmi_init(codec);
 }
 
-/*
- * patch entries
- */
+static const struct hda_codec_ops tegrahdmi_codec_ops = {
+	.probe = tegrahdmi_probe,
+	.remove = snd_hda_hdmi_generic_remove,
+	.init = snd_hda_hdmi_generic_init,
+	.build_pcms = tegra_hdmi_build_pcms,
+	.build_controls = snd_hda_hdmi_generic_build_controls,
+	.unsol_event = snd_hda_hdmi_generic_unsol_event,
+	.suspend = snd_hda_hdmi_generic_suspend,
+	.resume = snd_hda_hdmi_generic_resume,
+};
+
 static const struct hda_device_id snd_hda_id_tegrahdmi[] = {
-HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",	patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP",	patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP",	patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP",	patch_tegra234_hdmi),
-{} /* terminator */
+	HDA_CODEC_ID_MODEL(0x10de0020, "Tegra30 HDMI",		MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de0022, "Tegra114 HDMI",		MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de0028, "Tegra124 HDMI",		MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de0029, "Tegra210 HDMI/DP",	MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de002d, "Tegra186 HDMI/DP0",	MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de002e, "Tegra186 HDMI/DP1",	MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de002f, "Tegra194 HDMI/DP2",	MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de0030, "Tegra194 HDMI/DP3",	MODEL_TEGRA),
+	HDA_CODEC_ID_MODEL(0x10de0031, "Tegra234 HDMI/DP",	MODEL_TEGRA234),
+	HDA_CODEC_ID_MODEL(0x10de0034, "Tegra264 HDMI/DP",	MODEL_TEGRA234),
+	{} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_tegrahdmi);
 
@@ -308,6 +310,7 @@ MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");
 
 static struct hda_codec_driver tegrahdmi_driver = {
 	.id = snd_hda_id_tegrahdmi,
+	.ops = &tegrahdmi_codec_ops,
 };
 
 module_hda_codec_driver(tegrahdmi_driver);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 24/27] ALSA: hda: Drop old codec binding method
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (22 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 23/27] ALSA: hda/hdmi: " Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 25/27] ALSA: hda: Drop superfluous driver->ops NULL checks Takashi Iwai
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

Now that all patch_ops usage have been converted to the new
hda_codec_ops probe, we can drop patch_ops from the hda_codec,
together with the calls of patch_ops callbacks.

The hda_codec_ops.free callback is removed as all have been replaced
with the new remove callback.

Also, correct comments mentioning "patch"; it's replaced with "codec
driver".

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/hda_codec.h          | 22 ++-------------------
 sound/hda/Makefile                 |  2 +-
 sound/hda/codecs/generic.c         | 12 ------------
 sound/hda/codecs/generic.h         |  1 -
 sound/hda/codecs/hdmi/hdmi_local.h |  2 +-
 sound/hda/common/bind.c            | 26 +++++++------------------
 sound/hda/common/codec.c           | 20 ++-----------------
 sound/hda/common/hda_local.h       |  2 --
 sound/soc/codecs/hda.c             | 20 ++++---------------
 sound/soc/codecs/hdac_hda.c        | 31 +++++++++---------------------
 10 files changed, 26 insertions(+), 112 deletions(-)

diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
index a725ac48c20c..ddc9c392f93f 100644
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -70,12 +70,8 @@ struct hda_bus {
 
 /*
  * codec preset
- *
- * Known codecs have the patch to build and set up the controls/PCMs
- * better than the generic parser.
  */
-typedef int (*hda_codec_patch_t)(struct hda_codec *);
-	
+
 #define HDA_CODEC_ID_SKIP_PROBE		0x00000001
 #define HDA_CODEC_ID_GENERIC_HDMI	0x00000101
 #define HDA_CODEC_ID_GENERIC		0x00000201
@@ -90,14 +86,6 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *);
 #define HDA_CODEC_ID(_vid, _name) \
 	HDA_CODEC_ID_REV(_vid, 0, _name)
 
-/* old macros for patch_ops -- to be deprecated */
-#define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \
-	{ .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
-	  .api_version = HDA_DEV_LEGACY, \
-	  .driver_data = (unsigned long)(_patch) }
-#define HDA_CODEC_ENTRY(_vid, _name, _patch) \
-	HDA_CODEC_REV_ENTRY(_vid, 0, _name, _patch)
-
 struct hda_codec_driver {
 	struct hdac_driver core;
 	const struct hda_device_id *id;
@@ -116,14 +104,13 @@ void hda_codec_driver_unregister(struct hda_codec_driver *drv);
 	module_driver(drv, hda_codec_driver_register, \
 		      hda_codec_driver_unregister)
 
-/* ops set by the preset patch */
+/* ops for hda codec driver */
 struct hda_codec_ops {
 	int (*probe)(struct hda_codec *codec, const struct hda_device_id *id);
 	void (*remove)(struct hda_codec *codec);
 	int (*build_controls)(struct hda_codec *codec);
 	int (*build_pcms)(struct hda_codec *codec);
 	int (*init)(struct hda_codec *codec);
-	void (*free)(struct hda_codec *codec);
 	void (*unsol_event)(struct hda_codec *codec, unsigned int res);
 	void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg,
 				unsigned int power_state);
@@ -199,9 +186,6 @@ struct hda_codec {
 	const struct hda_device_id *preset;
 	const char *modelname;	/* model name for preset */
 
-	/* set by patch */
-	struct hda_codec_ops patch_ops;
-
 	/* PCM to create, set by hda_codec_ops.build_pcms callback */
 	struct list_head pcm_list_head;
 	refcount_t pcm_ref;
@@ -500,8 +484,6 @@ int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 
 	if (driver->ops && driver->ops->check_power_status)
 		return driver->ops->check_power_status(codec, nid);
-	else if (codec->patch_ops.check_power_status)
-		return codec->patch_ops.check_power_status(codec, nid);
 	return 0;
 }
 
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index 31b9fbedaa77..d9a6def582ef 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -3,6 +3,6 @@ obj-y += core/
 obj-$(CONFIG_SND_HDA) += common/
 obj-$(CONFIG_SND_HDA) += codecs/
 # this must be the last entry after codec drivers;
-# otherwise the codec patches won't be hooked before the PCI probe
+# otherwise the codec drivers won't be hooked before the PCI probe
 # when built in kernel
 obj-$(CONFIG_SND_HDA) += controllers/
diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c
index 82c31b93424c..044f1d0aeaea 100644
--- a/sound/hda/codecs/generic.c
+++ b/sound/hda/codecs/generic.c
@@ -5190,8 +5190,6 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 	if (spec->power_down_unused || codec->power_save_node) {
 		if (!codec->power_filter)
 			codec->power_filter = snd_hda_gen_path_power_filter;
-		if (!codec->patch_ops.stream_pm)
-			codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
 	}
 
 	if (!spec->no_analog && spec->beep_nid) {
@@ -6103,15 +6101,6 @@ EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
  * the generic codec support
  */
 
-static const struct hda_codec_ops generic_patch_ops = {
-	.build_controls = snd_hda_gen_build_controls,
-	.build_pcms = snd_hda_gen_build_pcms,
-	.init = snd_hda_gen_init,
-	.free = snd_hda_gen_free,
-	.unsol_event = snd_hda_jack_unsol_event,
-	.check_power_status = snd_hda_gen_check_power_status,
-};
-
 static int snd_hda_gen_probe(struct hda_codec *codec,
 			     const struct hda_device_id *id)
 {
@@ -6132,7 +6121,6 @@ static int snd_hda_gen_probe(struct hda_codec *codec,
 	if (err < 0)
 		goto error;
 
-	codec->patch_ops = generic_patch_ops;
 	return 0;
 
 error:
diff --git a/sound/hda/codecs/generic.h b/sound/hda/codecs/generic.h
index 00a92fc55846..524591821f8c 100644
--- a/sound/hda/codecs/generic.h
+++ b/sound/hda/codecs/generic.h
@@ -312,7 +312,6 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
 
 int snd_hda_gen_init(struct hda_codec *codec);
 void snd_hda_gen_remove(struct hda_codec *codec);
-#define snd_hda_gen_free	snd_hda_gen_remove
 
 int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
 struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h
index 0654013f1fda..548241ad3fa9 100644
--- a/sound/hda/codecs/hdmi/hdmi_local.h
+++ b/sound/hda/codecs/hdmi/hdmi_local.h
@@ -57,7 +57,7 @@ struct hdmi_spec_per_pin {
 #endif
 };
 
-/* operations used by generic code that can be overridden by patches */
+/* operations used by generic code that can be overridden by codec drivers */
 struct hdmi_ops {
 	int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
 			   int dev_id, unsigned char *buf, int *eld_size);
diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c
index 56975178f533..f85c640dd54f 100644
--- a/sound/hda/common/bind.c
+++ b/sound/hda/common/bind.c
@@ -54,8 +54,6 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
 
 	if (driver->ops && driver->ops->unsol_event)
 		driver->ops->unsol_event(codec, ev);
-	else if (codec->patch_ops.unsol_event)
-		codec->patch_ops.unsol_event(codec, ev);
 }
 
 /**
@@ -91,7 +89,6 @@ static int hda_codec_driver_probe(struct device *dev)
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 	struct module *owner = dev->driver->owner;
 	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
-	hda_codec_patch_t patch;
 	int err;
 
 	if (codec->bus->core.ext_ops) {
@@ -115,19 +112,14 @@ static int hda_codec_driver_probe(struct device *dev)
 		goto error;
 	}
 
-	if (driver->ops && driver->ops->probe) {
-		err = driver->ops->probe(codec, codec->preset);
-		if (err < 0)
-			goto error_module_put;
-	} else {
-		patch = (hda_codec_patch_t)codec->preset->driver_data;
-		if (patch) {
-			err = patch(codec);
-			if (err < 0)
-				goto error_module_put;
-		}
+	if (WARN_ON(!(driver->ops && driver->ops->probe))) {
+		err = -EINVAL;
+		goto error_module_put;
 	}
 
+	err = driver->ops->probe(codec, codec->preset);
+	if (err < 0)
+		goto error_module_put;
 	err = snd_hda_codec_build_pcms(codec);
 	if (err < 0)
 		goto error_module;
@@ -148,8 +140,6 @@ static int hda_codec_driver_probe(struct device *dev)
  error_module:
 	if (driver->ops && driver->ops->remove)
 		driver->ops->remove(codec);
-	else if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
  error_module_put:
 	module_put(owner);
 
@@ -178,8 +168,6 @@ static int hda_codec_driver_remove(struct device *dev)
 
 	if (driver->ops && driver->ops->remove)
 		driver->ops->remove(codec);
-	else if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
 	snd_hda_codec_cleanup_for_unbind(codec);
 	codec->preset = NULL;
 	module_put(dev->driver->owner);
@@ -320,7 +308,7 @@ static int codec_bind_generic(struct hda_codec *codec)
  * @codec: the HDA codec
  *
  * Start parsing of the given codec tree and (re-)initialize the whole
- * patch instance.
+ * codec driver binding.
  *
  * Returns 0 if successful or a negative error code.
  */
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index 8899be764d68..33121d002087 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -766,7 +766,6 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
 		snd_hda_ctls_clear(codec);
 	codec_release_pcms(codec);
 	snd_hda_detach_beep_device(codec);
-	memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
 	snd_hda_jack_tbl_clear(codec);
 	codec->proc_widget_hook = NULL;
 	codec->spec = NULL;
@@ -1132,8 +1131,6 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 
 	if (driver->ops && driver->ops->stream_pm)
 		driver->ops->stream_pm(codec, nid, true);
-	else if (codec->patch_ops.stream_pm)
-		codec->patch_ops.stream_pm(codec, nid, true);
 	if (codec->pcm_format_first)
 		update_pcm_format(codec, p, nid, format);
 	update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
@@ -1205,8 +1202,6 @@ static void really_cleanup_stream(struct hda_codec *codec,
 	q->nid = nid;
 	if (driver->ops && driver->ops->stream_pm)
 		driver->ops->stream_pm(codec, nid, false);
-	else if (codec->patch_ops.stream_pm)
-		codec->patch_ops.stream_pm(codec, nid, false);
 }
 
 /* clean up the all conflicting obsolete streams */
@@ -2397,7 +2392,7 @@ static const struct snd_kcontrol_new dig_mixes[] = {
  * @cvt_nid: converter NID
  * @type: HDA_PCM_TYPE_*
  * Creates controls related with the digital output.
- * Called from each patch supporting the digital out.
+ * Called from each codec driver supporting the digital out.
  *
  * Returns 0 if successful, or a negative error code.
  */
@@ -2656,7 +2651,7 @@ static const struct snd_kcontrol_new dig_in_ctls[] = {
  * @nid: audio in widget NID
  *
  * Creates controls related with the SPDIF input.
- * Called from each patch supporting the SPDIF in.
+ * Called from each codec driver supporting the SPDIF in.
  *
  * Returns 0 if successful, or a negative error code.
  */
@@ -2773,9 +2768,6 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
 		/* might be called before binding to driver, too */
 		if (driver && driver->ops && driver->ops->set_power_state)
 			driver->ops->set_power_state(codec, fg, power_state);
-		else if (codec->patch_ops.set_power_state)
-			codec->patch_ops.set_power_state(codec, fg,
-							 power_state);
 		else {
 			state = power_state;
 			if (codec->power_filter)
@@ -2859,8 +2851,6 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
 	snd_hdac_enter_pm(&codec->core);
 	if (driver->ops && driver->ops->suspend)
 		driver->ops->suspend(codec);
-	else if (codec->patch_ops.suspend)
-		codec->patch_ops.suspend(codec);
 	if (!codec->no_stream_clean_at_suspend)
 		hda_cleanup_all_streams(codec);
 	state = hda_set_power_state(codec, AC_PWRST_D3);
@@ -2888,8 +2878,6 @@ static void hda_call_codec_resume(struct hda_codec *codec)
 	snd_hda_jack_set_dirty_all(codec);
 	if (driver->ops && driver->ops->resume)
 		driver->ops->resume(codec);
-	else if (codec->patch_ops.resume)
-		codec->patch_ops.resume(codec);
 	else {
 		snd_hda_codec_init(codec);
 		snd_hda_regmap_sync(codec);
@@ -3085,8 +3073,6 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
 	if (!err) {
 		if (driver->ops && driver->ops->build_controls)
 			err = driver->ops->build_controls(codec);
-		else if (codec->patch_ops.build_controls)
-			err = codec->patch_ops.build_controls(codec);
 		if (err < 0)
 			return err;
 	}
@@ -3284,8 +3270,6 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 
 	if (driver->ops && driver->ops->build_pcms)
 		err = driver->ops->build_pcms(codec);
-	else if (codec->patch_ops.build_pcms)
-		err = codec->patch_ops.build_pcms(codec);
 	else
 		return 0;
 
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index 654fe1156d56..e56bea4c9357 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -658,8 +658,6 @@ static inline int snd_hda_codec_init(struct hda_codec *codec)
 
 	if (driver->ops && driver->ops->init)
 		return driver->ops->init(codec);
-	else if (codec->patch_ops.init)
-		return codec->patch_ops.init(codec);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index ddb31001657e..126270ffd418 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -177,7 +177,6 @@ static int hda_codec_probe(struct snd_soc_component *component)
 	struct hdac_device *hdev = &codec->core;
 	struct hdac_bus *bus = hdev->bus;
 	struct hdac_ext_link *hlink;
-	hda_codec_patch_t patch;
 	int ret;
 
 #ifdef CONFIG_PM
@@ -215,19 +214,12 @@ static int hda_codec_probe(struct snd_soc_component *component)
 		goto err;
 	}
 
-	if (driver->ops && driver->ops->probe) {
-		ret = driver->ops->probe(codec, codec->preset);
-	} else {
-		patch = (hda_codec_patch_t)codec->preset->driver_data;
-		if (!patch) {
-			dev_err(&hdev->dev, "no patch specified\n");
-			ret = -EINVAL;
-			goto err;
-		}
-
-		ret = patch(codec);
+	if (WARN_ON(!(driver->ops && driver->ops->probe))) {
+		ret = -EINVAL;
+		goto err;
 	}
 
+	ret = driver->ops->probe(codec, codec->preset);
 	if (ret < 0) {
 		dev_err(&hdev->dev, "codec init failed: %d\n", ret);
 		goto err;
@@ -260,8 +252,6 @@ static int hda_codec_probe(struct snd_soc_component *component)
 parse_pcms_err:
 	if (driver->ops && driver->ops->remove)
 		driver->ops->remove(codec);
-	else if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
 err:
 	snd_hda_codec_cleanup_for_unbind(codec);
 device_new_err:
@@ -292,8 +282,6 @@ static void hda_codec_remove(struct snd_soc_component *component)
 
 	if (driver->ops && driver->ops->remove)
 		driver->ops->remove(codec);
-	else if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
 
 	snd_hda_codec_cleanup_for_unbind(codec);
 	pm_runtime_put_noidle(&hdev->dev);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 7bb7845d5e43..191cb8427664 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -411,7 +411,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 	struct hda_codec *hcodec = hda_pvt->codec;
 	struct hda_codec_driver *driver = hda_codec_to_driver(hcodec);
 	struct hdac_ext_link *hlink;
-	hda_codec_patch_t patch;
 	int ret;
 
 	hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
@@ -485,23 +484,15 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 		goto error_pm;
 	}
 
-	if (driver->ops && driver->ops->probe) {
-		ret = driver->ops->probe(hcodec, hcodec->preset);
-		if (ret < 0) {
-			dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret);
-			goto error_regmap;
-		}
-	} else {
-		patch = (hda_codec_patch_t)hcodec->preset->driver_data;
-		if (patch) {
-			ret = patch(hcodec);
-			if (ret < 0) {
-				dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret);
-				goto error_regmap;
-			}
-		} else {
-			dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__);
-		}
+	if (WARN_ON(!(driver->ops && driver->ops->probe))) {
+		ret = -EINVAL;
+		goto error_regmap;
+	}
+
+	ret = driver->ops->probe(hcodec, hcodec->preset);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret);
+		goto error_regmap;
 	}
 
 	ret = snd_hda_codec_parse_pcms(hcodec);
@@ -542,8 +533,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 error_patch:
 	if (driver->ops && driver->ops->remove)
 		driver->ops->remove(hcodec);
-	else if (hcodec->patch_ops.free)
-		hcodec->patch_ops.free(hcodec);
 error_regmap:
 	snd_hdac_regmap_exit(hdev);
 error_pm:
@@ -573,8 +562,6 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
 
 	if (driver->ops && driver->ops->remove)
 		driver->ops->remove(codec);
-	else if (codec->patch_ops.free)
-		codec->patch_ops.free(codec);
 
 	snd_hda_codec_cleanup_for_unbind(codec);
 }
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 25/27] ALSA: hda: Drop superfluous driver->ops NULL checks
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (23 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 24/27] ALSA: hda: Drop old codec binding method Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-09 16:04 ` [PATCH 26/27] MAINTAINERS: Adjust to the new HD-audio driver paths Takashi Iwai
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

After all conversions, driver->ops became a must in most places
(except for the codec power setup which might be called before binding
to the codec driver), hence we can get rid of the superfluous
driver->ops NULL checks, too.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/common/bind.c      |  6 +++---
 sound/hda/common/codec.c     | 15 +++++++--------
 sound/hda/common/hda_local.h |  2 +-
 sound/soc/codecs/hda.c       |  4 ++--
 sound/soc/codecs/hdac_hda.c  |  4 ++--
 5 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c
index f85c640dd54f..bb1090b65699 100644
--- a/sound/hda/common/bind.c
+++ b/sound/hda/common/bind.c
@@ -52,7 +52,7 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
 	if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
 		return;
 
-	if (driver->ops && driver->ops->unsol_event)
+	if (driver->ops->unsol_event)
 		driver->ops->unsol_event(codec, ev);
 }
 
@@ -138,7 +138,7 @@ static int hda_codec_driver_probe(struct device *dev)
 	return 0;
 
  error_module:
-	if (driver->ops && driver->ops->remove)
+	if (driver->ops->remove)
 		driver->ops->remove(codec);
  error_module_put:
 	module_put(owner);
@@ -166,7 +166,7 @@ static int hda_codec_driver_remove(struct device *dev)
 		wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
 	snd_power_sync_ref(codec->bus->card);
 
-	if (driver->ops && driver->ops->remove)
+	if (driver->ops->remove)
 		driver->ops->remove(codec);
 	snd_hda_codec_cleanup_for_unbind(codec);
 	codec->preset = NULL;
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index 33121d002087..fa07a296abe8 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -1129,7 +1129,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 	if (!p)
 		return;
 
-	if (driver->ops && driver->ops->stream_pm)
+	if (driver->ops->stream_pm)
 		driver->ops->stream_pm(codec, nid, true);
 	if (codec->pcm_format_first)
 		update_pcm_format(codec, p, nid, format);
@@ -1200,7 +1200,7 @@ static void really_cleanup_stream(struct hda_codec *codec,
 );
 	memset(q, 0, sizeof(*q));
 	q->nid = nid;
-	if (driver->ops && driver->ops->stream_pm)
+	if (driver->ops->stream_pm)
 		driver->ops->stream_pm(codec, nid, false);
 }
 
@@ -2849,7 +2849,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
 	unsigned int state;
 
 	snd_hdac_enter_pm(&codec->core);
-	if (driver->ops && driver->ops->suspend)
+	if (driver->ops->suspend)
 		driver->ops->suspend(codec);
 	if (!codec->no_stream_clean_at_suspend)
 		hda_cleanup_all_streams(codec);
@@ -2876,7 +2876,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
 	restore_shutup_pins(codec);
 	hda_exec_init_verbs(codec);
 	snd_hda_jack_set_dirty_all(codec);
-	if (driver->ops && driver->ops->resume)
+	if (driver->ops->resume)
 		driver->ops->resume(codec);
 	else {
 		snd_hda_codec_init(codec);
@@ -3071,7 +3071,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
 	/* continue to initialize... */
 	err = snd_hda_codec_init(codec);
 	if (!err) {
-		if (driver->ops && driver->ops->build_controls)
+		if (driver->ops->build_controls)
 			err = driver->ops->build_controls(codec);
 		if (err < 0)
 			return err;
@@ -3268,11 +3268,10 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 	if (!list_empty(&codec->pcm_list_head))
 		return 0; /* already parsed */
 
-	if (driver->ops && driver->ops->build_pcms)
-		err = driver->ops->build_pcms(codec);
-	else
+	if (!driver->ops->build_pcms)
 		return 0;
 
+	err = driver->ops->build_pcms(codec);
 	if (err < 0) {
 		codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
 			  codec->core.addr, err);
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index e56bea4c9357..a7e53277a0fe 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -656,7 +656,7 @@ static inline int snd_hda_codec_init(struct hda_codec *codec)
 {
 	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
 
-	if (driver->ops && driver->ops->init)
+	if (driver->ops->init)
 		return driver->ops->init(codec);
 	return 0;
 }
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index 126270ffd418..c8344e28df3d 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -250,7 +250,7 @@ static int hda_codec_probe(struct snd_soc_component *component)
 complete_err:
 	hda_codec_unregister_dais(codec, component);
 parse_pcms_err:
-	if (driver->ops && driver->ops->remove)
+	if (driver->ops->remove)
 		driver->ops->remove(codec);
 err:
 	snd_hda_codec_cleanup_for_unbind(codec);
@@ -280,7 +280,7 @@ static void hda_codec_remove(struct snd_soc_component *component)
 
 	hda_codec_unregister_dais(codec, component);
 
-	if (driver->ops && driver->ops->remove)
+	if (driver->ops->remove)
 		driver->ops->remove(codec);
 
 	snd_hda_codec_cleanup_for_unbind(codec);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 191cb8427664..afd8edf10fdc 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -531,7 +531,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
 	return 0;
 
 error_patch:
-	if (driver->ops && driver->ops->remove)
+	if (driver->ops->remove)
 		driver->ops->remove(hcodec);
 error_regmap:
 	snd_hdac_regmap_exit(hdev);
@@ -560,7 +560,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
 	pm_runtime_disable(&hdev->dev);
 	snd_hdac_ext_bus_link_put(hdev->bus, hlink);
 
-	if (driver->ops && driver->ops->remove)
+	if (driver->ops->remove)
 		driver->ops->remove(codec);
 
 	snd_hda_codec_cleanup_for_unbind(codec);
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 26/27] MAINTAINERS: Adjust to the new HD-audio driver paths
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (24 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 25/27] ALSA: hda: Drop superfluous driver->ops NULL checks Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-10 10:30   ` Richard Fitzgerald
  2025-07-09 16:04 ` [PATCH 27/27] ALSA: hda: Return the codec init error properly at snd_hda_codec_build_controls() Takashi Iwai
  2025-07-11 12:55 ` [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
  27 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

The HD-audio drivers are moved under sound/hda now.
Correct the locations.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 MAINTAINERS | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5bfcaf0732ed..bd86f2ad65b9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5741,9 +5741,9 @@ F:	drivers/spi/spi-cs42l43*
 F:	include/dt-bindings/sound/cs*
 F:	include/linux/mfd/cs42l43*
 F:	include/sound/cs*
-F:	sound/pci/hda/cirrus*
-F:	sound/pci/hda/cs*
-F:	sound/pci/hda/hda_component*
+F:	sound/hda/codecs/cirrus*
+F:	sound/hda/codecs/side-codecs/cs*
+F:	sound/hda/codecs/side-codecs/hda_component*
 F:	sound/soc/codecs/cs*
 
 CIRRUS LOGIC HAPTIC DRIVERS
@@ -24533,7 +24533,7 @@ F:	Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
 F:	Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
 F:	include/sound/tas2*.h
 F:	include/sound/tlv320*.h
-F:	sound/pci/hda/tas2781_hda_i2c.c
+F:	sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
 F:	sound/soc/codecs/pcm1681.c
 F:	sound/soc/codecs/pcm1789*.*
 F:	sound/soc/codecs/pcm179x*.*
@@ -27473,7 +27473,7 @@ SENARYTECH AUDIO CODEC DRIVER
 M:	bo liu <bo.liu@senarytech.com>
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
-F:	sound/pci/hda/patch_senarytech.c
+F:	sound/hda/codecs/senarytech.c
 
 THE REST
 M:	Linus Torvalds <torvalds@linux-foundation.org>
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 27/27] ALSA: hda: Return the codec init error properly at snd_hda_codec_build_controls()
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (25 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 26/27] MAINTAINERS: Adjust to the new HD-audio driver paths Takashi Iwai
@ 2025-07-09 16:04 ` Takashi Iwai
  2025-07-11 12:55 ` [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-09 16:04 UTC (permalink / raw)
  To: linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

The error from snd_hda_codec_init() was ignored in
snd_hda_codec_build_controls(), which should have been taken account
and abort the flow.  Fix it now.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/hda/common/codec.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index fa07a296abe8..8e47769ef0ce 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -3065,14 +3065,16 @@ EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps);
 int snd_hda_codec_build_controls(struct hda_codec *codec)
 {
 	struct hda_codec_driver *driver = hda_codec_to_driver(codec);
-	int err = 0;
+	int err;
 
 	hda_exec_init_verbs(codec);
 	/* continue to initialize... */
 	err = snd_hda_codec_init(codec);
-	if (!err) {
-		if (driver->ops->build_controls)
-			err = driver->ops->build_controls(codec);
+	if (err < 0)
+		return err;
+
+	if (driver->ops->build_controls) {
+		err = driver->ops->build_controls(codec);
 		if (err < 0)
 			return err;
 	}
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-09 16:04 ` [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory Takashi Iwai
@ 2025-07-10 10:05   ` Richard Fitzgerald
  2025-07-14  8:57   ` Cezary Rojewski
  1 sibling, 0 replies; 48+ messages in thread
From: Richard Fitzgerald @ 2025-07-10 10:05 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 09/07/2025 5:04 pm, Takashi Iwai wrote:
> Now move the all remaining codec drivers from sound/pci/hda to
> sound/hda/codecs subdirectory.  Some drivers are put under the further
> vendor subdirectory, and the vendor helper code (*_helper.c) are put
> under helpers subdirectory.  Also the sub-codec drivers are moved under
> a different subdirectory, sound/hda/codecs/sub-codecs, for
> distinguishing from the main HD-audio codec drivers.
> 
> The prefix patch_ and hda_ as well as the suffix _helper are dropped
> from file names as they are mostly superfluous.
> 
> No functional changes but just file path shuffling.
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>

For the Cirrus files:
Reviewed-by: Richard Fitzgerald <rf@opensource.cirrus.com>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 16/27] ALSA: hda/cs8409: Rewrite to new probe method
  2025-07-09 16:04 ` [PATCH 16/27] ALSA: hda/cs8409: Rewrite to new probe method Takashi Iwai
@ 2025-07-10 10:25   ` Richard Fitzgerald
  0 siblings, 0 replies; 48+ messages in thread
From: Richard Fitzgerald @ 2025-07-10 10:25 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 09/07/2025 5:04 pm, Takashi Iwai wrote:
> Convert the CS8409 codec driver to use the new hda_codec_ops probe.
> The Dolphin support needs an override of unsol_event callback, and
> redirect via spec->unsol_event function pointer for now.
> 
> Other than that, no functional changes.
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>

Reviewed-by: Richard Fitzgerald <rf@opensource.cirrus.com>


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 26/27] MAINTAINERS: Adjust to the new HD-audio driver paths
  2025-07-09 16:04 ` [PATCH 26/27] MAINTAINERS: Adjust to the new HD-audio driver paths Takashi Iwai
@ 2025-07-10 10:30   ` Richard Fitzgerald
  0 siblings, 0 replies; 48+ messages in thread
From: Richard Fitzgerald @ 2025-07-10 10:30 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 09/07/2025 5:04 pm, Takashi Iwai wrote:
> The HD-audio drivers are moved under sound/hda now.
> Correct the locations.
> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>   MAINTAINERS | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5bfcaf0732ed..bd86f2ad65b9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5741,9 +5741,9 @@ F:	drivers/spi/spi-cs42l43*
>   F:	include/dt-bindings/sound/cs*
>   F:	include/linux/mfd/cs42l43*
>   F:	include/sound/cs*
> -F:	sound/pci/hda/cirrus*
> -F:	sound/pci/hda/cs*
> -F:	sound/pci/hda/hda_component*
> +F:	sound/hda/codecs/cirrus*
This should be sound/hda/codecs/side-codecs/cirrus*
It's to pick up the cirrus_scodec* files.

> +F:	sound/hda/codecs/side-codecs/cs*
> +F:	sound/hda/codecs/side-codecs/hda_component*
>   F:	sound/soc/codecs/cs*


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 00/27] ALSA: Reorganize HD-audio driver code
  2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
                   ` (26 preceding siblings ...)
  2025-07-09 16:04 ` [PATCH 27/27] ALSA: hda: Return the codec init error properly at snd_hda_codec_build_controls() Takashi Iwai
@ 2025-07-11 12:55 ` Takashi Iwai
  27 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-11 12:55 UTC (permalink / raw)
  To: linux-sound
  Cc: Stephen Rothwell, Richard Fitzgerald, Kailang, Kai Vehmanen,
	Cezary Rojewski, Amadeusz Sławiński, patches, Baojun Xu,
	bo liu

On Wed, 09 Jul 2025 18:04:03 +0200,
Takashi Iwai wrote:
> 
> HD-audio driver is known to be quite messy in both file structures and
> its design, but until now I haven't touched its files paths so much
> because I set a higher priority for the easiness of backport to stable
> kernels.  But, you can't leave garbages forever, it's been already
> high time for a large clean up -- so here it is.
> 
> The basic idea is to move the code from sound/pci/hda/* into different
> subdirectories in sound/hda/ per functionality, as most of the stuff
> are independent from PCI, but rather HD-audio bus specific.
> 
> So, now the all HD-audio driver code are moved under sound/hda:
> 
>   % ls sound/hda 
>   codecs/  common/  controllers/  core/  Kconfig  Makefile
> 
> * The former hda core code is found in sound/hda/core.
> * The former snd-hda-codec code is found in sound/hda/common.
> * The former snd-hda-intel, tegra and acpi are put in
>   sound/hda/controllers.
> * The former patch_* and co are put to sound/hda/codecs.
> * Realtek codec driver is split to several modules as
>   sound/hda/codecs/realtek/alc*.
> * Cirrus codec driver is split to cs420x and cs421x, put under
>   sound/hda/codecs/cirrus together with cs8409.
> * HDMI codec driver is split to several modules under
>   sound/hda/codecs/hdmi
> * Cirrus and TI sub-codecs are put under sound/hda/codecs/side-codecs
> 
> Also, the probe of the HD-audio codec driver is moved into the
> driver's ops instead of the ugly patch_ops embedded in hda_codec
> object. (As of now, hda_codec_driver.ops is a pointer, but it can be
> embedded later, too.)
> 
> This change required some code to be modified without the dynamic
> override of callbacks.
> 
> In future, we may convert the runtime PM handling to use the standard
> pm_ops, too.  This was raised some time ago during the discussion with
> Realtek devs.
> 
> The tree applying those patches is found in topic/hda-reorg branch of
> sound git tree:
>   https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git/log/?h=topic/hda-reorg

I merged this change to for-next branch now, destined for 6.17.

It means that there may be some merge conflict in future in linux-next
because of many file renames from sound/pci/hda/* -> sound/hda/*.
So adding Stephen to Cc.  The conflict resolution should be relatively
easy, though.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h
  2025-07-09 16:04 ` [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h Takashi Iwai
@ 2025-07-14  8:40   ` Cezary Rojewski
  0 siblings, 0 replies; 48+ messages in thread
From: Cezary Rojewski @ 2025-07-14  8:40 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> The get_wcaps() and co are used not only by HD-audio core but also

What is 'co'? Meaning get_wpacs() and friends?

> other driver code, hence it'd be better to put into the common header
> instead of local.h.
> 
> OTOH, there are macros of the same name like get_wcaps() that are
> still used in sound/pci/hda/* locally, and those conflict with each
> other.  So we need to rename get_wcaps() (to be moved from hda-core)
> with the proper snd_hdac prefix for avoiding name conflicts, and
> define in the common hdaudio.h.

No problems found, just some nitpicks.

Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>

> 
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>   include/sound/hdaudio.h      | 24 ++++++++++++++++++++++++
>   sound/hda/hdac_device.c      |  8 ++++----
>   sound/hda/hdac_sysfs.c       | 14 +++++++-------
>   sound/hda/local.h            | 21 ---------------------
>   sound/soc/codecs/hdac_hdmi.c | 21 ++++++++++-----------
>   5 files changed, 45 insertions(+), 43 deletions(-)
> 
> diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
> index 25668eee65cf..d38234f8fe44 100644
> --- a/include/sound/hdaudio.h
> +++ b/include/sound/hdaudio.h
> @@ -680,6 +680,30 @@ static inline void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
>   }
>   #endif /* CONFIG_SND_HDA_DSP_LOADER */
>   
> +/*
> + * Easy macros for widget capabilities
> + */

Nitpick: there is just one macro here.

TBH perhaps there is a better location for it - where all 
snd_hdac_read_parm() could lie - but that's probably a subject for a 
different tale.

> +#define snd_hdac_get_wcaps(codec, nid) \
> +	snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)

In future wording for "parameter" could also be streamlined. Typically I 
see 'param' in the code. "parm" is more of an outlier.

> +
> +/* get the widget type from widget capability bits */
> +static inline int snd_hdac_get_wcaps_type(unsigned int wcaps)
> +{
> +	if (!wcaps)
> +		return -1; /* invalid type */
> +	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
> +}
> +
> +/* get the number of supported channels */
> +static inline unsigned int snd_hdac_get_wcaps_channels(u32 wcaps)
> +{
> +	unsigned int chans;
> +
> +	chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
> +	chans = (chans + 1) * 2;
> +
> +	return chans;
> +}

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 02/27] ALSA: hda: Move HD-audio core stuff into sound/hda/core
  2025-07-09 16:04 ` [PATCH 02/27] ALSA: hda: Move HD-audio core stuff into sound/hda/core Takashi Iwai
@ 2025-07-14  8:41   ` Cezary Rojewski
  0 siblings, 0 replies; 48+ messages in thread
From: Cezary Rojewski @ 2025-07-14  8:41 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> This is a part of HD-audio code restructuring.
> Simply move the current code of sound/hda/* into the subdirectory
> sound/hda/core, so that more stuff can be moved into sound/hda cleanly
> later.

Nitpicks: I'd suggest to drop 'stuff' in the title, 'HD-audio core' is 
enough. Same with 'Simply move'. 'Move' is sufficient.

> 
> Most of file names with hdac_ and hdac_ext_ prefix are renamed without
> the prefix, since they can be identified well in the directory name
> and superfluous.
> 

Just nitpicks - nothing TODO as a must, looks good as is.

Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>

> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>   sound/hda/Kconfig                             | 67 +------------------
>   sound/hda/Makefile                            | 22 +-----
>   sound/hda/core/Kconfig                        | 67 +++++++++++++++++++
>   sound/hda/core/Makefile                       | 22 ++++++
>   sound/hda/{ => core}/array.c                  |  0
>   sound/hda/{hdac_bus.c => core/bus.c}          |  0
>   .../{hdac_component.c => core/component.c}    |  0
>   .../{hdac_controller.c => core/controller.c}  |  0
>   sound/hda/{hdac_device.c => core/device.c}    |  0
>   sound/hda/{ => core}/ext/Makefile             |  2 +-
>   .../{ext/hdac_ext_bus.c => core/ext/bus.c}    |  0
>   .../ext/controller.c}                         |  0
>   .../hdac_ext_stream.c => core/ext/stream.c}   |  0
>   sound/hda/{ => core}/hda_bus_type.c           |  0
>   sound/hda/{ => core}/hdmi_chmap.c             |  0
>   sound/hda/{hdac_i915.c => core/i915.c}        |  0
>   sound/hda/{ => core}/intel-dsp-config.c       |  0
>   sound/hda/{ => core}/intel-nhlt.c             |  0
>   sound/hda/{ => core}/intel-sdw-acpi.c         |  0
>   sound/hda/{ => core}/local.h                  |  0
>   sound/hda/{hdac_regmap.c => core/regmap.c}    |  0
>   sound/hda/{hdac_stream.c => core/stream.c}    |  0
>   sound/hda/{hdac_sysfs.c => core/sysfs.c}      |  0
>   sound/hda/{ => core}/trace.c                  |  0
>   sound/hda/{ => core}/trace.h                  |  0
>   25 files changed, 92 insertions(+), 88 deletions(-)
>   create mode 100644 sound/hda/core/Kconfig
>   create mode 100644 sound/hda/core/Makefile
>   rename sound/hda/{ => core}/array.c (100%)
>   rename sound/hda/{hdac_bus.c => core/bus.c} (100%)
>   rename sound/hda/{hdac_component.c => core/component.c} (100%)
>   rename sound/hda/{hdac_controller.c => core/controller.c} (100%)
>   rename sound/hda/{hdac_device.c => core/device.c} (100%)
>   rename sound/hda/{ => core}/ext/Makefile (54%)
>   rename sound/hda/{ext/hdac_ext_bus.c => core/ext/bus.c} (100%)
>   rename sound/hda/{ext/hdac_ext_controller.c => core/ext/controller.c} (100%)
>   rename sound/hda/{ext/hdac_ext_stream.c => core/ext/stream.c} (100%)
>   rename sound/hda/{ => core}/hda_bus_type.c (100%)
>   rename sound/hda/{ => core}/hdmi_chmap.c (100%)
>   rename sound/hda/{hdac_i915.c => core/i915.c} (100%)
>   rename sound/hda/{ => core}/intel-dsp-config.c (100%)
>   rename sound/hda/{ => core}/intel-nhlt.c (100%)
>   rename sound/hda/{ => core}/intel-sdw-acpi.c (100%)
>   rename sound/hda/{ => core}/local.h (100%)
>   rename sound/hda/{hdac_regmap.c => core/regmap.c} (100%)
>   rename sound/hda/{hdac_stream.c => core/stream.c} (100%)
>   rename sound/hda/{hdac_sysfs.c => core/sysfs.c} (100%)
>   rename sound/hda/{ => core}/trace.c (100%)
>   rename sound/hda/{ => core}/trace.h (100%)

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-09 16:04 ` [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory Takashi Iwai
  2025-07-10 10:05   ` Richard Fitzgerald
@ 2025-07-14  8:57   ` Cezary Rojewski
  2025-07-14  9:04     ` Takashi Iwai
  1 sibling, 1 reply; 48+ messages in thread
From: Cezary Rojewski @ 2025-07-14  8:57 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> Now move the all remaining codec drivers from sound/pci/hda to
> sound/hda/codecs subdirectory.  Some drivers are put under the further
> vendor subdirectory, and the vendor helper code (*_helper.c) are put
> under helpers subdirectory.  Also the sub-codec drivers are moved under
> a different subdirectory, sound/hda/codecs/sub-codecs, for
> distinguishing from the main HD-audio codec drivers.
> 
> The prefix patch_ and hda_ as well as the suffix _helper are dropped
> from file names as they are mostly superfluous.
> 
> No functional changes but just file path shuffling.
> 

Path: codecs/side-codecs/ looks wierd. My suggestion is to avoid the 
repeat and stay with codecs/side/.

In regard to 'helpers', I believe some of these .c files could be 
converted to headers and lie in sound/hda/quirks/ directory. These are 
more of a platform-level files, not sound/hda/codecs/ per-se.

> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>   sound/hda/Kconfig                             |   1 +
>   sound/hda/Makefile                            |   1 +
>   sound/{pci/hda => hda/codecs}/Kconfig         | 158 +-----------------
>   sound/hda/codecs/Makefile                     |  31 ++++
>   .../patch_analog.c => hda/codecs/analog.c}    |   2 +-
>   .../patch_ca0110.c => hda/codecs/ca0110.c}    |   2 +-
>   .../patch_ca0132.c => hda/codecs/ca0132.c}    |   2 +-
>   sound/{pci/hda => hda/codecs}/ca0132_regs.h   |   0
>   sound/hda/codecs/cirrus/Kconfig               |  21 +++
>   sound/hda/codecs/cirrus/Makefile              |   8 +
>   .../codecs/cirrus/cirrus.c}                   |   2 +-
>   .../codecs/cirrus/cs8409-tables.c}            |   4 +-
>   .../codecs/cirrus/cs8409.c}                   |   2 +-
>   .../codecs/cirrus/cs8409.h}                   |   2 +-
>   .../patch_cmedia.c => hda/codecs/cmedia.c}    |   2 +-
>   .../codecs/conexant.c}                        |   6 +-
>   .../hda_generic.c => hda/codecs/generic.c}    |   2 +-
>   .../hda_generic.h => hda/codecs/generic.h}    |   0
>   sound/hda/codecs/hdmi/Makefile                |   6 +
>   .../hda/hda_eld.c => hda/codecs/hdmi/eld.c}   |   0
>   .../patch_hdmi.c => hda/codecs/hdmi/hdmi.c}   |   2 +-
>   .../codecs/helpers/hp_x360.c}                 |   0
>   .../codecs/helpers/ideapad_hotkey_led.c}      |   0
>   .../codecs/helpers/ideapad_s740.c}            |   0
>   .../codecs/helpers/thinkpad.c}                |   0
>   .../patch_realtek.c => hda/codecs/realtek.c}  |  12 +-
>   .../codecs/senarytech.c}                      |   4 +-
>   .../patch_si3054.c => hda/codecs/si3054.c}    |   0
>   sound/hda/codecs/side-codecs/Kconfig          | 128 ++++++++++++++
>   sound/hda/codecs/side-codecs/Makefile         |  28 ++++
>   .../codecs/side-codecs}/cirrus_scodec.c       |   0
>   .../codecs/side-codecs}/cirrus_scodec.h       |   0
>   .../codecs/side-codecs}/cirrus_scodec_test.c  |   0
>   .../codecs/side-codecs}/cs35l41_hda.c         |   2 +-
>   .../codecs/side-codecs}/cs35l41_hda.h         |   0
>   .../codecs/side-codecs}/cs35l41_hda_i2c.c     |   0
>   .../side-codecs}/cs35l41_hda_property.c       |   0
>   .../side-codecs}/cs35l41_hda_property.h       |   0
>   .../codecs/side-codecs}/cs35l41_hda_spi.c     |   0
>   .../codecs/side-codecs}/cs35l56_hda.c         |   2 +-
>   .../codecs/side-codecs}/cs35l56_hda.h         |   0
>   .../codecs/side-codecs}/cs35l56_hda_i2c.c     |   0
>   .../codecs/side-codecs}/cs35l56_hda_spi.c     |   0
>   .../codecs/side-codecs}/hda_component.c       |   0
>   .../codecs/side-codecs}/hda_component.h       |   0
>   .../codecs/side-codecs}/tas2781_hda.c         |   0
>   .../codecs/side-codecs}/tas2781_hda.h         |   0
>   .../codecs/side-codecs}/tas2781_hda_i2c.c     |   2 +-
>   .../codecs/side-codecs}/tas2781_hda_spi.c     |   2 +-
>   .../codecs/sigmatel.c}                        |   4 +-
>   .../{pci/hda/patch_via.c => hda/codecs/via.c} |   2 +-
>   sound/pci/Kconfig                             |   2 -
>   sound/pci/Makefile                            |   1 -
>   sound/pci/hda/Makefile                        |  61 -------
>   54 files changed, 257 insertions(+), 247 deletions(-)
>   rename sound/{pci/hda => hda/codecs}/Kconfig (55%)
>   create mode 100644 sound/hda/codecs/Makefile
>   rename sound/{pci/hda/patch_analog.c => hda/codecs/analog.c} (99%)
>   rename sound/{pci/hda/patch_ca0110.c => hda/codecs/ca0110.c} (98%)
>   rename sound/{pci/hda/patch_ca0132.c => hda/codecs/ca0132.c} (99%)
>   rename sound/{pci/hda => hda/codecs}/ca0132_regs.h (100%)
>   create mode 100644 sound/hda/codecs/cirrus/Kconfig
>   create mode 100644 sound/hda/codecs/cirrus/Makefile
>   rename sound/{pci/hda/patch_cirrus.c => hda/codecs/cirrus/cirrus.c} (99%)
>   rename sound/{pci/hda/patch_cs8409-tables.c => hda/codecs/cirrus/cs8409-tables.c} (99%)
>   rename sound/{pci/hda/patch_cs8409.c => hda/codecs/cirrus/cs8409.c} (99%)
>   rename sound/{pci/hda/patch_cs8409.h => hda/codecs/cirrus/cs8409.h} (99%)
>   rename sound/{pci/hda/patch_cmedia.c => hda/codecs/cmedia.c} (99%)
>   rename sound/{pci/hda/patch_conexant.c => hda/codecs/conexant.c} (99%)
>   rename sound/{pci/hda/hda_generic.c => hda/codecs/generic.c} (99%)
>   rename sound/{pci/hda/hda_generic.h => hda/codecs/generic.h} (100%)
>   create mode 100644 sound/hda/codecs/hdmi/Makefile
>   rename sound/{pci/hda/hda_eld.c => hda/codecs/hdmi/eld.c} (100%)
>   rename sound/{pci/hda/patch_hdmi.c => hda/codecs/hdmi/hdmi.c} (99%)
>   rename sound/{pci/hda/hp_x360_helper.c => hda/codecs/helpers/hp_x360.c} (100%)
>   rename sound/{pci/hda/ideapad_hotkey_led_helper.c => hda/codecs/helpers/ideapad_hotkey_led.c} (100%)
>   rename sound/{pci/hda/ideapad_s740_helper.c => hda/codecs/helpers/ideapad_s740.c} (100%)
>   rename sound/{pci/hda/thinkpad_helper.c => hda/codecs/helpers/thinkpad.c} (100%)
>   rename sound/{pci/hda/patch_realtek.c => hda/codecs/realtek.c} (99%)
>   rename sound/{pci/hda/patch_senarytech.c => hda/codecs/senarytech.c} (98%)
>   rename sound/{pci/hda/patch_si3054.c => hda/codecs/si3054.c} (100%)
>   create mode 100644 sound/hda/codecs/side-codecs/Kconfig
>   create mode 100644 sound/hda/codecs/side-codecs/Makefile
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.h (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec_test.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.c (99%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.h (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_i2c.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.h (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_spi.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.c (99%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.h (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_i2c.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_spi.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.h (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.c (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.h (100%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_i2c.c (99%)
>   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_spi.c (99%)
>   rename sound/{pci/hda/patch_sigmatel.c => hda/codecs/sigmatel.c} (99%)
>   rename sound/{pci/hda/patch_via.c => hda/codecs/via.c} (99%)
>   delete mode 100644 sound/pci/hda/Makefile

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 07/27] ALSA: hda: Split Realtek HD-audio codec driver
  2025-07-09 16:04 ` [PATCH 07/27] ALSA: hda: Split Realtek HD-audio codec driver Takashi Iwai
@ 2025-07-14  9:02   ` Cezary Rojewski
  0 siblings, 0 replies; 48+ messages in thread
From: Cezary Rojewski @ 2025-07-14  9:02 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu



On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> The snd-hda-codec-realtek driver supports many different codec models
> and accumulated lots of quirks.  Now let's split it to multiple
> modules per probe function, i.e. for ALC260, ALC262, ALC269, etc.
> 
> The common code and quirks are provided by the common library module,
> snd-hda-codec-realtek-lib now.  One drawback of this action is that
> many symbols have to be exported.  But they are limited with
> SND_HDA_CODEC_REALTEK namespace, at least.
> 
> This patch tries to be idiomatic and doesn't try to rewrite the
> existing code.  We can move the codec model-specific code into each
> codec driver later.

Thank you for mentioning this.

> 
> The HD-audio sub-codec component binding is currently specific to
> ALC269, hence the management is moved into alc269.c.
> After that, alc_free() became identical with snd_hda_gen_free(), and
> it's replaced as a macro just to call snd_hda_gen_free().
> 

That's some outstanding work right there, Takashi. Given the commit 
message above, any refactoring shall be left for later. My only comment 
is related to: sound/hda/codecs/realtek/realtek.c :)
Perhaps 'common.c/h' ?

Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>

> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>   sound/hda/codecs/Kconfig                      |   14 +-
>   sound/hda/codecs/Makefile                     |    5 +-
>   sound/hda/codecs/realtek/Kconfig              |   90 +
>   sound/hda/codecs/realtek/Makefile             |   26 +
>   sound/hda/codecs/realtek/alc260.c             |  276 +
>   sound/hda/codecs/realtek/alc262.c             |  199 +
>   sound/hda/codecs/realtek/alc268.c             |  176 +
>   .../codecs/{realtek.c => realtek/alc269.c}    | 5727 +----------------
>   sound/hda/codecs/realtek/alc662.c             | 1102 ++++
>   sound/hda/codecs/realtek/alc680.c             |   53 +
>   sound/hda/codecs/realtek/alc861.c             |  149 +
>   sound/hda/codecs/realtek/alc861vd.c           |  123 +
>   sound/hda/codecs/realtek/alc880.c             |  497 ++
>   sound/hda/codecs/realtek/alc882.c             |  847 +++
>   sound/hda/codecs/realtek/realtek.c            | 2314 +++++++
>   sound/hda/codecs/realtek/realtek.h            |  302 +
>   16 files changed, 6191 insertions(+), 5709 deletions(-)
>   create mode 100644 sound/hda/codecs/realtek/Kconfig
>   create mode 100644 sound/hda/codecs/realtek/Makefile
>   create mode 100644 sound/hda/codecs/realtek/alc260.c
>   create mode 100644 sound/hda/codecs/realtek/alc262.c
>   create mode 100644 sound/hda/codecs/realtek/alc268.c
>   rename sound/hda/codecs/{realtek.c => realtek/alc269.c} (64%)
>   create mode 100644 sound/hda/codecs/realtek/alc662.c
>   create mode 100644 sound/hda/codecs/realtek/alc680.c
>   create mode 100644 sound/hda/codecs/realtek/alc861.c
>   create mode 100644 sound/hda/codecs/realtek/alc861vd.c
>   create mode 100644 sound/hda/codecs/realtek/alc880.c
>   create mode 100644 sound/hda/codecs/realtek/alc882.c
>   create mode 100644 sound/hda/codecs/realtek/realtek.c
>   create mode 100644 sound/hda/codecs/realtek/realtek.h
> 
> diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
> index bac19a664be0..0bb675ab84fe 100644
> --- a/sound/hda/codecs/Kconfig
> +++ b/sound/hda/codecs/Kconfig
> @@ -4,19 +4,6 @@ if SND_HDA
>   config SND_HDA_GENERIC_LEDS
>          bool
>   
> -config SND_HDA_CODEC_REALTEK
> -	tristate "Build Realtek HD-audio codec support"
> -	depends on INPUT
> -	select SND_HDA_GENERIC
> -	select SND_HDA_GENERIC_LEDS
> -	select SND_HDA_SCODEC_COMPONENT
> -	help
> -	  Say Y or M here to include Realtek HD-audio codec support in
> -	  snd-hda-intel driver, such as ALC880.
> -
> -comment "Set to Y if you want auto-loading the codec driver"
> -	depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
> -
>   config SND_HDA_CODEC_ANALOG
>   	tristate "Build Analog Devices HD-audio codec support"
>   	select SND_HDA_GENERIC
> @@ -162,6 +149,7 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
>   	  This feature can impact power consumption as resources
>   	  are kept reserved both at transmitter and receiver.
>   
> +source "sound/hda/codecs/realtek/Kconfig"
>   source "sound/hda/codecs/cirrus/Kconfig"
>   source "sound/hda/codecs/side-codecs/Kconfig"
>   
> diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
> index 205cd1373b42..14e5041aa4f0 100644
> --- a/sound/hda/codecs/Makefile
> +++ b/sound/hda/codecs/Makefile
> @@ -2,30 +2,31 @@
>   subdir-ccflags-y += -I$(src)/../common
>   
>   snd-hda-codec-generic-y :=	generic.o
> +snd-hda-codec-cmedia-y :=	cmedia.o
>   snd-hda-codec-analog-y :=	analog.o
>   snd-hda-codec-ca0110-y :=	ca0110.o
>   snd-hda-codec-ca0132-y :=	ca0132.o
>   snd-hda-codec-cmedia-y :=	cmedia.o
>   snd-hda-codec-conexant-y :=	conexant.o
>   snd-hda-codec-idt-y :=		sigmatel.o
> -snd-hda-codec-realtek-y :=	realtek.o
>   snd-hda-codec-senarytech-y :=	senarytech.o
>   snd-hda-codec-si3054-y :=	si3054.o
>   snd-hda-codec-via-y :=		via.o
>   
>   obj-y += cirrus/
>   obj-y += hdmi/
> +obj-y += realtek/
>   obj-y += side-codecs/
>   
>   # codec drivers
>   obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
> +obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
>   obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
>   obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
>   obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
>   obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
>   obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
>   obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
> -obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
>   obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
>   obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
>   obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
> diff --git a/sound/hda/codecs/realtek/Kconfig b/sound/hda/codecs/realtek/Kconfig
> new file mode 100644
> index 000000000000..4b3ab28203b4
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/Kconfig
> @@ -0,0 +1,90 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +menuconfig SND_HDA_CODEC_REALTEK
> +	bool "Realtek HD-audio codec support"
> +
> +if SND_HDA_CODEC_REALTEK
> +
> +config SND_HDA_CODEC_REALTEK_LIB
> +	tristate
> +	select SND_HDA_GENERIC
> +	select SND_HDA_GENERIC_LEDS
> +	select SND_HDA_SCODEC_COMPONENT
> +
> +config SND_HDA_CODEC_ALC260
> +	tristate "Build Realtek ALC260 HD-audio codec support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC260 HD-audio codec support
> +
> +config SND_HDA_CODEC_ALC262
> +	tristate "Build Realtek ALC262 HD-audio codec support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC262 HD-audio codec support
> +
> +config SND_HDA_CODEC_ALC268
> +	tristate "Build Realtek ALC268 HD-audio codec support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC268 and compatible HD-audio
> +	  codec support
> +
> +config SND_HDA_CODEC_ALC269
> +	tristate "Build Realtek ALC269 HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC269 and compatible HD-audio
> +	  codec support
> +
> +config SND_HDA_CODEC_ALC662
> +	tristate "Build Realtek ALC662 HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC662 and compatible HD-audio
> +	  codec support
> +
> +config SND_HDA_CODEC_ALC680
> +	tristate "Build Realtek ALC680 HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC680 HD-audio codec support
> +
> +config SND_HDA_CODEC_ALC861
> +	tristate "Build Realtek ALC861 HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC861 HD-audio codec support
> +
> +config SND_HDA_CODEC_ALC861VD
> +	tristate "Build Realtek ALC861-VD HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC861-VD HD-audio codec support
> +
> +config SND_HDA_CODEC_ALC880
> +	tristate "Build Realtek ALC880 HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC880 HD-audio codec support
> +
> +config SND_HDA_CODEC_ALC882
> +	tristate "Build Realtek ALC882 HD-audio codecs support"
> +	depends on INPUT
> +	select SND_HDA_CODEC_REALTEK_LIB
> +	help
> +	  Say Y or M here to include Realtek ALC882 and compatible HD-audio
> +	  codec support
> +
> +endif
> +
> +
> diff --git a/sound/hda/codecs/realtek/Makefile b/sound/hda/codecs/realtek/Makefile
> new file mode 100644
> index 000000000000..c6ee4e526a40
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/Makefile
> @@ -0,0 +1,26 @@
> +# SPDX-License-Identifier: GPL-2.0
> +subdir-ccflags-y += -I$(src)/../../common
> +
> +snd-hda-codec-realtek-lib-y :=	realtek.o
> +snd-hda-codec-alc260-y :=	alc260.o
> +snd-hda-codec-alc262-y :=	alc262.o
> +snd-hda-codec-alc268-y :=	alc268.o
> +snd-hda-codec-alc269-y :=	alc269.o
> +snd-hda-codec-alc662-y :=	alc662.o
> +snd-hda-codec-alc680-y :=	alc680.o
> +snd-hda-codec-alc861-y :=	alc861.o
> +snd-hda-codec-alc861vd-y :=	alc861vd.o
> +snd-hda-codec-alc880-y :=	alc880.o
> +snd-hda-codec-alc882-y :=	alc882.o
> +
> +obj-$(CONFIG_SND_HDA_CODEC_REALTEK_LIB) += snd-hda-codec-realtek-lib.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC260) += snd-hda-codec-alc260.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC262) += snd-hda-codec-alc262.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC268) += snd-hda-codec-alc268.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC269) += snd-hda-codec-alc269.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC662) += snd-hda-codec-alc662.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC680) += snd-hda-codec-alc680.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC861) += snd-hda-codec-alc861.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC861VD) += snd-hda-codec-alc861vd.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC880) += snd-hda-codec-alc880.o
> +obj-$(CONFIG_SND_HDA_CODEC_ALC882) += snd-hda-codec-alc882.o
> diff --git a/sound/hda/codecs/realtek/alc260.c b/sound/hda/codecs/realtek/alc260.c
> new file mode 100644
> index 000000000000..ebe20eaec58a
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc260.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC260 codec
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +static int alc260_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
> +	static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
> +	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
> +}
> +
> +/*
> + * Pin config fixes
> + */
> +enum {
> +	ALC260_FIXUP_HP_DC5750,
> +	ALC260_FIXUP_HP_PIN_0F,
> +	ALC260_FIXUP_COEF,
> +	ALC260_FIXUP_GPIO1,
> +	ALC260_FIXUP_GPIO1_TOGGLE,
> +	ALC260_FIXUP_REPLACER,
> +	ALC260_FIXUP_HP_B1900,
> +	ALC260_FIXUP_KN1,
> +	ALC260_FIXUP_FSC_S7020,
> +	ALC260_FIXUP_FSC_S7020_JWSE,
> +	ALC260_FIXUP_VAIO_PINS,
> +};
> +
> +static void alc260_gpio1_automute(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
> +}
> +
> +static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
> +				      const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PROBE) {
> +		/* although the machine has only one output pin, we need to
> +		 * toggle GPIO1 according to the jack state
> +		 */
> +		spec->gen.automute_hook = alc260_gpio1_automute;
> +		spec->gen.detect_hp = 1;
> +		spec->gen.automute_speaker = 1;
> +		spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
> +		snd_hda_jack_detect_enable_callback(codec, 0x0f,
> +						    snd_hda_gen_hp_automute);
> +		alc_setup_gpio(codec, 0x01);
> +	}
> +}
> +
> +static void alc260_fixup_kn1(struct hda_codec *codec,
> +			     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	static const struct hda_pintbl pincfgs[] = {
> +		{ 0x0f, 0x02214000 }, /* HP/speaker */
> +		{ 0x12, 0x90a60160 }, /* int mic */
> +		{ 0x13, 0x02a19000 }, /* ext mic */
> +		{ 0x18, 0x01446000 }, /* SPDIF out */
> +		/* disable bogus I/O pins */
> +		{ 0x10, 0x411111f0 },
> +		{ 0x11, 0x411111f0 },
> +		{ 0x14, 0x411111f0 },
> +		{ 0x15, 0x411111f0 },
> +		{ 0x16, 0x411111f0 },
> +		{ 0x17, 0x411111f0 },
> +		{ 0x19, 0x411111f0 },
> +		{ }
> +	};
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		snd_hda_apply_pincfgs(codec, pincfgs);
> +		spec->init_amp = ALC_INIT_NONE;
> +		break;
> +	}
> +}
> +
> +static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
> +				   const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +		spec->init_amp = ALC_INIT_NONE;
> +}
> +
> +static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
> +				   const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->gen.add_jack_modes = 1;
> +		spec->gen.hp_mic = 1;
> +	}
> +}
> +
> +static const struct hda_fixup alc260_fixups[] = {
> +	[ALC260_FIXUP_HP_DC5750] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x11, 0x90130110 }, /* speaker */
> +			{ }
> +		}
> +	},
> +	[ALC260_FIXUP_HP_PIN_0F] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x0f, 0x01214000 }, /* HP */
> +			{ }
> +		}
> +	},
> +	[ALC260_FIXUP_COEF] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
> +			{ }
> +		},
> +	},
> +	[ALC260_FIXUP_GPIO1] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio1,
> +	},
> +	[ALC260_FIXUP_GPIO1_TOGGLE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc260_fixup_gpio1_toggle,
> +		.chained = true,
> +		.chain_id = ALC260_FIXUP_HP_PIN_0F,
> +	},
> +	[ALC260_FIXUP_REPLACER] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
> +	},
> +	[ALC260_FIXUP_HP_B1900] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc260_fixup_gpio1_toggle,
> +		.chained = true,
> +		.chain_id = ALC260_FIXUP_COEF,
> +	},
> +	[ALC260_FIXUP_KN1] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc260_fixup_kn1,
> +	},
> +	[ALC260_FIXUP_FSC_S7020] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc260_fixup_fsc_s7020,
> +	},
> +	[ALC260_FIXUP_FSC_S7020_JWSE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc260_fixup_fsc_s7020_jwse,
> +		.chained = true,
> +		.chain_id = ALC260_FIXUP_FSC_S7020,
> +	},
> +	[ALC260_FIXUP_VAIO_PINS] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			/* Pin configs are missing completely on some VAIOs */
> +			{ 0x0f, 0x01211020 },
> +			{ 0x10, 0x0001003f },
> +			{ 0x11, 0x411111f0 },
> +			{ 0x12, 0x01a15930 },
> +			{ 0x13, 0x411111f0 },
> +			{ 0x14, 0x411111f0 },
> +			{ 0x15, 0x411111f0 },
> +			{ 0x16, 0x411111f0 },
> +			{ 0x17, 0x411111f0 },
> +			{ 0x18, 0x411111f0 },
> +			{ 0x19, 0x411111f0 },
> +			{ }
> +		}
> +	},
> +};
> +
> +static const struct hda_quirk alc260_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
> +	SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
> +	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
> +	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
> +	SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
> +	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
> +	SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
> +	SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
> +	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
> +	SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
> +	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
> +	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
> +	{}
> +};
> +
> +static const struct hda_model_fixup alc260_fixup_models[] = {
> +	{.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
> +	{.id = ALC260_FIXUP_COEF, .name = "coef"},
> +	{.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
> +	{.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
> +	{}
> +};
> +
> +/*
> + */
> +static int patch_alc260(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x07);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +	/* as quite a few machines require HP amp for speaker outputs,
> +	 * it's easier to enable it unconditionally; even if it's unneeded,
> +	 * it's almost harmless.
> +	 */
> +	spec->gen.prefer_hp_amp = 1;
> +	spec->gen.beep_nid = 0x01;
> +
> +	spec->shutup = alc_eapd_shutup;
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
> +			   alc260_fixups);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc260_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog) {
> +		err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc260[] = {
> +	HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc260);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC260 HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc260_driver = {
> +	.id = snd_hda_id_alc260,
> +};
> +
> +module_hda_codec_driver(alc260_driver);
> diff --git a/sound/hda/codecs/realtek/alc262.c b/sound/hda/codecs/realtek/alc262.c
> new file mode 100644
> index 000000000000..ffe61f447667
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc262.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC262 codec
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +static int alc262_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
> +	static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> +	return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
> +}
> +
> +/*
> + * Pin config fixes
> + */
> +enum {
> +	ALC262_FIXUP_FSC_H270,
> +	ALC262_FIXUP_FSC_S7110,
> +	ALC262_FIXUP_HP_Z200,
> +	ALC262_FIXUP_TYAN,
> +	ALC262_FIXUP_LENOVO_3000,
> +	ALC262_FIXUP_BENQ,
> +	ALC262_FIXUP_BENQ_T31,
> +	ALC262_FIXUP_INV_DMIC,
> +	ALC262_FIXUP_INTEL_BAYLEYBAY,
> +};
> +
> +static const struct hda_fixup alc262_fixups[] = {
> +	[ALC262_FIXUP_FSC_H270] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x15, 0x0221142f }, /* front HP */
> +			{ 0x1b, 0x0121141f }, /* rear HP */
> +			{ }
> +		}
> +	},
> +	[ALC262_FIXUP_FSC_S7110] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x90170110 }, /* speaker */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC262_FIXUP_BENQ,
> +	},
> +	[ALC262_FIXUP_HP_Z200] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x16, 0x99130120 }, /* internal speaker */
> +			{ }
> +		}
> +	},
> +	[ALC262_FIXUP_TYAN] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x1993e1f0 }, /* int AUX */
> +			{ }
> +		}
> +	},
> +	[ALC262_FIXUP_LENOVO_3000] = {
> +		.type = HDA_FIXUP_PINCTLS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, PIN_VREF50 },
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC262_FIXUP_BENQ,
> +	},
> +	[ALC262_FIXUP_BENQ] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
> +			{}
> +		}
> +	},
> +	[ALC262_FIXUP_BENQ_T31] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
> +			{}
> +		}
> +	},
> +	[ALC262_FIXUP_INV_DMIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_inv_dmic,
> +	},
> +	[ALC262_FIXUP_INTEL_BAYLEYBAY] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_no_depop_delay,
> +	},
> +};
> +
> +static const struct hda_quirk alc262_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
> +	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
> +	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
> +	SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
> +	SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
> +	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
> +	SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
> +	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
> +	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
> +	SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
> +	{}
> +};
> +
> +static const struct hda_model_fixup alc262_fixup_models[] = {
> +	{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
> +	{.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
> +	{.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
> +	{.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
> +	{.id = ALC262_FIXUP_TYAN, .name = "tyan"},
> +	{.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
> +	{.id = ALC262_FIXUP_BENQ, .name = "benq"},
> +	{.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
> +	{.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
> +	{}
> +};
> +
> +/*
> + */
> +static int patch_alc262(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x0b);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +	spec->gen.shared_mic_vref_pin = 0x18;
> +
> +	spec->shutup = alc_eapd_shutup;
> +
> +#if 0
> +	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
> +	 * under-run
> +	 */
> +	alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
> +#endif
> +	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
> +		       alc262_fixups);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	alc_auto_parse_customize_define(codec);
> +
> +	if (has_cdefine_beep(codec))
> +		spec->gen.beep_nid = 0x01;
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc262_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog && spec->gen.beep_nid) {
> +		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc262[] = {
> +	HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc262);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC262 HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc262_driver = {
> +	.id = snd_hda_id_alc262,
> +};
> +
> +module_hda_codec_driver(alc262_driver);
> diff --git a/sound/hda/codecs/realtek/alc268.c b/sound/hda/codecs/realtek/alc268.c
> new file mode 100644
> index 000000000000..d018f9982feb
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc268.c
> @@ -0,0 +1,176 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +/* bind Beep switches of both NID 0x0f and 0x10 */
> +static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
> +				  struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
> +	unsigned long pval;
> +	int err;
> +
> +	mutex_lock(&codec->control_mutex);
> +	pval = kcontrol->private_value;
> +	kcontrol->private_value = (pval & ~0xff) | 0x0f;
> +	err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
> +	if (err >= 0) {
> +		kcontrol->private_value = (pval & ~0xff) | 0x10;
> +		err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
> +	}
> +	kcontrol->private_value = pval;
> +	mutex_unlock(&codec->control_mutex);
> +	return err;
> +}
> +
> +static const struct snd_kcontrol_new alc268_beep_mixer[] = {
> +	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
> +	{
> +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
> +		.name = "Beep Playback Switch",
> +		.subdevice = HDA_SUBDEV_AMP_FLAG,
> +		.info = snd_hda_mixer_amp_switch_info,
> +		.get = snd_hda_mixer_amp_switch_get,
> +		.put = alc268_beep_switch_put,
> +		.private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
> +	},
> +};
> +
> +/* set PCBEEP vol = 0, mute connections */
> +static const struct hda_verb alc268_beep_init_verbs[] = {
> +	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
> +	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
> +	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
> +	{ }
> +};
> +
> +enum {
> +	ALC268_FIXUP_INV_DMIC,
> +	ALC268_FIXUP_HP_EAPD,
> +	ALC268_FIXUP_SPDIF,
> +};
> +
> +static const struct hda_fixup alc268_fixups[] = {
> +	[ALC268_FIXUP_INV_DMIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_inv_dmic,
> +	},
> +	[ALC268_FIXUP_HP_EAPD] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
> +			{}
> +		}
> +	},
> +	[ALC268_FIXUP_SPDIF] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x014b1180 }, /* enable SPDIF out */
> +			{}
> +		}
> +	},
> +};
> +
> +static const struct hda_model_fixup alc268_fixup_models[] = {
> +	{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
> +	{.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
> +	{.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
> +	{}
> +};
> +
> +static const struct hda_quirk alc268_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
> +	SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
> +	/* below is codec SSID since multiple Toshiba laptops have the
> +	 * same PCI SSID 1179:ff00
> +	 */
> +	SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
> +	{}
> +};
> +
> +/*
> + * BIOS auto configuration
> + */
> +static int alc268_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> +	return alc_parse_auto_config(codec, NULL, alc268_ssids);
> +}
> +
> +/*
> + */
> +static int patch_alc268(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int i, err;
> +
> +	/* ALC268 has no aa-loopback mixer */
> +	err = alc_alloc_spec(codec, 0);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +	if (has_cdefine_beep(codec))
> +		spec->gen.beep_nid = 0x01;
> +
> +	spec->shutup = alc_eapd_shutup;
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc268_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (err > 0 && !spec->gen.no_analog &&
> +	    spec->gen.autocfg.speaker_pins[0] != 0x1d) {
> +		for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
> +			if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
> +						  &alc268_beep_mixer[i])) {
> +				err = -ENOMEM;
> +				goto error;
> +			}
> +		}
> +		snd_hda_add_verbs(codec, alc268_beep_init_verbs);
> +		if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
> +			/* override the amp caps for beep generator */
> +			snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
> +					  (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
> +					  (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
> +					  (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
> +					  (0 << AC_AMPCAP_MUTE_SHIFT));
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc268[] = {
> +	HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
> +	HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc268);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC267/268 HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc268_driver = {
> +	.id = snd_hda_id_alc268,
> +};
> +
> +module_hda_codec_driver(alc268_driver);
> diff --git a/sound/hda/codecs/realtek.c b/sound/hda/codecs/realtek/alc269.c
> similarity index 64%
> rename from sound/hda/codecs/realtek.c
> rename to sound/hda/codecs/realtek/alc269.c
> index 9c86c7bd1a90..325ba08e2981 100644
> --- a/sound/hda/codecs/realtek.c
> +++ b/sound/hda/codecs/realtek/alc269.c
> @@ -1,3160 +1,15 @@
>   // SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - * Universal Interface for Intel High Definition Audio Codec
> - *
> - * HD audio interface patch for Realtek ALC codecs
> - *
> - * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
> - *                    PeiSen Hou <pshou@realtek.com.tw>
> - *                    Takashi Iwai <tiwai@suse.de>
> - *                    Jonathan Woithe <jwoithe@just42.net>
> - */
> +//
> +// Realtek ALC269 and compatible codecs
> +//
>   
> -#include <linux/acpi.h>
> -#include <linux/cleanup.h>
>   #include <linux/init.h>
> -#include <linux/delay.h>
> -#include <linux/slab.h>
> -#include <linux/pci.h>
> -#include <linux/dmi.h>
>   #include <linux/module.h>
> -#include <linux/i2c.h>
> -#include <linux/input.h>
> -#include <linux/leds.h>
> -#include <linux/ctype.h>
> -#include <linux/spi/spi.h>
> -#include <sound/core.h>
> -#include <sound/jack.h>
> -#include <sound/hda_codec.h>
> -#include "hda_local.h"
> -#include "hda_auto_parser.h"
> -#include "hda_beep.h"
> -#include "hda_jack.h"
> -#include "generic.h"
> -#include "side-codecs/hda_component.h"
> +#include "realtek.h"
>   
>   /* keep halting ALC5505 DSP, for power saving */
>   #define HALT_REALTEK_ALC5505
>   
> -/* extra amp-initialization sequence types */
> -enum {
> -	ALC_INIT_UNDEFINED,
> -	ALC_INIT_NONE,
> -	ALC_INIT_DEFAULT,
> -};
> -
> -enum {
> -	ALC_HEADSET_MODE_UNKNOWN,
> -	ALC_HEADSET_MODE_UNPLUGGED,
> -	ALC_HEADSET_MODE_HEADSET,
> -	ALC_HEADSET_MODE_MIC,
> -	ALC_HEADSET_MODE_HEADPHONE,
> -};
> -
> -enum {
> -	ALC_HEADSET_TYPE_UNKNOWN,
> -	ALC_HEADSET_TYPE_CTIA,
> -	ALC_HEADSET_TYPE_OMTP,
> -};
> -
> -enum {
> -	ALC_KEY_MICMUTE_INDEX,
> -};
> -
> -struct alc_customize_define {
> -	unsigned int  sku_cfg;
> -	unsigned char port_connectivity;
> -	unsigned char check_sum;
> -	unsigned char customization;
> -	unsigned char external_amp;
> -	unsigned int  enable_pcbeep:1;
> -	unsigned int  platform_type:1;
> -	unsigned int  swap:1;
> -	unsigned int  override:1;
> -	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
> -};
> -
> -struct alc_coef_led {
> -	unsigned int idx;
> -	unsigned int mask;
> -	unsigned int on;
> -	unsigned int off;
> -};
> -
> -struct alc_spec {
> -	struct hda_gen_spec gen; /* must be at head */
> -
> -	/* codec parameterization */
> -	struct alc_customize_define cdefine;
> -	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
> -
> -	/* GPIO bits */
> -	unsigned int gpio_mask;
> -	unsigned int gpio_dir;
> -	unsigned int gpio_data;
> -	bool gpio_write_delay;	/* add a delay before writing gpio_data */
> -
> -	/* mute LED for HP laptops, see vref_mute_led_set() */
> -	int mute_led_polarity;
> -	int micmute_led_polarity;
> -	hda_nid_t mute_led_nid;
> -	hda_nid_t cap_mute_led_nid;
> -
> -	unsigned int gpio_mute_led_mask;
> -	unsigned int gpio_mic_led_mask;
> -	struct alc_coef_led mute_led_coef;
> -	struct alc_coef_led mic_led_coef;
> -	struct mutex coef_mutex;
> -
> -	hda_nid_t headset_mic_pin;
> -	hda_nid_t headphone_mic_pin;
> -	int current_headset_mode;
> -	int current_headset_type;
> -
> -	/* hooks */
> -	void (*init_hook)(struct hda_codec *codec);
> -	void (*power_hook)(struct hda_codec *codec);
> -	void (*shutup)(struct hda_codec *codec);
> -
> -	int init_amp;
> -	int codec_variant;	/* flag for other variants */
> -	unsigned int has_alc5505_dsp:1;
> -	unsigned int no_depop_delay:1;
> -	unsigned int done_hp_init:1;
> -	unsigned int no_shutup_pins:1;
> -	unsigned int ultra_low_power:1;
> -	unsigned int has_hs_key:1;
> -	unsigned int no_internal_mic_pin:1;
> -	unsigned int en_3kpull_low:1;
> -	int num_speaker_amps;
> -
> -	/* for PLL fix */
> -	hda_nid_t pll_nid;
> -	unsigned int pll_coef_idx, pll_coef_bit;
> -	unsigned int coef0;
> -	struct input_dev *kb_dev;
> -	u8 alc_mute_keycode_map[1];
> -
> -	/* component binding */
> -	struct hda_component_parent comps;
> -};
> -
> -/*
> - * COEF access helper functions
> - */
> -
> -static void coef_mutex_lock(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	snd_hda_power_up_pm(codec);
> -	mutex_lock(&spec->coef_mutex);
> -}
> -
> -static void coef_mutex_unlock(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	mutex_unlock(&spec->coef_mutex);
> -	snd_hda_power_down_pm(codec);
> -}
> -
> -static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> -				 unsigned int coef_idx)
> -{
> -	unsigned int val;
> -
> -	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
> -	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
> -	return val;
> -}
> -
> -static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> -			       unsigned int coef_idx)
> -{
> -	unsigned int val;
> -
> -	coef_mutex_lock(codec);
> -	val = __alc_read_coefex_idx(codec, nid, coef_idx);
> -	coef_mutex_unlock(codec);
> -	return val;
> -}
> -
> -#define alc_read_coef_idx(codec, coef_idx) \
> -	alc_read_coefex_idx(codec, 0x20, coef_idx)
> -
> -static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> -				   unsigned int coef_idx, unsigned int coef_val)
> -{
> -	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
> -	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
> -}
> -
> -static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> -				 unsigned int coef_idx, unsigned int coef_val)
> -{
> -	coef_mutex_lock(codec);
> -	__alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
> -	coef_mutex_unlock(codec);
> -}
> -
> -#define alc_write_coef_idx(codec, coef_idx, coef_val) \
> -	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
> -
> -static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> -				    unsigned int coef_idx, unsigned int mask,
> -				    unsigned int bits_set)
> -{
> -	unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
> -
> -	if (val != -1)
> -		__alc_write_coefex_idx(codec, nid, coef_idx,
> -				       (val & ~mask) | bits_set);
> -}
> -
> -static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> -				  unsigned int coef_idx, unsigned int mask,
> -				  unsigned int bits_set)
> -{
> -	coef_mutex_lock(codec);
> -	__alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
> -	coef_mutex_unlock(codec);
> -}
> -
> -#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)	\
> -	alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
> -
> -/* a special bypass for COEF 0; read the cached value at the second time */
> -static unsigned int alc_get_coef0(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (!spec->coef0)
> -		spec->coef0 = alc_read_coef_idx(codec, 0);
> -	return spec->coef0;
> -}
> -
> -/* coef writes/updates batch */
> -struct coef_fw {
> -	unsigned char nid;
> -	unsigned char idx;
> -	unsigned short mask;
> -	unsigned short val;
> -};
> -
> -#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
> -	{ .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
> -#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
> -#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
> -#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
> -
> -static void alc_process_coef_fw(struct hda_codec *codec,
> -				const struct coef_fw *fw)
> -{
> -	coef_mutex_lock(codec);
> -	for (; fw->nid; fw++) {
> -		if (fw->mask == (unsigned short)-1)
> -			__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
> -		else
> -			__alc_update_coefex_idx(codec, fw->nid, fw->idx,
> -						fw->mask, fw->val);
> -	}
> -	coef_mutex_unlock(codec);
> -}
> -
> -/*
> - * GPIO setup tables, used in initialization
> - */
> -
> -/* Enable GPIO mask and set output */
> -static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	spec->gpio_mask |= mask;
> -	spec->gpio_dir |= mask;
> -	spec->gpio_data |= mask;
> -}
> -
> -static void alc_write_gpio_data(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
> -			    spec->gpio_data);
> -}
> -
> -static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
> -				 bool on)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	unsigned int oldval = spec->gpio_data;
> -
> -	if (on)
> -		spec->gpio_data |= mask;
> -	else
> -		spec->gpio_data &= ~mask;
> -	if (oldval != spec->gpio_data)
> -		alc_write_gpio_data(codec);
> -}
> -
> -static void alc_write_gpio(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (!spec->gpio_mask)
> -		return;
> -
> -	snd_hda_codec_write(codec, codec->core.afg, 0,
> -			    AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
> -	snd_hda_codec_write(codec, codec->core.afg, 0,
> -			    AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
> -	if (spec->gpio_write_delay)
> -		msleep(1);
> -	alc_write_gpio_data(codec);
> -}
> -
> -static void alc_fixup_gpio(struct hda_codec *codec, int action,
> -			   unsigned int mask)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> -		alc_setup_gpio(codec, mask);
> -}
> -
> -static void alc_fixup_gpio1(struct hda_codec *codec,
> -			    const struct hda_fixup *fix, int action)
> -{
> -	alc_fixup_gpio(codec, action, 0x01);
> -}
> -
> -static void alc_fixup_gpio2(struct hda_codec *codec,
> -			    const struct hda_fixup *fix, int action)
> -{
> -	alc_fixup_gpio(codec, action, 0x02);
> -}
> -
> -static void alc_fixup_gpio3(struct hda_codec *codec,
> -			    const struct hda_fixup *fix, int action)
> -{
> -	alc_fixup_gpio(codec, action, 0x03);
> -}
> -
> -static void alc_fixup_gpio4(struct hda_codec *codec,
> -			    const struct hda_fixup *fix, int action)
> -{
> -	alc_fixup_gpio(codec, action, 0x04);
> -}
> -
> -static void alc_fixup_micmute_led(struct hda_codec *codec,
> -				  const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> -		snd_hda_gen_add_micmute_led_cdev(codec, NULL);
> -}
> -
> -/*
> - * Fix hardware PLL issue
> - * On some codecs, the analog PLL gating control must be off while
> - * the default value is 1.
> - */
> -static void alc_fix_pll(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (spec->pll_nid)
> -		alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
> -				      1 << spec->pll_coef_bit, 0);
> -}
> -
> -static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
> -			     unsigned int coef_idx, unsigned int coef_bit)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	spec->pll_nid = nid;
> -	spec->pll_coef_idx = coef_idx;
> -	spec->pll_coef_bit = coef_bit;
> -	alc_fix_pll(codec);
> -}
> -
> -/* update the master volume per volume-knob's unsol event */
> -static void alc_update_knob_master(struct hda_codec *codec,
> -				   struct hda_jack_callback *jack)
> -{
> -	unsigned int val;
> -	struct snd_kcontrol *kctl;
> -	struct snd_ctl_elem_value *uctl;
> -
> -	kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
> -	if (!kctl)
> -		return;
> -	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
> -	if (!uctl)
> -		return;
> -	val = snd_hda_codec_read(codec, jack->nid, 0,
> -				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
> -	val &= HDA_AMP_VOLMASK;
> -	uctl->value.integer.value[0] = val;
> -	uctl->value.integer.value[1] = val;
> -	kctl->put(kctl, uctl);
> -	kfree(uctl);
> -}
> -
> -static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
> -{
> -	/* For some reason, the res given from ALC880 is broken.
> -	   Here we adjust it properly. */
> -	snd_hda_jack_unsol_event(codec, res >> 2);
> -}
> -
> -/* Change EAPD to verb control */
> -static void alc_fill_eapd_coef(struct hda_codec *codec)
> -{
> -	int coef;
> -
> -	coef = alc_get_coef0(codec);
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0262:
> -		alc_update_coef_idx(codec, 0x7, 0, 1<<5);
> -		break;
> -	case 0x10ec0267:
> -	case 0x10ec0268:
> -		alc_update_coef_idx(codec, 0x7, 0, 1<<13);
> -		break;
> -	case 0x10ec0269:
> -		if ((coef & 0x00f0) == 0x0010)
> -			alc_update_coef_idx(codec, 0xd, 0, 1<<14);
> -		if ((coef & 0x00f0) == 0x0020)
> -			alc_update_coef_idx(codec, 0x4, 1<<15, 0);
> -		if ((coef & 0x00f0) == 0x0030)
> -			alc_update_coef_idx(codec, 0x10, 1<<9, 0);
> -		break;
> -	case 0x10ec0280:
> -	case 0x10ec0284:
> -	case 0x10ec0290:
> -	case 0x10ec0292:
> -		alc_update_coef_idx(codec, 0x4, 1<<15, 0);
> -		break;
> -	case 0x10ec0225:
> -	case 0x10ec0295:
> -	case 0x10ec0299:
> -		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
> -		fallthrough;
> -	case 0x10ec0215:
> -	case 0x10ec0236:
> -	case 0x10ec0245:
> -	case 0x10ec0256:
> -	case 0x10ec0257:
> -	case 0x10ec0285:
> -	case 0x10ec0289:
> -		alc_update_coef_idx(codec, 0x36, 1<<13, 0);
> -		fallthrough;
> -	case 0x10ec0230:
> -	case 0x10ec0233:
> -	case 0x10ec0235:
> -	case 0x10ec0255:
> -	case 0x19e58326:
> -	case 0x10ec0282:
> -	case 0x10ec0283:
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -	case 0x10ec0298:
> -	case 0x10ec0300:
> -		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
> -		break;
> -	case 0x10ec0275:
> -		alc_update_coef_idx(codec, 0xe, 0, 1<<0);
> -		break;
> -	case 0x10ec0287:
> -		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
> -		alc_write_coef_idx(codec, 0x8, 0x4ab7);
> -		break;
> -	case 0x10ec0293:
> -		alc_update_coef_idx(codec, 0xa, 1<<13, 0);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -		alc_write_coef_idx(codec, 0x6e, 0x0c25);
> -		fallthrough;
> -	case 0x10ec0294:
> -	case 0x10ec0700:
> -	case 0x10ec0701:
> -	case 0x10ec0703:
> -	case 0x10ec0711:
> -		alc_update_coef_idx(codec, 0x10, 1<<15, 0);
> -		break;
> -	case 0x10ec0662:
> -		if ((coef & 0x00f0) == 0x0030)
> -			alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
> -		break;
> -	case 0x10ec0272:
> -	case 0x10ec0273:
> -	case 0x10ec0663:
> -	case 0x10ec0665:
> -	case 0x10ec0670:
> -	case 0x10ec0671:
> -	case 0x10ec0672:
> -		alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
> -		break;
> -	case 0x10ec0222:
> -	case 0x10ec0623:
> -		alc_update_coef_idx(codec, 0x19, 1<<13, 0);
> -		break;
> -	case 0x10ec0668:
> -		alc_update_coef_idx(codec, 0x7, 3<<13, 0);
> -		break;
> -	case 0x10ec0867:
> -		alc_update_coef_idx(codec, 0x4, 1<<10, 0);
> -		break;
> -	case 0x10ec0888:
> -		if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
> -			alc_update_coef_idx(codec, 0x7, 1<<5, 0);
> -		break;
> -	case 0x10ec0892:
> -	case 0x10ec0897:
> -		alc_update_coef_idx(codec, 0x7, 1<<5, 0);
> -		break;
> -	case 0x10ec0899:
> -	case 0x10ec0900:
> -	case 0x10ec0b00:
> -	case 0x10ec1168:
> -	case 0x10ec1220:
> -		alc_update_coef_idx(codec, 0x7, 1<<1, 0);
> -		break;
> -	}
> -}
> -
> -/* additional initialization for ALC888 variants */
> -static void alc888_coef_init(struct hda_codec *codec)
> -{
> -	switch (alc_get_coef0(codec) & 0x00f0) {
> -	/* alc888-VA */
> -	case 0x00:
> -	/* alc888-VB */
> -	case 0x10:
> -		alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
> -		break;
> -	}
> -}
> -
> -/* turn on/off EAPD control (only if available) */
> -static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
> -{
> -	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
> -		return;
> -	if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
> -		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
> -				    on ? 2 : 0);
> -}
> -
> -/* turn on/off EAPD controls of the codec */
> -static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
> -{
> -	/* We currently only handle front, HP */
> -	static const hda_nid_t pins[] = {
> -		0x0f, 0x10, 0x14, 0x15, 0x17, 0
> -	};
> -	const hda_nid_t *p;
> -	for (p = pins; *p; p++)
> -		set_eapd(codec, *p, on);
> -}
> -
> -static int find_ext_mic_pin(struct hda_codec *codec);
> -
> -static void alc_headset_mic_no_shutup(struct hda_codec *codec)
> -{
> -	const struct hda_pincfg *pin;
> -	int mic_pin = find_ext_mic_pin(codec);
> -	int i;
> -
> -	/* don't shut up pins when unloading the driver; otherwise it breaks
> -	 * the default pin setup at the next load of the driver
> -	 */
> -	if (codec->bus->shutdown)
> -		return;
> -
> -	snd_array_for_each(&codec->init_pins, i, pin) {
> -		/* use read here for syncing after issuing each verb */
> -		if (pin->nid != mic_pin)
> -			snd_hda_codec_read(codec, pin->nid, 0,
> -					AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
> -	}
> -
> -	codec->pins_shutup = 1;
> -}
> -
> -static void alc_shutup_pins(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (spec->no_shutup_pins)
> -		return;
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x10ec0257:
> -	case 0x19e58326:
> -	case 0x10ec0283:
> -	case 0x10ec0285:
> -	case 0x10ec0286:
> -	case 0x10ec0287:
> -	case 0x10ec0288:
> -	case 0x10ec0295:
> -	case 0x10ec0298:
> -		alc_headset_mic_no_shutup(codec);
> -		break;
> -	default:
> -		snd_hda_shutup_pins(codec);
> -		break;
> -	}
> -}
> -
> -/* generic shutup callback;
> - * just turning off EAPD and a little pause for avoiding pop-noise
> - */
> -static void alc_eapd_shutup(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	alc_auto_setup_eapd(codec, false);
> -	if (!spec->no_depop_delay)
> -		msleep(200);
> -	alc_shutup_pins(codec);
> -}
> -
> -/* generic EAPD initialization */
> -static void alc_auto_init_amp(struct hda_codec *codec, int type)
> -{
> -	alc_auto_setup_eapd(codec, true);
> -	alc_write_gpio(codec);
> -	switch (type) {
> -	case ALC_INIT_DEFAULT:
> -		switch (codec->core.vendor_id) {
> -		case 0x10ec0260:
> -			alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
> -			break;
> -		case 0x10ec0880:
> -		case 0x10ec0882:
> -		case 0x10ec0883:
> -		case 0x10ec0885:
> -			alc_update_coef_idx(codec, 7, 0, 0x2030);
> -			break;
> -		case 0x10ec0888:
> -			alc888_coef_init(codec);
> -			break;
> -		}
> -		break;
> -	}
> -}
> -
> -/* get a primary headphone pin if available */
> -static hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
> -{
> -	if (spec->gen.autocfg.hp_pins[0])
> -		return spec->gen.autocfg.hp_pins[0];
> -	if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
> -		return spec->gen.autocfg.line_out_pins[0];
> -	return 0;
> -}
> -
> -/*
> - * Realtek SSID verification
> - */
> -
> -/* Could be any non-zero and even value. When used as fixup, tells
> - * the driver to ignore any present sku defines.
> - */
> -#define ALC_FIXUP_SKU_IGNORE (2)
> -
> -static void alc_fixup_sku_ignore(struct hda_codec *codec,
> -				 const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->cdefine.fixup = 1;
> -		spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
> -	}
> -}
> -
> -static void alc_fixup_no_depop_delay(struct hda_codec *codec,
> -				    const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (action == HDA_FIXUP_ACT_PROBE) {
> -		spec->no_depop_delay = 1;
> -		codec->depop_delay = 0;
> -	}
> -}
> -
> -static int alc_auto_parse_customize_define(struct hda_codec *codec)
> -{
> -	unsigned int ass, tmp, i;
> -	unsigned nid = 0;
> -	struct alc_spec *spec = codec->spec;
> -
> -	spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
> -
> -	if (spec->cdefine.fixup) {
> -		ass = spec->cdefine.sku_cfg;
> -		if (ass == ALC_FIXUP_SKU_IGNORE)
> -			return -1;
> -		goto do_sku;
> -	}
> -
> -	if (!codec->bus->pci)
> -		return -1;
> -	ass = codec->core.subsystem_id & 0xffff;
> -	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
> -		goto do_sku;
> -
> -	nid = 0x1d;
> -	if (codec->core.vendor_id == 0x10ec0260)
> -		nid = 0x17;
> -	ass = snd_hda_codec_get_pincfg(codec, nid);
> -
> -	if (!(ass & 1)) {
> -		codec_info(codec, "%s: SKU not ready 0x%08x\n",
> -			   codec->core.chip_name, ass);
> -		return -1;
> -	}
> -
> -	/* check sum */
> -	tmp = 0;
> -	for (i = 1; i < 16; i++) {
> -		if ((ass >> i) & 1)
> -			tmp++;
> -	}
> -	if (((ass >> 16) & 0xf) != tmp)
> -		return -1;
> -
> -	spec->cdefine.port_connectivity = ass >> 30;
> -	spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
> -	spec->cdefine.check_sum = (ass >> 16) & 0xf;
> -	spec->cdefine.customization = ass >> 8;
> -do_sku:
> -	spec->cdefine.sku_cfg = ass;
> -	spec->cdefine.external_amp = (ass & 0x38) >> 3;
> -	spec->cdefine.platform_type = (ass & 0x4) >> 2;
> -	spec->cdefine.swap = (ass & 0x2) >> 1;
> -	spec->cdefine.override = ass & 0x1;
> -
> -	codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
> -		   nid, spec->cdefine.sku_cfg);
> -	codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
> -		   spec->cdefine.port_connectivity);
> -	codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
> -	codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
> -	codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
> -	codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
> -	codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
> -	codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
> -	codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
> -
> -	return 0;
> -}
> -
> -/* return the position of NID in the list, or -1 if not found */
> -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
> -{
> -	int i;
> -	for (i = 0; i < nums; i++)
> -		if (list[i] == nid)
> -			return i;
> -	return -1;
> -}
> -/* return true if the given NID is found in the list */
> -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
> -{
> -	return find_idx_in_nid_list(nid, list, nums) >= 0;
> -}
> -
> -/* check subsystem ID and set up device-specific initialization;
> - * return 1 if initialized, 0 if invalid SSID
> - */
> -/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
> - *	31 ~ 16 :	Manufacture ID
> - *	15 ~ 8	:	SKU ID
> - *	7  ~ 0	:	Assembly ID
> - *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
> - */
> -static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
> -{
> -	unsigned int ass, tmp, i;
> -	unsigned nid;
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (spec->cdefine.fixup) {
> -		ass = spec->cdefine.sku_cfg;
> -		if (ass == ALC_FIXUP_SKU_IGNORE)
> -			return 0;
> -		goto do_sku;
> -	}
> -
> -	ass = codec->core.subsystem_id & 0xffff;
> -	if (codec->bus->pci &&
> -	    ass != codec->bus->pci->subsystem_device && (ass & 1))
> -		goto do_sku;
> -
> -	/* invalid SSID, check the special NID pin defcfg instead */
> -	/*
> -	 * 31~30	: port connectivity
> -	 * 29~21	: reserve
> -	 * 20		: PCBEEP input
> -	 * 19~16	: Check sum (15:1)
> -	 * 15~1		: Custom
> -	 * 0		: override
> -	*/
> -	nid = 0x1d;
> -	if (codec->core.vendor_id == 0x10ec0260)
> -		nid = 0x17;
> -	ass = snd_hda_codec_get_pincfg(codec, nid);
> -	codec_dbg(codec,
> -		  "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
> -		   ass, nid);
> -	if (!(ass & 1))
> -		return 0;
> -	if ((ass >> 30) != 1)	/* no physical connection */
> -		return 0;
> -
> -	/* check sum */
> -	tmp = 0;
> -	for (i = 1; i < 16; i++) {
> -		if ((ass >> i) & 1)
> -			tmp++;
> -	}
> -	if (((ass >> 16) & 0xf) != tmp)
> -		return 0;
> -do_sku:
> -	codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
> -		   ass & 0xffff, codec->core.vendor_id);
> -	/*
> -	 * 0 : override
> -	 * 1 :	Swap Jack
> -	 * 2 : 0 --> Desktop, 1 --> Laptop
> -	 * 3~5 : External Amplifier control
> -	 * 7~6 : Reserved
> -	*/
> -	tmp = (ass & 0x38) >> 3;	/* external Amp control */
> -	if (spec->init_amp == ALC_INIT_UNDEFINED) {
> -		switch (tmp) {
> -		case 1:
> -			alc_setup_gpio(codec, 0x01);
> -			break;
> -		case 3:
> -			alc_setup_gpio(codec, 0x02);
> -			break;
> -		case 7:
> -			alc_setup_gpio(codec, 0x04);
> -			break;
> -		case 5:
> -		default:
> -			spec->init_amp = ALC_INIT_DEFAULT;
> -			break;
> -		}
> -	}
> -
> -	/* is laptop or Desktop and enable the function "Mute internal speaker
> -	 * when the external headphone out jack is plugged"
> -	 */
> -	if (!(ass & 0x8000))
> -		return 1;
> -	/*
> -	 * 10~8 : Jack location
> -	 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
> -	 * 14~13: Resvered
> -	 * 15   : 1 --> enable the function "Mute internal speaker
> -	 *	        when the external headphone out jack is plugged"
> -	 */
> -	if (!alc_get_hp_pin(spec)) {
> -		hda_nid_t nid;
> -		tmp = (ass >> 11) & 0x3;	/* HP to chassis */
> -		nid = ports[tmp];
> -		if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
> -				      spec->gen.autocfg.line_outs))
> -			return 1;
> -		spec->gen.autocfg.hp_pins[0] = nid;
> -	}
> -	return 1;
> -}
> -
> -/* Check the validity of ALC subsystem-id
> - * ports contains an array of 4 pin NIDs for port-A, E, D and I */
> -static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
> -{
> -	if (!alc_subsystem_id(codec, ports)) {
> -		struct alc_spec *spec = codec->spec;
> -		if (spec->init_amp == ALC_INIT_UNDEFINED) {
> -			codec_dbg(codec,
> -				  "realtek: Enable default setup for auto mode as fallback\n");
> -			spec->init_amp = ALC_INIT_DEFAULT;
> -		}
> -	}
> -}
> -
> -/* inverted digital-mic */
> -static void alc_fixup_inv_dmic(struct hda_codec *codec,
> -			       const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	spec->gen.inv_dmic_split = 1;
> -}
> -
> -
> -static int alc_build_controls(struct hda_codec *codec)
> -{
> -	int err;
> -
> -	err = snd_hda_gen_build_controls(codec);
> -	if (err < 0)
> -		return err;
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
> -	return 0;
> -}
> -
> -
> -/*
> - * Common callbacks
> - */
> -
> -static void alc_pre_init(struct hda_codec *codec)
> -{
> -	alc_fill_eapd_coef(codec);
> -}
> -
> -#define is_s3_resume(codec) \
> -	((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
> -#define is_s4_resume(codec) \
> -	((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
> -#define is_s4_suspend(codec) \
> -	((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
> -
> -static int alc_init(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	/* hibernation resume needs the full chip initialization */
> -	if (is_s4_resume(codec))
> -		alc_pre_init(codec);
> -
> -	if (spec->init_hook)
> -		spec->init_hook(codec);
> -
> -	spec->gen.skip_verbs = 1; /* applied in below */
> -	snd_hda_gen_init(codec);
> -	alc_fix_pll(codec);
> -	alc_auto_init_amp(codec, spec->init_amp);
> -	snd_hda_apply_verbs(codec); /* apply verbs here after own init */
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
> -
> -	return 0;
> -}
> -
> -/* forward declaration */
> -static const struct component_master_ops comp_master_ops;
> -
> -static void alc_free(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (spec)
> -		hda_component_manager_free(&spec->comps, &comp_master_ops);
> -
> -	snd_hda_gen_free(codec);
> -}
> -
> -static inline void alc_shutup(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (!snd_hda_get_bool_hint(codec, "shutup"))
> -		return; /* disabled explicitly by hints */
> -
> -	if (spec && spec->shutup)
> -		spec->shutup(codec);
> -	else
> -		alc_shutup_pins(codec);
> -}
> -
> -static void alc_power_eapd(struct hda_codec *codec)
> -{
> -	alc_auto_setup_eapd(codec, false);
> -}
> -
> -static int alc_suspend(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	alc_shutup(codec);
> -	if (spec && spec->power_hook)
> -		spec->power_hook(codec);
> -	return 0;
> -}
> -
> -static int alc_resume(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (!spec->no_depop_delay)
> -		msleep(150); /* to avoid pop noise */
> -	codec->patch_ops.init(codec);
> -	snd_hda_regmap_sync(codec);
> -	hda_call_check_power_status(codec, 0x01);
> -	return 0;
> -}
> -
> -/*
> - */
> -static const struct hda_codec_ops alc_patch_ops = {
> -	.build_controls = alc_build_controls,
> -	.build_pcms = snd_hda_gen_build_pcms,
> -	.init = alc_init,
> -	.free = alc_free,
> -	.unsol_event = snd_hda_jack_unsol_event,
> -	.resume = alc_resume,
> -	.suspend = alc_suspend,
> -	.check_power_status = snd_hda_gen_check_power_status,
> -};
> -
> -
> -#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
> -
> -/*
> - * Rename codecs appropriately from COEF value or subvendor id
> - */
> -struct alc_codec_rename_table {
> -	unsigned int vendor_id;
> -	unsigned short coef_mask;
> -	unsigned short coef_bits;
> -	const char *name;
> -};
> -
> -struct alc_codec_rename_pci_table {
> -	unsigned int codec_vendor_id;
> -	unsigned short pci_subvendor;
> -	unsigned short pci_subdevice;
> -	const char *name;
> -};
> -
> -static const struct alc_codec_rename_table rename_tbl[] = {
> -	{ 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
> -	{ 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
> -	{ 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
> -	{ 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
> -	{ 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
> -	{ 0x10ec0269, 0xffff, 0xa023, "ALC259" },
> -	{ 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
> -	{ 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
> -	{ 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
> -	{ 0x10ec0662, 0xffff, 0x4020, "ALC656" },
> -	{ 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
> -	{ 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
> -	{ 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
> -	{ 0x10ec0899, 0x2000, 0x2000, "ALC899" },
> -	{ 0x10ec0892, 0xffff, 0x8020, "ALC661" },
> -	{ 0x10ec0892, 0xffff, 0x8011, "ALC661" },
> -	{ 0x10ec0892, 0xffff, 0x4011, "ALC656" },
> -	{ } /* terminator */
> -};
> -
> -static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
> -	{ 0x10ec0280, 0x1028, 0, "ALC3220" },
> -	{ 0x10ec0282, 0x1028, 0, "ALC3221" },
> -	{ 0x10ec0283, 0x1028, 0, "ALC3223" },
> -	{ 0x10ec0288, 0x1028, 0, "ALC3263" },
> -	{ 0x10ec0292, 0x1028, 0, "ALC3226" },
> -	{ 0x10ec0293, 0x1028, 0, "ALC3235" },
> -	{ 0x10ec0255, 0x1028, 0, "ALC3234" },
> -	{ 0x10ec0668, 0x1028, 0, "ALC3661" },
> -	{ 0x10ec0275, 0x1028, 0, "ALC3260" },
> -	{ 0x10ec0899, 0x1028, 0, "ALC3861" },
> -	{ 0x10ec0298, 0x1028, 0, "ALC3266" },
> -	{ 0x10ec0236, 0x1028, 0, "ALC3204" },
> -	{ 0x10ec0256, 0x1028, 0, "ALC3246" },
> -	{ 0x10ec0225, 0x1028, 0, "ALC3253" },
> -	{ 0x10ec0295, 0x1028, 0, "ALC3254" },
> -	{ 0x10ec0299, 0x1028, 0, "ALC3271" },
> -	{ 0x10ec0670, 0x1025, 0, "ALC669X" },
> -	{ 0x10ec0676, 0x1025, 0, "ALC679X" },
> -	{ 0x10ec0282, 0x1043, 0, "ALC3229" },
> -	{ 0x10ec0233, 0x1043, 0, "ALC3236" },
> -	{ 0x10ec0280, 0x103c, 0, "ALC3228" },
> -	{ 0x10ec0282, 0x103c, 0, "ALC3227" },
> -	{ 0x10ec0286, 0x103c, 0, "ALC3242" },
> -	{ 0x10ec0290, 0x103c, 0, "ALC3241" },
> -	{ 0x10ec0668, 0x103c, 0, "ALC3662" },
> -	{ 0x10ec0283, 0x17aa, 0, "ALC3239" },
> -	{ 0x10ec0292, 0x17aa, 0, "ALC3232" },
> -	{ 0x10ec0257, 0x12f0, 0, "ALC3328" },
> -	{ } /* terminator */
> -};
> -
> -static int alc_codec_rename_from_preset(struct hda_codec *codec)
> -{
> -	const struct alc_codec_rename_table *p;
> -	const struct alc_codec_rename_pci_table *q;
> -
> -	for (p = rename_tbl; p->vendor_id; p++) {
> -		if (p->vendor_id != codec->core.vendor_id)
> -			continue;
> -		if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
> -			return alc_codec_rename(codec, p->name);
> -	}
> -
> -	if (!codec->bus->pci)
> -		return 0;
> -	for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
> -		if (q->codec_vendor_id != codec->core.vendor_id)
> -			continue;
> -		if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
> -			continue;
> -		if (!q->pci_subdevice ||
> -		    q->pci_subdevice == codec->bus->pci->subsystem_device)
> -			return alc_codec_rename(codec, q->name);
> -	}
> -
> -	return 0;
> -}
> -
> -
> -/*
> - * Digital-beep handlers
> - */
> -#ifdef CONFIG_SND_HDA_INPUT_BEEP
> -
> -/* additional beep mixers; private_value will be overwritten */
> -static const struct snd_kcontrol_new alc_beep_mixer[] = {
> -	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
> -	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
> -};
> -
> -/* set up and create beep controls */
> -static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
> -			int idx, int dir)
> -{
> -	struct snd_kcontrol_new *knew;
> -	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
> -	int i;
> -
> -	for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
> -		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
> -					    &alc_beep_mixer[i]);
> -		if (!knew)
> -			return -ENOMEM;
> -		knew->private_value = beep_amp;
> -	}
> -	return 0;
> -}
> -
> -static const struct snd_pci_quirk beep_allow_list[] = {
> -	SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
> -	SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
> -	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
> -	SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
> -	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
> -	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
> -	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
> -	SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
> -	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
> -	/* denylist -- no beep available */
> -	SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
> -	SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
> -	{}
> -};
> -
> -static inline int has_cdefine_beep(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	const struct snd_pci_quirk *q;
> -	q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
> -	if (q)
> -		return q->value;
> -	return spec->cdefine.enable_pcbeep;
> -}
> -#else
> -#define set_beep_amp(spec, nid, idx, dir)	0
> -#define has_cdefine_beep(codec)		0
> -#endif
> -
> -/* parse the BIOS configuration and set up the alc_spec */
> -/* return 1 if successful, 0 if the proper config is not found,
> - * or a negative error code
> - */
> -static int alc_parse_auto_config(struct hda_codec *codec,
> -				 const hda_nid_t *ignore_nids,
> -				 const hda_nid_t *ssid_nids)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
> -	int err;
> -
> -	err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
> -				       spec->parse_flags);
> -	if (err < 0)
> -		return err;
> -
> -	if (ssid_nids)
> -		alc_ssid_check(codec, ssid_nids);
> -
> -	err = snd_hda_gen_parse_auto_config(codec, cfg);
> -	if (err < 0)
> -		return err;
> -
> -	return 1;
> -}
> -
> -/* common preparation job for alc_spec */
> -static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
> -{
> -	struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
> -	int err;
> -
> -	if (!spec)
> -		return -ENOMEM;
> -	codec->spec = spec;
> -	snd_hda_gen_spec_init(&spec->gen);
> -	spec->gen.mixer_nid = mixer_nid;
> -	spec->gen.own_eapd_ctl = 1;
> -	codec->single_adc_amp = 1;
> -	/* FIXME: do we need this for all Realtek codec models? */
> -	codec->spdif_status_reset = 1;
> -	codec->forced_resume = 1;
> -	codec->patch_ops = alc_patch_ops;
> -	mutex_init(&spec->coef_mutex);
> -
> -	err = alc_codec_rename_from_preset(codec);
> -	if (err < 0) {
> -		kfree(spec);
> -		return err;
> -	}
> -	return 0;
> -}
> -
> -static int alc880_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
> -	static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> -	return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
> -}
> -
> -/*
> - * ALC880 fix-ups
> - */
> -enum {
> -	ALC880_FIXUP_GPIO1,
> -	ALC880_FIXUP_GPIO2,
> -	ALC880_FIXUP_MEDION_RIM,
> -	ALC880_FIXUP_LG,
> -	ALC880_FIXUP_LG_LW25,
> -	ALC880_FIXUP_W810,
> -	ALC880_FIXUP_EAPD_COEF,
> -	ALC880_FIXUP_TCL_S700,
> -	ALC880_FIXUP_VOL_KNOB,
> -	ALC880_FIXUP_FUJITSU,
> -	ALC880_FIXUP_F1734,
> -	ALC880_FIXUP_UNIWILL,
> -	ALC880_FIXUP_UNIWILL_DIG,
> -	ALC880_FIXUP_Z71V,
> -	ALC880_FIXUP_ASUS_W5A,
> -	ALC880_FIXUP_3ST_BASE,
> -	ALC880_FIXUP_3ST,
> -	ALC880_FIXUP_3ST_DIG,
> -	ALC880_FIXUP_5ST_BASE,
> -	ALC880_FIXUP_5ST,
> -	ALC880_FIXUP_5ST_DIG,
> -	ALC880_FIXUP_6ST_BASE,
> -	ALC880_FIXUP_6ST,
> -	ALC880_FIXUP_6ST_DIG,
> -	ALC880_FIXUP_6ST_AUTOMUTE,
> -};
> -
> -/* enable the volume-knob widget support on NID 0x21 */
> -static void alc880_fixup_vol_knob(struct hda_codec *codec,
> -				  const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PROBE)
> -		snd_hda_jack_detect_enable_callback(codec, 0x21,
> -						    alc_update_knob_master);
> -}
> -
> -static const struct hda_fixup alc880_fixups[] = {
> -	[ALC880_FIXUP_GPIO1] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio1,
> -	},
> -	[ALC880_FIXUP_GPIO2] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio2,
> -	},
> -	[ALC880_FIXUP_MEDION_RIM] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_GPIO2,
> -	},
> -	[ALC880_FIXUP_LG] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			/* disable bogus unused pins */
> -			{ 0x16, 0x411111f0 },
> -			{ 0x18, 0x411111f0 },
> -			{ 0x1a, 0x411111f0 },
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_LG_LW25] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1a, 0x0181344f }, /* line-in */
> -			{ 0x1b, 0x0321403f }, /* headphone */
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_W810] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			/* disable bogus unused pins */
> -			{ 0x17, 0x411111f0 },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_GPIO2,
> -	},
> -	[ALC880_FIXUP_EAPD_COEF] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* change to EAPD mode */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
> -			{}
> -		},
> -	},
> -	[ALC880_FIXUP_TCL_S700] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* change to EAPD mode */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_GPIO2,
> -	},
> -	[ALC880_FIXUP_VOL_KNOB] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc880_fixup_vol_knob,
> -	},
> -	[ALC880_FIXUP_FUJITSU] = {
> -		/* override all pins as BIOS on old Amilo is broken */
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x0121401f }, /* HP */
> -			{ 0x15, 0x99030120 }, /* speaker */
> -			{ 0x16, 0x99030130 }, /* bass speaker */
> -			{ 0x17, 0x411111f0 }, /* N/A */
> -			{ 0x18, 0x411111f0 }, /* N/A */
> -			{ 0x19, 0x01a19950 }, /* mic-in */
> -			{ 0x1a, 0x411111f0 }, /* N/A */
> -			{ 0x1b, 0x411111f0 }, /* N/A */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			{ 0x1e, 0x01454140 }, /* SPDIF out */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_VOL_KNOB,
> -	},
> -	[ALC880_FIXUP_F1734] = {
> -		/* almost compatible with FUJITSU, but no bass and SPDIF */
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x0121401f }, /* HP */
> -			{ 0x15, 0x99030120 }, /* speaker */
> -			{ 0x16, 0x411111f0 }, /* N/A */
> -			{ 0x17, 0x411111f0 }, /* N/A */
> -			{ 0x18, 0x411111f0 }, /* N/A */
> -			{ 0x19, 0x01a19950 }, /* mic-in */
> -			{ 0x1a, 0x411111f0 }, /* N/A */
> -			{ 0x1b, 0x411111f0 }, /* N/A */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			{ 0x1e, 0x411111f0 }, /* N/A */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_VOL_KNOB,
> -	},
> -	[ALC880_FIXUP_UNIWILL] = {
> -		/* need to fix HP and speaker pins to be parsed correctly */
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x0121411f }, /* HP */
> -			{ 0x15, 0x99030120 }, /* speaker */
> -			{ 0x16, 0x99030130 }, /* bass speaker */
> -			{ }
> -		},
> -	},
> -	[ALC880_FIXUP_UNIWILL_DIG] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			/* disable bogus unused pins */
> -			{ 0x17, 0x411111f0 },
> -			{ 0x19, 0x411111f0 },
> -			{ 0x1b, 0x411111f0 },
> -			{ 0x1f, 0x411111f0 },
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_Z71V] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			/* set up the whole pins as BIOS is utterly broken */
> -			{ 0x14, 0x99030120 }, /* speaker */
> -			{ 0x15, 0x0121411f }, /* HP */
> -			{ 0x16, 0x411111f0 }, /* N/A */
> -			{ 0x17, 0x411111f0 }, /* N/A */
> -			{ 0x18, 0x01a19950 }, /* mic-in */
> -			{ 0x19, 0x411111f0 }, /* N/A */
> -			{ 0x1a, 0x01813031 }, /* line-in */
> -			{ 0x1b, 0x411111f0 }, /* N/A */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			{ 0x1e, 0x0144111e }, /* SPDIF */
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_ASUS_W5A] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			/* set up the whole pins as BIOS is utterly broken */
> -			{ 0x14, 0x0121411f }, /* HP */
> -			{ 0x15, 0x411111f0 }, /* N/A */
> -			{ 0x16, 0x411111f0 }, /* N/A */
> -			{ 0x17, 0x411111f0 }, /* N/A */
> -			{ 0x18, 0x90a60160 }, /* mic */
> -			{ 0x19, 0x411111f0 }, /* N/A */
> -			{ 0x1a, 0x411111f0 }, /* N/A */
> -			{ 0x1b, 0x411111f0 }, /* N/A */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			{ 0x1e, 0xb743111e }, /* SPDIF out */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_GPIO1,
> -	},
> -	[ALC880_FIXUP_3ST_BASE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x01014010 }, /* line-out */
> -			{ 0x15, 0x411111f0 }, /* N/A */
> -			{ 0x16, 0x411111f0 }, /* N/A */
> -			{ 0x17, 0x411111f0 }, /* N/A */
> -			{ 0x18, 0x01a19c30 }, /* mic-in */
> -			{ 0x19, 0x0121411f }, /* HP */
> -			{ 0x1a, 0x01813031 }, /* line-in */
> -			{ 0x1b, 0x02a19c40 }, /* front-mic */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			/* 0x1e is filled in below */
> -			{ 0x1f, 0x411111f0 }, /* N/A */
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_3ST] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x411111f0 }, /* N/A */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_3ST_BASE,
> -	},
> -	[ALC880_FIXUP_3ST_DIG] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x0144111e }, /* SPDIF */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_3ST_BASE,
> -	},
> -	[ALC880_FIXUP_5ST_BASE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x01014010 }, /* front */
> -			{ 0x15, 0x411111f0 }, /* N/A */
> -			{ 0x16, 0x01011411 }, /* CLFE */
> -			{ 0x17, 0x01016412 }, /* surr */
> -			{ 0x18, 0x01a19c30 }, /* mic-in */
> -			{ 0x19, 0x0121411f }, /* HP */
> -			{ 0x1a, 0x01813031 }, /* line-in */
> -			{ 0x1b, 0x02a19c40 }, /* front-mic */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			/* 0x1e is filled in below */
> -			{ 0x1f, 0x411111f0 }, /* N/A */
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_5ST] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x411111f0 }, /* N/A */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_5ST_BASE,
> -	},
> -	[ALC880_FIXUP_5ST_DIG] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x0144111e }, /* SPDIF */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_5ST_BASE,
> -	},
> -	[ALC880_FIXUP_6ST_BASE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x01014010 }, /* front */
> -			{ 0x15, 0x01016412 }, /* surr */
> -			{ 0x16, 0x01011411 }, /* CLFE */
> -			{ 0x17, 0x01012414 }, /* side */
> -			{ 0x18, 0x01a19c30 }, /* mic-in */
> -			{ 0x19, 0x02a19c40 }, /* front-mic */
> -			{ 0x1a, 0x01813031 }, /* line-in */
> -			{ 0x1b, 0x0121411f }, /* HP */
> -			{ 0x1c, 0x411111f0 }, /* N/A */
> -			{ 0x1d, 0x411111f0 }, /* N/A */
> -			/* 0x1e is filled in below */
> -			{ 0x1f, 0x411111f0 }, /* N/A */
> -			{ }
> -		}
> -	},
> -	[ALC880_FIXUP_6ST] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x411111f0 }, /* N/A */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_6ST_BASE,
> -	},
> -	[ALC880_FIXUP_6ST_DIG] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x0144111e }, /* SPDIF */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC880_FIXUP_6ST_BASE,
> -	},
> -	[ALC880_FIXUP_6ST_AUTOMUTE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1b, 0x0121401f }, /* HP with jack detect */
> -			{ }
> -		},
> -		.chained_before = true,
> -		.chain_id = ALC880_FIXUP_6ST_BASE,
> -	},
> -};
> -
> -static const struct hda_quirk alc880_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
> -	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
> -	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
> -	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
> -	SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
> -	SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
> -	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
> -	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
> -	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
> -	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
> -	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
> -	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
> -	SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
> -	SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
> -	SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
> -	SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
> -	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
> -	SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
> -	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
> -	SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
> -	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
> -	SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
> -	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
> -
> -	/* Below is the copied entries from alc880_quirks.c.
> -	 * It's not quite sure whether BIOS sets the correct pin-config table
> -	 * on these machines, thus they are kept to be compatible with
> -	 * the old static quirks.  Once when it's confirmed to work without
> -	 * these overrides, it'd be better to remove.
> -	 */
> -	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
> -	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
> -	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
> -	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
> -	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
> -	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
> -	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
> -	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
> -	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
> -	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
> -	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> -	/* default Intel */
> -	SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
> -	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
> -	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
> -	{}
> -};
> -
> -static const struct hda_model_fixup alc880_fixup_models[] = {
> -	{.id = ALC880_FIXUP_3ST, .name = "3stack"},
> -	{.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
> -	{.id = ALC880_FIXUP_5ST, .name = "5stack"},
> -	{.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
> -	{.id = ALC880_FIXUP_6ST, .name = "6stack"},
> -	{.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
> -	{.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
> -	{}
> -};
> -
> -
> -/*
> - * OK, here we have finally the patch for ALC880
> - */
> -static int patch_alc880(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x0b);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -	spec->gen.need_dac_fix = 1;
> -	spec->gen.beep_nid = 0x01;
> -
> -	codec->patch_ops.unsol_event = alc880_unsol_event;
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
> -		       alc880_fixups);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc880_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog) {
> -		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -
> -/*
> - * ALC260 support
> - */
> -static int alc260_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
> -	static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
> -	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
> -}
> -
> -/*
> - * Pin config fixes
> - */
> -enum {
> -	ALC260_FIXUP_HP_DC5750,
> -	ALC260_FIXUP_HP_PIN_0F,
> -	ALC260_FIXUP_COEF,
> -	ALC260_FIXUP_GPIO1,
> -	ALC260_FIXUP_GPIO1_TOGGLE,
> -	ALC260_FIXUP_REPLACER,
> -	ALC260_FIXUP_HP_B1900,
> -	ALC260_FIXUP_KN1,
> -	ALC260_FIXUP_FSC_S7020,
> -	ALC260_FIXUP_FSC_S7020_JWSE,
> -	ALC260_FIXUP_VAIO_PINS,
> -};
> -
> -static void alc260_gpio1_automute(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
> -}
> -
> -static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
> -				      const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PROBE) {
> -		/* although the machine has only one output pin, we need to
> -		 * toggle GPIO1 according to the jack state
> -		 */
> -		spec->gen.automute_hook = alc260_gpio1_automute;
> -		spec->gen.detect_hp = 1;
> -		spec->gen.automute_speaker = 1;
> -		spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
> -		snd_hda_jack_detect_enable_callback(codec, 0x0f,
> -						    snd_hda_gen_hp_automute);
> -		alc_setup_gpio(codec, 0x01);
> -	}
> -}
> -
> -static void alc260_fixup_kn1(struct hda_codec *codec,
> -			     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	static const struct hda_pintbl pincfgs[] = {
> -		{ 0x0f, 0x02214000 }, /* HP/speaker */
> -		{ 0x12, 0x90a60160 }, /* int mic */
> -		{ 0x13, 0x02a19000 }, /* ext mic */
> -		{ 0x18, 0x01446000 }, /* SPDIF out */
> -		/* disable bogus I/O pins */
> -		{ 0x10, 0x411111f0 },
> -		{ 0x11, 0x411111f0 },
> -		{ 0x14, 0x411111f0 },
> -		{ 0x15, 0x411111f0 },
> -		{ 0x16, 0x411111f0 },
> -		{ 0x17, 0x411111f0 },
> -		{ 0x19, 0x411111f0 },
> -		{ }
> -	};
> -
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		snd_hda_apply_pincfgs(codec, pincfgs);
> -		spec->init_amp = ALC_INIT_NONE;
> -		break;
> -	}
> -}
> -
> -static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
> -				   const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> -		spec->init_amp = ALC_INIT_NONE;
> -}
> -
> -static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
> -				   const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->gen.add_jack_modes = 1;
> -		spec->gen.hp_mic = 1;
> -	}
> -}
> -
> -static const struct hda_fixup alc260_fixups[] = {
> -	[ALC260_FIXUP_HP_DC5750] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x11, 0x90130110 }, /* speaker */
> -			{ }
> -		}
> -	},
> -	[ALC260_FIXUP_HP_PIN_0F] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x0f, 0x01214000 }, /* HP */
> -			{ }
> -		}
> -	},
> -	[ALC260_FIXUP_COEF] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
> -			{ }
> -		},
> -	},
> -	[ALC260_FIXUP_GPIO1] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio1,
> -	},
> -	[ALC260_FIXUP_GPIO1_TOGGLE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc260_fixup_gpio1_toggle,
> -		.chained = true,
> -		.chain_id = ALC260_FIXUP_HP_PIN_0F,
> -	},
> -	[ALC260_FIXUP_REPLACER] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
> -	},
> -	[ALC260_FIXUP_HP_B1900] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc260_fixup_gpio1_toggle,
> -		.chained = true,
> -		.chain_id = ALC260_FIXUP_COEF,
> -	},
> -	[ALC260_FIXUP_KN1] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc260_fixup_kn1,
> -	},
> -	[ALC260_FIXUP_FSC_S7020] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc260_fixup_fsc_s7020,
> -	},
> -	[ALC260_FIXUP_FSC_S7020_JWSE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc260_fixup_fsc_s7020_jwse,
> -		.chained = true,
> -		.chain_id = ALC260_FIXUP_FSC_S7020,
> -	},
> -	[ALC260_FIXUP_VAIO_PINS] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			/* Pin configs are missing completely on some VAIOs */
> -			{ 0x0f, 0x01211020 },
> -			{ 0x10, 0x0001003f },
> -			{ 0x11, 0x411111f0 },
> -			{ 0x12, 0x01a15930 },
> -			{ 0x13, 0x411111f0 },
> -			{ 0x14, 0x411111f0 },
> -			{ 0x15, 0x411111f0 },
> -			{ 0x16, 0x411111f0 },
> -			{ 0x17, 0x411111f0 },
> -			{ 0x18, 0x411111f0 },
> -			{ 0x19, 0x411111f0 },
> -			{ }
> -		}
> -	},
> -};
> -
> -static const struct hda_quirk alc260_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
> -	SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
> -	SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
> -	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
> -	SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
> -	SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
> -	SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
> -	SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
> -	SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
> -	SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
> -	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
> -	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
> -	{}
> -};
> -
> -static const struct hda_model_fixup alc260_fixup_models[] = {
> -	{.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
> -	{.id = ALC260_FIXUP_COEF, .name = "coef"},
> -	{.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
> -	{.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
> -	{}
> -};
> -
> -/*
> - */
> -static int patch_alc260(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x07);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -	/* as quite a few machines require HP amp for speaker outputs,
> -	 * it's easier to enable it unconditionally; even if it's unneeded,
> -	 * it's almost harmless.
> -	 */
> -	spec->gen.prefer_hp_amp = 1;
> -	spec->gen.beep_nid = 0x01;
> -
> -	spec->shutup = alc_eapd_shutup;
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
> -			   alc260_fixups);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc260_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog) {
> -		err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -
> -/*
> - * ALC882/883/885/888/889 support
> - *
> - * ALC882 is almost identical with ALC880 but has cleaner and more flexible
> - * configuration.  Each pin widget can choose any input DACs and a mixer.
> - * Each ADC is connected from a mixer of all inputs.  This makes possible
> - * 6-channel independent captures.
> - *
> - * In addition, an independent DAC for the multi-playback (not used in this
> - * driver yet).
> - */
> -
> -/*
> - * Pin config fixes
> - */
> -enum {
> -	ALC882_FIXUP_ABIT_AW9D_MAX,
> -	ALC882_FIXUP_LENOVO_Y530,
> -	ALC882_FIXUP_PB_M5210,
> -	ALC882_FIXUP_ACER_ASPIRE_7736,
> -	ALC882_FIXUP_ASUS_W90V,
> -	ALC889_FIXUP_CD,
> -	ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
> -	ALC889_FIXUP_VAIO_TT,
> -	ALC888_FIXUP_EEE1601,
> -	ALC886_FIXUP_EAPD,
> -	ALC882_FIXUP_EAPD,
> -	ALC883_FIXUP_EAPD,
> -	ALC883_FIXUP_ACER_EAPD,
> -	ALC882_FIXUP_GPIO1,
> -	ALC882_FIXUP_GPIO2,
> -	ALC882_FIXUP_GPIO3,
> -	ALC889_FIXUP_COEF,
> -	ALC882_FIXUP_ASUS_W2JC,
> -	ALC882_FIXUP_ACER_ASPIRE_4930G,
> -	ALC882_FIXUP_ACER_ASPIRE_8930G,
> -	ALC882_FIXUP_ASPIRE_8930G_VERBS,
> -	ALC885_FIXUP_MACPRO_GPIO,
> -	ALC889_FIXUP_DAC_ROUTE,
> -	ALC889_FIXUP_MBP_VREF,
> -	ALC889_FIXUP_IMAC91_VREF,
> -	ALC889_FIXUP_MBA11_VREF,
> -	ALC889_FIXUP_MBA21_VREF,
> -	ALC889_FIXUP_MP11_VREF,
> -	ALC889_FIXUP_MP41_VREF,
> -	ALC882_FIXUP_INV_DMIC,
> -	ALC882_FIXUP_NO_PRIMARY_HP,
> -	ALC887_FIXUP_ASUS_BASS,
> -	ALC887_FIXUP_BASS_CHMAP,
> -	ALC1220_FIXUP_GB_DUAL_CODECS,
> -	ALC1220_FIXUP_GB_X570,
> -	ALC1220_FIXUP_CLEVO_P950,
> -	ALC1220_FIXUP_CLEVO_PB51ED,
> -	ALC1220_FIXUP_CLEVO_PB51ED_PINS,
> -	ALC887_FIXUP_ASUS_AUDIO,
> -	ALC887_FIXUP_ASUS_HMIC,
> -	ALCS1200A_FIXUP_MIC_VREF,
> -	ALC888VD_FIXUP_MIC_100VREF,
> -};
> -
> -static void alc889_fixup_coef(struct hda_codec *codec,
> -			      const struct hda_fixup *fix, int action)
> -{
> -	if (action != HDA_FIXUP_ACT_INIT)
> -		return;
> -	alc_update_coef_idx(codec, 7, 0, 0x2030);
> -}
> -
> -/* set up GPIO at initialization */
> -static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	spec->gpio_write_delay = true;
> -	alc_fixup_gpio3(codec, fix, action);
> -}
> -
> -/* Fix the connection of some pins for ALC889:
> - * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
> - * work correctly (bko#42740)
> - */
> -static void alc889_fixup_dac_route(struct hda_codec *codec,
> -				   const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		/* fake the connections during parsing the tree */
> -		static const hda_nid_t conn1[] = { 0x0c, 0x0d };
> -		static const hda_nid_t conn2[] = { 0x0e, 0x0f };
> -		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
> -		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
> -		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
> -		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
> -	} else if (action == HDA_FIXUP_ACT_PROBE) {
> -		/* restore the connections */
> -		static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
> -		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
> -		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
> -		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
> -		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
> -	}
> -}
> -
> -/* Set VREF on HP pin */
> -static void alc889_fixup_mbp_vref(struct hda_codec *codec,
> -				  const struct hda_fixup *fix, int action)
> -{
> -	static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
> -	struct alc_spec *spec = codec->spec;
> -	int i;
> -
> -	if (action != HDA_FIXUP_ACT_INIT)
> -		return;
> -	for (i = 0; i < ARRAY_SIZE(nids); i++) {
> -		unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
> -		if (get_defcfg_device(val) != AC_JACK_HP_OUT)
> -			continue;
> -		val = snd_hda_codec_get_pin_target(codec, nids[i]);
> -		val |= AC_PINCTL_VREF_80;
> -		snd_hda_set_pin_ctl(codec, nids[i], val);
> -		spec->gen.keep_vref_in_automute = 1;
> -		break;
> -	}
> -}
> -
> -static void alc889_fixup_mac_pins(struct hda_codec *codec,
> -				  const hda_nid_t *nids, int num_nids)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	int i;
> -
> -	for (i = 0; i < num_nids; i++) {
> -		unsigned int val;
> -		val = snd_hda_codec_get_pin_target(codec, nids[i]);
> -		val |= AC_PINCTL_VREF_50;
> -		snd_hda_set_pin_ctl(codec, nids[i], val);
> -	}
> -	spec->gen.keep_vref_in_automute = 1;
> -}
> -
> -/* Set VREF on speaker pins on imac91 */
> -static void alc889_fixup_imac91_vref(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	static const hda_nid_t nids[] = { 0x18, 0x1a };
> -
> -	if (action == HDA_FIXUP_ACT_INIT)
> -		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
> -}
> -
> -/* Set VREF on speaker pins on mba11 */
> -static void alc889_fixup_mba11_vref(struct hda_codec *codec,
> -				    const struct hda_fixup *fix, int action)
> -{
> -	static const hda_nid_t nids[] = { 0x18 };
> -
> -	if (action == HDA_FIXUP_ACT_INIT)
> -		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
> -}
> -
> -/* Set VREF on speaker pins on mba21 */
> -static void alc889_fixup_mba21_vref(struct hda_codec *codec,
> -				    const struct hda_fixup *fix, int action)
> -{
> -	static const hda_nid_t nids[] = { 0x18, 0x19 };
> -
> -	if (action == HDA_FIXUP_ACT_INIT)
> -		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
> -}
> -
> -/* Don't take HP output as primary
> - * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
> - * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
> - */
> -static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
> -				       const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->gen.no_primary_hp = 1;
> -		spec->gen.no_multi_io = 1;
> -	}
> -}
> -
> -static void alc_fixup_bass_chmap(struct hda_codec *codec,
> -				 const struct hda_fixup *fix, int action);
> -
> -/* For dual-codec configuration, we need to disable some features to avoid
> - * conflicts of kctls and PCM streams
> - */
> -static void alc_fixup_dual_codecs(struct hda_codec *codec,
> -				  const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> -		return;
> -	/* disable vmaster */
> -	spec->gen.suppress_vmaster = 1;
> -	/* auto-mute and auto-mic switch don't work with multiple codecs */
> -	spec->gen.suppress_auto_mute = 1;
> -	spec->gen.suppress_auto_mic = 1;
> -	/* disable aamix as well */
> -	spec->gen.mixer_nid = 0;
> -	/* add location prefix to avoid conflicts */
> -	codec->force_pin_prefix = 1;
> -}
> -
> -static void rename_ctl(struct hda_codec *codec, const char *oldname,
> -		       const char *newname)
> -{
> -	struct snd_kcontrol *kctl;
> -
> -	kctl = snd_hda_find_mixer_ctl(codec, oldname);
> -	if (kctl)
> -		snd_ctl_rename(codec->card, kctl, newname);
> -}
> -
> -static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
> -					 const struct hda_fixup *fix,
> -					 int action)
> -{
> -	alc_fixup_dual_codecs(codec, fix, action);
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		/* override card longname to provide a unique UCM profile */
> -		strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
> -		break;
> -	case HDA_FIXUP_ACT_BUILD:
> -		/* rename Capture controls depending on the codec */
> -		rename_ctl(codec, "Capture Volume",
> -			   codec->addr == 0 ?
> -			   "Rear-Panel Capture Volume" :
> -			   "Front-Panel Capture Volume");
> -		rename_ctl(codec, "Capture Switch",
> -			   codec->addr == 0 ?
> -			   "Rear-Panel Capture Switch" :
> -			   "Front-Panel Capture Switch");
> -		break;
> -	}
> -}
> -
> -static void alc1220_fixup_gb_x570(struct hda_codec *codec,
> -				     const struct hda_fixup *fix,
> -				     int action)
> -{
> -	static const hda_nid_t conn1[] = { 0x0c };
> -	static const struct coef_fw gb_x570_coefs[] = {
> -		WRITE_COEF(0x07, 0x03c0),
> -		WRITE_COEF(0x1a, 0x01c1),
> -		WRITE_COEF(0x1b, 0x0202),
> -		WRITE_COEF(0x43, 0x3005),
> -		{}
> -	};
> -
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
> -		snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
> -		break;
> -	case HDA_FIXUP_ACT_INIT:
> -		alc_process_coef_fw(codec, gb_x570_coefs);
> -		break;
> -	}
> -}
> -
> -static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
> -				     const struct hda_fixup *fix,
> -				     int action)
> -{
> -	static const hda_nid_t conn1[] = { 0x0c };
> -
> -	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> -		return;
> -
> -	alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
> -	/* We therefore want to make sure 0x14 (front headphone) and
> -	 * 0x1b (speakers) use the stereo DAC 0x02
> -	 */
> -	snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
> -	snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
> -}
> -
> -static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action);
> -
> -static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
> -				     const struct hda_fixup *fix,
> -				     int action)
> -{
> -	alc1220_fixup_clevo_p950(codec, fix, action);
> -	alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
> -}
> -
> -static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
> -					 struct hda_jack_callback *jack)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	unsigned int vref;
> -
> -	snd_hda_gen_hp_automute(codec, jack);
> -
> -	if (spec->gen.hp_jack_present)
> -		vref = AC_PINCTL_VREF_80;
> -	else
> -		vref = AC_PINCTL_VREF_HIZ;
> -	snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
> -}
> -
> -static void alc887_fixup_asus_jack(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action != HDA_FIXUP_ACT_PROBE)
> -		return;
> -	snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
> -	spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
> -}
> -
> -static const struct hda_fixup alc882_fixups[] = {
> -	[ALC882_FIXUP_ABIT_AW9D_MAX] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x01080104 }, /* side */
> -			{ 0x16, 0x01011012 }, /* rear */
> -			{ 0x17, 0x01016011 }, /* clfe */
> -			{ }
> -		}
> -	},
> -	[ALC882_FIXUP_LENOVO_Y530] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x99130112 }, /* rear int speakers */
> -			{ 0x16, 0x99130111 }, /* subwoofer */
> -			{ }
> -		}
> -	},
> -	[ALC882_FIXUP_PB_M5210] = {
> -		.type = HDA_FIXUP_PINCTLS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, PIN_VREF50 },
> -			{}
> -		}
> -	},
> -	[ALC882_FIXUP_ACER_ASPIRE_7736] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_sku_ignore,
> -	},
> -	[ALC882_FIXUP_ASUS_W90V] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x16, 0x99130110 }, /* fix sequence for CLFE */
> -			{ }
> -		}
> -	},
> -	[ALC889_FIXUP_CD] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1c, 0x993301f0 }, /* CD */
> -			{ }
> -		}
> -	},
> -	[ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC889_FIXUP_CD,
> -	},
> -	[ALC889_FIXUP_VAIO_TT] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x17, 0x90170111 }, /* hidden surround speaker */
> -			{ }
> -		}
> -	},
> -	[ALC888_FIXUP_EEE1601] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
> -			{ 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
> -			{ }
> -		}
> -	},
> -	[ALC886_FIXUP_EAPD] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* change to EAPD mode */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
> -			{ }
> -		}
> -	},
> -	[ALC882_FIXUP_EAPD] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* change to EAPD mode */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
> -			{ }
> -		}
> -	},
> -	[ALC883_FIXUP_EAPD] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* change to EAPD mode */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
> -			{ }
> -		}
> -	},
> -	[ALC883_FIXUP_ACER_EAPD] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* eanable EAPD on Acer laptops */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
> -			{ }
> -		}
> -	},
> -	[ALC882_FIXUP_GPIO1] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio1,
> -	},
> -	[ALC882_FIXUP_GPIO2] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio2,
> -	},
> -	[ALC882_FIXUP_GPIO3] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio3,
> -	},
> -	[ALC882_FIXUP_ASUS_W2JC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_gpio1,
> -		.chained = true,
> -		.chain_id = ALC882_FIXUP_EAPD,
> -	},
> -	[ALC889_FIXUP_COEF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_coef,
> -	},
> -	[ALC882_FIXUP_ACER_ASPIRE_4930G] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x16, 0x99130111 }, /* CLFE speaker */
> -			{ 0x17, 0x99130112 }, /* surround speaker */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC882_FIXUP_GPIO1,
> -	},
> -	[ALC882_FIXUP_ACER_ASPIRE_8930G] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x16, 0x99130111 }, /* CLFE speaker */
> -			{ 0x1b, 0x99130112 }, /* surround speaker */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
> -	},
> -	[ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
> -		/* additional init verbs for Acer Aspire 8930G */
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* Enable all DACs */
> -			/* DAC DISABLE/MUTE 1? */
> -			/*  setting bits 1-5 disables DAC nids 0x02-0x06
> -			 *  apparently. Init=0x38 */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
> -			/* DAC DISABLE/MUTE 2? */
> -			/*  some bit here disables the other DACs.
> -			 *  Init=0x4900 */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
> -			/* DMIC fix
> -			 * This laptop has a stereo digital microphone.
> -			 * The mics are only 1cm apart which makes the stereo
> -			 * useless. However, either the mic or the ALC889
> -			 * makes the signal become a difference/sum signal
> -			 * instead of standard stereo, which is annoying.
> -			 * So instead we flip this bit which makes the
> -			 * codec replicate the sum signal to both channels,
> -			 * turning it into a normal mono mic.
> -			 */
> -			/* DMIC_CONTROL? Init value = 0x0001 */
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC882_FIXUP_GPIO1,
> -	},
> -	[ALC885_FIXUP_MACPRO_GPIO] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc885_fixup_macpro_gpio,
> -	},
> -	[ALC889_FIXUP_DAC_ROUTE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_dac_route,
> -	},
> -	[ALC889_FIXUP_MBP_VREF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_mbp_vref,
> -		.chained = true,
> -		.chain_id = ALC882_FIXUP_GPIO1,
> -	},
> -	[ALC889_FIXUP_IMAC91_VREF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_imac91_vref,
> -		.chained = true,
> -		.chain_id = ALC882_FIXUP_GPIO1,
> -	},
> -	[ALC889_FIXUP_MBA11_VREF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_mba11_vref,
> -		.chained = true,
> -		.chain_id = ALC889_FIXUP_MBP_VREF,
> -	},
> -	[ALC889_FIXUP_MBA21_VREF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_mba21_vref,
> -		.chained = true,
> -		.chain_id = ALC889_FIXUP_MBP_VREF,
> -	},
> -	[ALC889_FIXUP_MP11_VREF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_mba11_vref,
> -		.chained = true,
> -		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
> -	},
> -	[ALC889_FIXUP_MP41_VREF] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc889_fixup_mbp_vref,
> -		.chained = true,
> -		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
> -	},
> -	[ALC882_FIXUP_INV_DMIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_inv_dmic,
> -	},
> -	[ALC882_FIXUP_NO_PRIMARY_HP] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc882_fixup_no_primary_hp,
> -	},
> -	[ALC887_FIXUP_ASUS_BASS] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{0x16, 0x99130130}, /* bass speaker */
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC887_FIXUP_BASS_CHMAP,
> -	},
> -	[ALC887_FIXUP_BASS_CHMAP] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_bass_chmap,
> -	},
> -	[ALC1220_FIXUP_GB_DUAL_CODECS] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc1220_fixup_gb_dual_codecs,
> -	},
> -	[ALC1220_FIXUP_GB_X570] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc1220_fixup_gb_x570,
> -	},
> -	[ALC1220_FIXUP_CLEVO_P950] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc1220_fixup_clevo_p950,
> -	},
> -	[ALC1220_FIXUP_CLEVO_PB51ED] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc1220_fixup_clevo_pb51ed,
> -	},
> -	[ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
> -	},
> -	[ALC887_FIXUP_ASUS_AUDIO] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
> -			{ 0x19, 0x22219420 },
> -			{}
> -		},
> -	},
> -	[ALC887_FIXUP_ASUS_HMIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc887_fixup_asus_jack,
> -		.chained = true,
> -		.chain_id = ALC887_FIXUP_ASUS_AUDIO,
> -	},
> -	[ALCS1200A_FIXUP_MIC_VREF] = {
> -		.type = HDA_FIXUP_PINCTLS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x18, PIN_VREF50 }, /* rear mic */
> -			{ 0x19, PIN_VREF50 }, /* front mic */
> -			{}
> -		}
> -	},
> -	[ALC888VD_FIXUP_MIC_100VREF] = {
> -		.type = HDA_FIXUP_PINCTLS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x18, PIN_VREF100 }, /* headset mic */
> -			{}
> -		}
> -	},
> -};
> -
> -static const struct hda_quirk alc882_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
> -	SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
> -		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> -	SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
> -		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> -	SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
> -		      ALC882_FIXUP_ACER_ASPIRE_8930G),
> -	SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
> -		      ALC882_FIXUP_ACER_ASPIRE_8930G),
> -	SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
> -		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> -	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
> -	SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
> -		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> -	SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
> -		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> -	SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
> -		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> -	SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
> -	SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
> -	SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
> -	SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
> -	SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
> -	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
> -	SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
> -	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
> -	SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
> -	SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
> -	SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
> -	SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
> -	SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
> -	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
> -	SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
> -	SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
> -
> -	/* All Apple entries are in codec SSIDs */
> -	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
> -	SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
> -	SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
> -	SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
> -	SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
> -	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
> -
> -	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
> -	SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
> -	SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
> -	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
> -	SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
> -	SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
> -	SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
> -	SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
> -	SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
> -	SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
> -	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
> -	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
> -	SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
> -	SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
> -	SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> -	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
> -	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
> -	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
> -	SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
> -	{}
> -};
> -
> -static const struct hda_model_fixup alc882_fixup_models[] = {
> -	{.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
> -	{.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
> -	{.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
> -	{.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
> -	{.id = ALC889_FIXUP_CD, .name = "cd"},
> -	{.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
> -	{.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
> -	{.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
> -	{.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
> -	{.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
> -	{.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
> -	{.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
> -	{.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
> -	{.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
> -	{.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
> -	{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
> -	{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
> -	{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
> -	{.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
> -	{.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
> -	{.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
> -	{.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
> -	{.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
> -	{.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
> -	{.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
> -	{.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
> -	{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
> -	{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
> -	{.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
> -	{.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
> -	{.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
> -	{.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
> -	{}
> -};
> -
> -static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
> -	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
> -		{0x14, 0x01014010},
> -		{0x15, 0x01011012},
> -		{0x16, 0x01016011},
> -		{0x18, 0x01a19040},
> -		{0x19, 0x02a19050},
> -		{0x1a, 0x0181304f},
> -		{0x1b, 0x0221401f},
> -		{0x1e, 0x01456130}),
> -	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
> -		{0x14, 0x01015010},
> -		{0x15, 0x01011012},
> -		{0x16, 0x01011011},
> -		{0x18, 0x01a11040},
> -		{0x19, 0x02a19050},
> -		{0x1a, 0x0181104f},
> -		{0x1b, 0x0221401f},
> -		{0x1e, 0x01451130}),
> -	{}
> -};
> -
> -/*
> - * BIOS auto configuration
> - */
> -/* almost identical with ALC880 parser... */
> -static int alc882_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
> -	static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> -	return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
> -}
> -
> -/*
> - */
> -static int patch_alc882(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x0b);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0882:
> -	case 0x10ec0885:
> -	case 0x10ec0900:
> -	case 0x10ec0b00:
> -	case 0x10ec1220:
> -		break;
> -	default:
> -		/* ALC883 and variants */
> -		alc_fix_pll_init(codec, 0x20, 0x0a, 10);
> -		break;
> -	}
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
> -		       alc882_fixups);
> -	snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	alc_auto_parse_customize_define(codec);
> -
> -	if (has_cdefine_beep(codec))
> -		spec->gen.beep_nid = 0x01;
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc882_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog && spec->gen.beep_nid) {
> -		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -
> -/*
> - * ALC262 support
> - */
> -static int alc262_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
> -	static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> -	return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
> -}
> -
> -/*
> - * Pin config fixes
> - */
> -enum {
> -	ALC262_FIXUP_FSC_H270,
> -	ALC262_FIXUP_FSC_S7110,
> -	ALC262_FIXUP_HP_Z200,
> -	ALC262_FIXUP_TYAN,
> -	ALC262_FIXUP_LENOVO_3000,
> -	ALC262_FIXUP_BENQ,
> -	ALC262_FIXUP_BENQ_T31,
> -	ALC262_FIXUP_INV_DMIC,
> -	ALC262_FIXUP_INTEL_BAYLEYBAY,
> -};
> -
> -static const struct hda_fixup alc262_fixups[] = {
> -	[ALC262_FIXUP_FSC_H270] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x15, 0x0221142f }, /* front HP */
> -			{ 0x1b, 0x0121141f }, /* rear HP */
> -			{ }
> -		}
> -	},
> -	[ALC262_FIXUP_FSC_S7110] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x90170110 }, /* speaker */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC262_FIXUP_BENQ,
> -	},
> -	[ALC262_FIXUP_HP_Z200] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x16, 0x99130120 }, /* internal speaker */
> -			{ }
> -		}
> -	},
> -	[ALC262_FIXUP_TYAN] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x1993e1f0 }, /* int AUX */
> -			{ }
> -		}
> -	},
> -	[ALC262_FIXUP_LENOVO_3000] = {
> -		.type = HDA_FIXUP_PINCTLS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, PIN_VREF50 },
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC262_FIXUP_BENQ,
> -	},
> -	[ALC262_FIXUP_BENQ] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
> -			{}
> -		}
> -	},
> -	[ALC262_FIXUP_BENQ_T31] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
> -			{}
> -		}
> -	},
> -	[ALC262_FIXUP_INV_DMIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_inv_dmic,
> -	},
> -	[ALC262_FIXUP_INTEL_BAYLEYBAY] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_no_depop_delay,
> -	},
> -};
> -
> -static const struct hda_quirk alc262_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
> -	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
> -	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
> -	SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
> -	SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
> -	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
> -	SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
> -	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
> -	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
> -	SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
> -	{}
> -};
> -
> -static const struct hda_model_fixup alc262_fixup_models[] = {
> -	{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
> -	{.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
> -	{.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
> -	{.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
> -	{.id = ALC262_FIXUP_TYAN, .name = "tyan"},
> -	{.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
> -	{.id = ALC262_FIXUP_BENQ, .name = "benq"},
> -	{.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
> -	{.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
> -	{}
> -};
> -
> -/*
> - */
> -static int patch_alc262(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x0b);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -	spec->gen.shared_mic_vref_pin = 0x18;
> -
> -	spec->shutup = alc_eapd_shutup;
> -
> -#if 0
> -	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
> -	 * under-run
> -	 */
> -	alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
> -#endif
> -	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
> -		       alc262_fixups);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	alc_auto_parse_customize_define(codec);
> -
> -	if (has_cdefine_beep(codec))
> -		spec->gen.beep_nid = 0x01;
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc262_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog && spec->gen.beep_nid) {
> -		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -/*
> - *  ALC268
> - */
> -/* bind Beep switches of both NID 0x0f and 0x10 */
> -static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
> -				  struct snd_ctl_elem_value *ucontrol)
> -{
> -	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
> -	unsigned long pval;
> -	int err;
> -
> -	mutex_lock(&codec->control_mutex);
> -	pval = kcontrol->private_value;
> -	kcontrol->private_value = (pval & ~0xff) | 0x0f;
> -	err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
> -	if (err >= 0) {
> -		kcontrol->private_value = (pval & ~0xff) | 0x10;
> -		err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
> -	}
> -	kcontrol->private_value = pval;
> -	mutex_unlock(&codec->control_mutex);
> -	return err;
> -}
> -
> -static const struct snd_kcontrol_new alc268_beep_mixer[] = {
> -	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
> -	{
> -		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
> -		.name = "Beep Playback Switch",
> -		.subdevice = HDA_SUBDEV_AMP_FLAG,
> -		.info = snd_hda_mixer_amp_switch_info,
> -		.get = snd_hda_mixer_amp_switch_get,
> -		.put = alc268_beep_switch_put,
> -		.private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
> -	},
> -};
> -
> -/* set PCBEEP vol = 0, mute connections */
> -static const struct hda_verb alc268_beep_init_verbs[] = {
> -	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
> -	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
> -	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
> -	{ }
> -};
> -
> -enum {
> -	ALC268_FIXUP_INV_DMIC,
> -	ALC268_FIXUP_HP_EAPD,
> -	ALC268_FIXUP_SPDIF,
> -};
> -
> -static const struct hda_fixup alc268_fixups[] = {
> -	[ALC268_FIXUP_INV_DMIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_inv_dmic,
> -	},
> -	[ALC268_FIXUP_HP_EAPD] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
> -			{}
> -		}
> -	},
> -	[ALC268_FIXUP_SPDIF] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1e, 0x014b1180 }, /* enable SPDIF out */
> -			{}
> -		}
> -	},
> -};
> -
> -static const struct hda_model_fixup alc268_fixup_models[] = {
> -	{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
> -	{.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
> -	{.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
> -	{}
> -};
> -
> -static const struct hda_quirk alc268_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
> -	SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
> -	/* below is codec SSID since multiple Toshiba laptops have the
> -	 * same PCI SSID 1179:ff00
> -	 */
> -	SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
> -	{}
> -};
> -
> -/*
> - * BIOS auto configuration
> - */
> -static int alc268_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> -	return alc_parse_auto_config(codec, NULL, alc268_ssids);
> -}
> -
> -/*
> - */
> -static int patch_alc268(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int i, err;
> -
> -	/* ALC268 has no aa-loopback mixer */
> -	err = alc_alloc_spec(codec, 0);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -	if (has_cdefine_beep(codec))
> -		spec->gen.beep_nid = 0x01;
> -
> -	spec->shutup = alc_eapd_shutup;
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc268_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (err > 0 && !spec->gen.no_analog &&
> -	    spec->gen.autocfg.speaker_pins[0] != 0x1d) {
> -		for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
> -			if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
> -						  &alc268_beep_mixer[i])) {
> -				err = -ENOMEM;
> -				goto error;
> -			}
> -		}
> -		snd_hda_add_verbs(codec, alc268_beep_init_verbs);
> -		if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
> -			/* override the amp caps for beep generator */
> -			snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
> -					  (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
> -					  (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
> -					  (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
> -					  (0 << AC_AMPCAP_MUTE_SHIFT));
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -/*
> - * ALC269
> - */
> -
>   static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
>   	.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
>   };
> @@ -4191,15 +1046,6 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
>   		alc_update_coef_idx(codec, 0x1e, 0, 0x80);
>   }
>   
> -static void alc269_fixup_headset_mic(struct hda_codec *codec,
> -				       const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> -}
> -
>   static void alc271_fixup_dmic(struct hda_codec *codec,
>   			      const struct hda_fixup *fix, int action)
>   {
> @@ -4470,61 +1316,6 @@ static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
>   	alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
>   }
>   
> -/* update LED status via GPIO */
> -static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
> -				int polarity, bool enabled)
> -{
> -	if (polarity)
> -		enabled = !enabled;
> -	alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
> -}
> -
> -/* turn on/off mute LED via GPIO per vmaster hook */
> -static int gpio_mute_led_set(struct led_classdev *led_cdev,
> -			     enum led_brightness brightness)
> -{
> -	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
> -	struct alc_spec *spec = codec->spec;
> -
> -	alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
> -			    spec->mute_led_polarity, !brightness);
> -	return 0;
> -}
> -
> -/* turn on/off mic-mute LED via GPIO per capture hook */
> -static int micmute_led_set(struct led_classdev *led_cdev,
> -			   enum led_brightness brightness)
> -{
> -	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
> -	struct alc_spec *spec = codec->spec;
> -
> -	alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
> -			    spec->micmute_led_polarity, !brightness);
> -	return 0;
> -}
> -
> -/* setup mute and mic-mute GPIO bits, add hooks appropriately */
> -static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
> -				  int action,
> -				  unsigned int mute_mask,
> -				  unsigned int micmute_mask)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
> -
> -	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> -		return;
> -	if (mute_mask) {
> -		spec->gpio_mute_led_mask = mute_mask;
> -		snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
> -	}
> -	if (micmute_mask) {
> -		spec->gpio_mic_led_mask = micmute_mask;
> -		snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
> -	}
> -}
> -
>   static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
>   				const struct hda_fixup *fix, int action)
>   {
> @@ -5167,985 +1958,6 @@ static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec,
>   	alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
>   }
>   
> -static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
> -{
> -	if (delay <= 0)
> -		delay = 75;
> -	snd_hda_codec_write(codec, 0x21, 0,
> -		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
> -	msleep(delay);
> -	snd_hda_codec_write(codec, 0x21, 0,
> -		    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
> -	msleep(delay);
> -}
> -
> -static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
> -{
> -	if (delay <= 0)
> -		delay = 75;
> -	snd_hda_codec_write(codec, 0x21, 0,
> -		    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
> -	msleep(delay);
> -	snd_hda_codec_write(codec, 0x21, 0,
> -		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
> -	msleep(delay);
> -}
> -
> -static const struct coef_fw alc225_pre_hsmode[] = {
> -	UPDATE_COEF(0x4a, 1<<8, 0),
> -	UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
> -	UPDATE_COEF(0x63, 3<<14, 3<<14),
> -	UPDATE_COEF(0x4a, 3<<4, 2<<4),
> -	UPDATE_COEF(0x4a, 3<<10, 3<<10),
> -	UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
> -	UPDATE_COEF(0x4a, 3<<10, 0),
> -	{}
> -};
> -
> -static void alc_headset_mode_unplugged(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	static const struct coef_fw coef0255[] = {
> -		WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
> -		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
> -		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
> -		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
> -		WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
> -		{}
> -	};
> -	static const struct coef_fw coef0256[] = {
> -		WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
> -		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
> -		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
> -		WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
> -		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
> -		{}
> -	};
> -	static const struct coef_fw coef0233[] = {
> -		WRITE_COEF(0x1b, 0x0c0b),
> -		WRITE_COEF(0x45, 0xc429),
> -		UPDATE_COEF(0x35, 0x4000, 0),
> -		WRITE_COEF(0x06, 0x2104),
> -		WRITE_COEF(0x1a, 0x0001),
> -		WRITE_COEF(0x26, 0x0004),
> -		WRITE_COEF(0x32, 0x42a3),
> -		{}
> -	};
> -	static const struct coef_fw coef0288[] = {
> -		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
> -		UPDATE_COEF(0x50, 0x2000, 0x2000),
> -		UPDATE_COEF(0x56, 0x0006, 0x0006),
> -		UPDATE_COEF(0x66, 0x0008, 0),
> -		UPDATE_COEF(0x67, 0x2000, 0),
> -		{}
> -	};
> -	static const struct coef_fw coef0298[] = {
> -		UPDATE_COEF(0x19, 0x1300, 0x0300),
> -		{}
> -	};
> -	static const struct coef_fw coef0292[] = {
> -		WRITE_COEF(0x76, 0x000e),
> -		WRITE_COEF(0x6c, 0x2400),
> -		WRITE_COEF(0x18, 0x7308),
> -		WRITE_COEF(0x6b, 0xc429),
> -		{}
> -	};
> -	static const struct coef_fw coef0293[] = {
> -		UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
> -		UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
> -		UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
> -		UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
> -		WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
> -		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
> -		{}
> -	};
> -	static const struct coef_fw coef0668[] = {
> -		WRITE_COEF(0x15, 0x0d40),
> -		WRITE_COEF(0xb7, 0x802b),
> -		{}
> -	};
> -	static const struct coef_fw coef0225[] = {
> -		UPDATE_COEF(0x63, 3<<14, 0),
> -		{}
> -	};
> -	static const struct coef_fw coef0274[] = {
> -		UPDATE_COEF(0x4a, 0x0100, 0),
> -		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
> -		UPDATE_COEF(0x6b, 0xf000, 0x5000),
> -		UPDATE_COEF(0x4a, 0x0010, 0),
> -		UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
> -		WRITE_COEF(0x45, 0x5289),
> -		UPDATE_COEF(0x4a, 0x0c00, 0),
> -		{}
> -	};
> -
> -	if (spec->no_internal_mic_pin) {
> -		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
> -		return;
> -	}
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0255:
> -		alc_process_coef_fw(codec, coef0255);
> -		break;
> -	case 0x10ec0230:
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x19e58326:
> -		alc_hp_mute_disable(codec, 75);
> -		alc_process_coef_fw(codec, coef0256);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -	case 0x10ec0294:
> -		alc_process_coef_fw(codec, coef0274);
> -		break;
> -	case 0x10ec0233:
> -	case 0x10ec0283:
> -		alc_process_coef_fw(codec, coef0233);
> -		break;
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -		alc_process_coef_fw(codec, coef0288);
> -		break;
> -	case 0x10ec0298:
> -		alc_process_coef_fw(codec, coef0298);
> -		alc_process_coef_fw(codec, coef0288);
> -		break;
> -	case 0x10ec0292:
> -		alc_process_coef_fw(codec, coef0292);
> -		break;
> -	case 0x10ec0293:
> -		alc_process_coef_fw(codec, coef0293);
> -		break;
> -	case 0x10ec0668:
> -		alc_process_coef_fw(codec, coef0668);
> -		break;
> -	case 0x10ec0215:
> -	case 0x10ec0225:
> -	case 0x10ec0285:
> -	case 0x10ec0295:
> -	case 0x10ec0289:
> -	case 0x10ec0299:
> -		alc_hp_mute_disable(codec, 75);
> -		alc_process_coef_fw(codec, alc225_pre_hsmode);
> -		alc_process_coef_fw(codec, coef0225);
> -		break;
> -	case 0x10ec0867:
> -		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> -		break;
> -	}
> -	codec_dbg(codec, "Headset jack set to unplugged mode.\n");
> -}
> -
> -
> -static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
> -				    hda_nid_t mic_pin)
> -{
> -	static const struct coef_fw coef0255[] = {
> -		WRITE_COEFEX(0x57, 0x03, 0x8aa6),
> -		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
> -		{}
> -	};
> -	static const struct coef_fw coef0256[] = {
> -		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
> -		WRITE_COEFEX(0x57, 0x03, 0x09a3),
> -		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
> -		{}
> -	};
> -	static const struct coef_fw coef0233[] = {
> -		UPDATE_COEF(0x35, 0, 1<<14),
> -		WRITE_COEF(0x06, 0x2100),
> -		WRITE_COEF(0x1a, 0x0021),
> -		WRITE_COEF(0x26, 0x008c),
> -		{}
> -	};
> -	static const struct coef_fw coef0288[] = {
> -		UPDATE_COEF(0x4f, 0x00c0, 0),
> -		UPDATE_COEF(0x50, 0x2000, 0),
> -		UPDATE_COEF(0x56, 0x0006, 0),
> -		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
> -		UPDATE_COEF(0x66, 0x0008, 0x0008),
> -		UPDATE_COEF(0x67, 0x2000, 0x2000),
> -		{}
> -	};
> -	static const struct coef_fw coef0292[] = {
> -		WRITE_COEF(0x19, 0xa208),
> -		WRITE_COEF(0x2e, 0xacf0),
> -		{}
> -	};
> -	static const struct coef_fw coef0293[] = {
> -		UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
> -		UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
> -		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
> -		{}
> -	};
> -	static const struct coef_fw coef0688[] = {
> -		WRITE_COEF(0xb7, 0x802b),
> -		WRITE_COEF(0xb5, 0x1040),
> -		UPDATE_COEF(0xc3, 0, 1<<12),
> -		{}
> -	};
> -	static const struct coef_fw coef0225[] = {
> -		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
> -		UPDATE_COEF(0x4a, 3<<4, 2<<4),
> -		UPDATE_COEF(0x63, 3<<14, 0),
> -		{}
> -	};
> -	static const struct coef_fw coef0274[] = {
> -		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
> -		UPDATE_COEF(0x4a, 0x0010, 0),
> -		UPDATE_COEF(0x6b, 0xf000, 0),
> -		{}
> -	};
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0255:
> -		alc_write_coef_idx(codec, 0x45, 0xc489);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0255);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0230:
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x19e58326:
> -		alc_write_coef_idx(codec, 0x45, 0xc489);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0256);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -	case 0x10ec0294:
> -		alc_write_coef_idx(codec, 0x45, 0x4689);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0274);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0233:
> -	case 0x10ec0283:
> -		alc_write_coef_idx(codec, 0x45, 0xc429);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0233);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -	case 0x10ec0298:
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0288);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0292:
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0292);
> -		break;
> -	case 0x10ec0293:
> -		/* Set to TRS mode */
> -		alc_write_coef_idx(codec, 0x45, 0xc429);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0293);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0867:
> -		alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
> -		fallthrough;
> -	case 0x10ec0221:
> -	case 0x10ec0662:
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0668:
> -		alc_write_coef_idx(codec, 0x11, 0x0001);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0688);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	case 0x10ec0215:
> -	case 0x10ec0225:
> -	case 0x10ec0285:
> -	case 0x10ec0295:
> -	case 0x10ec0289:
> -	case 0x10ec0299:
> -		alc_process_coef_fw(codec, alc225_pre_hsmode);
> -		alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> -		alc_process_coef_fw(codec, coef0225);
> -		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> -		break;
> -	}
> -	codec_dbg(codec, "Headset jack set to mic-in mode.\n");
> -}
> -
> -static void alc_headset_mode_default(struct hda_codec *codec)
> -{
> -	static const struct coef_fw coef0225[] = {
> -		UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
> -		UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
> -		UPDATE_COEF(0x49, 3<<8, 0<<8),
> -		UPDATE_COEF(0x4a, 3<<4, 3<<4),
> -		UPDATE_COEF(0x63, 3<<14, 0),
> -		UPDATE_COEF(0x67, 0xf000, 0x3000),
> -		{}
> -	};
> -	static const struct coef_fw coef0255[] = {
> -		WRITE_COEF(0x45, 0xc089),
> -		WRITE_COEF(0x45, 0xc489),
> -		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
> -		WRITE_COEF(0x49, 0x0049),
> -		{}
> -	};
> -	static const struct coef_fw coef0256[] = {
> -		WRITE_COEF(0x45, 0xc489),
> -		WRITE_COEFEX(0x57, 0x03, 0x0da3),
> -		WRITE_COEF(0x49, 0x0049),
> -		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
> -		WRITE_COEF(0x06, 0x6100),
> -		{}
> -	};
> -	static const struct coef_fw coef0233[] = {
> -		WRITE_COEF(0x06, 0x2100),
> -		WRITE_COEF(0x32, 0x4ea3),
> -		{}
> -	};
> -	static const struct coef_fw coef0288[] = {
> -		UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
> -		UPDATE_COEF(0x50, 0x2000, 0x2000),
> -		UPDATE_COEF(0x56, 0x0006, 0x0006),
> -		UPDATE_COEF(0x66, 0x0008, 0),
> -		UPDATE_COEF(0x67, 0x2000, 0),
> -		{}
> -	};
> -	static const struct coef_fw coef0292[] = {
> -		WRITE_COEF(0x76, 0x000e),
> -		WRITE_COEF(0x6c, 0x2400),
> -		WRITE_COEF(0x6b, 0xc429),
> -		WRITE_COEF(0x18, 0x7308),
> -		{}
> -	};
> -	static const struct coef_fw coef0293[] = {
> -		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
> -		WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
> -		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
> -		{}
> -	};
> -	static const struct coef_fw coef0688[] = {
> -		WRITE_COEF(0x11, 0x0041),
> -		WRITE_COEF(0x15, 0x0d40),
> -		WRITE_COEF(0xb7, 0x802b),
> -		{}
> -	};
> -	static const struct coef_fw coef0274[] = {
> -		WRITE_COEF(0x45, 0x4289),
> -		UPDATE_COEF(0x4a, 0x0010, 0x0010),
> -		UPDATE_COEF(0x6b, 0x0f00, 0),
> -		UPDATE_COEF(0x49, 0x0300, 0x0300),
> -		{}
> -	};
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0215:
> -	case 0x10ec0225:
> -	case 0x10ec0285:
> -	case 0x10ec0295:
> -	case 0x10ec0289:
> -	case 0x10ec0299:
> -		alc_process_coef_fw(codec, alc225_pre_hsmode);
> -		alc_process_coef_fw(codec, coef0225);
> -		alc_hp_enable_unmute(codec, 75);
> -		break;
> -	case 0x10ec0255:
> -		alc_process_coef_fw(codec, coef0255);
> -		break;
> -	case 0x10ec0230:
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x19e58326:
> -		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
> -		alc_write_coef_idx(codec, 0x45, 0xc089);
> -		msleep(50);
> -		alc_process_coef_fw(codec, coef0256);
> -		alc_hp_enable_unmute(codec, 75);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -	case 0x10ec0294:
> -		alc_process_coef_fw(codec, coef0274);
> -		break;
> -	case 0x10ec0233:
> -	case 0x10ec0283:
> -		alc_process_coef_fw(codec, coef0233);
> -		break;
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -	case 0x10ec0298:
> -		alc_process_coef_fw(codec, coef0288);
> -		break;
> -	case 0x10ec0292:
> -		alc_process_coef_fw(codec, coef0292);
> -		break;
> -	case 0x10ec0293:
> -		alc_process_coef_fw(codec, coef0293);
> -		break;
> -	case 0x10ec0668:
> -		alc_process_coef_fw(codec, coef0688);
> -		break;
> -	case 0x10ec0867:
> -		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> -		break;
> -	}
> -	codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
> -}
> -
> -/* Iphone type */
> -static void alc_headset_mode_ctia(struct hda_codec *codec)
> -{
> -	int val;
> -
> -	static const struct coef_fw coef0255[] = {
> -		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
> -		WRITE_COEF(0x1b, 0x0c2b),
> -		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
> -		{}
> -	};
> -	static const struct coef_fw coef0256[] = {
> -		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
> -		WRITE_COEF(0x1b, 0x0e6b),
> -		{}
> -	};
> -	static const struct coef_fw coef0233[] = {
> -		WRITE_COEF(0x45, 0xd429),
> -		WRITE_COEF(0x1b, 0x0c2b),
> -		WRITE_COEF(0x32, 0x4ea3),
> -		{}
> -	};
> -	static const struct coef_fw coef0288[] = {
> -		UPDATE_COEF(0x50, 0x2000, 0x2000),
> -		UPDATE_COEF(0x56, 0x0006, 0x0006),
> -		UPDATE_COEF(0x66, 0x0008, 0),
> -		UPDATE_COEF(0x67, 0x2000, 0),
> -		{}
> -	};
> -	static const struct coef_fw coef0292[] = {
> -		WRITE_COEF(0x6b, 0xd429),
> -		WRITE_COEF(0x76, 0x0008),
> -		WRITE_COEF(0x18, 0x7388),
> -		{}
> -	};
> -	static const struct coef_fw coef0293[] = {
> -		WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
> -		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
> -		{}
> -	};
> -	static const struct coef_fw coef0688[] = {
> -		WRITE_COEF(0x11, 0x0001),
> -		WRITE_COEF(0x15, 0x0d60),
> -		WRITE_COEF(0xc3, 0x0000),
> -		{}
> -	};
> -	static const struct coef_fw coef0225_1[] = {
> -		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
> -		UPDATE_COEF(0x63, 3<<14, 2<<14),
> -		{}
> -	};
> -	static const struct coef_fw coef0225_2[] = {
> -		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
> -		UPDATE_COEF(0x63, 3<<14, 1<<14),
> -		{}
> -	};
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0255:
> -		alc_process_coef_fw(codec, coef0255);
> -		break;
> -	case 0x10ec0230:
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x19e58326:
> -		alc_process_coef_fw(codec, coef0256);
> -		alc_hp_enable_unmute(codec, 75);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -	case 0x10ec0294:
> -		alc_write_coef_idx(codec, 0x45, 0xd689);
> -		break;
> -	case 0x10ec0233:
> -	case 0x10ec0283:
> -		alc_process_coef_fw(codec, coef0233);
> -		break;
> -	case 0x10ec0298:
> -		val = alc_read_coef_idx(codec, 0x50);
> -		if (val & (1 << 12)) {
> -			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
> -			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
> -			msleep(300);
> -		} else {
> -			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
> -			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
> -			msleep(300);
> -		}
> -		break;
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
> -		msleep(300);
> -		alc_process_coef_fw(codec, coef0288);
> -		break;
> -	case 0x10ec0292:
> -		alc_process_coef_fw(codec, coef0292);
> -		break;
> -	case 0x10ec0293:
> -		alc_process_coef_fw(codec, coef0293);
> -		break;
> -	case 0x10ec0668:
> -		alc_process_coef_fw(codec, coef0688);
> -		break;
> -	case 0x10ec0215:
> -	case 0x10ec0225:
> -	case 0x10ec0285:
> -	case 0x10ec0295:
> -	case 0x10ec0289:
> -	case 0x10ec0299:
> -		val = alc_read_coef_idx(codec, 0x45);
> -		if (val & (1 << 9))
> -			alc_process_coef_fw(codec, coef0225_2);
> -		else
> -			alc_process_coef_fw(codec, coef0225_1);
> -		alc_hp_enable_unmute(codec, 75);
> -		break;
> -	case 0x10ec0867:
> -		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> -		break;
> -	}
> -	codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
> -}
> -
> -/* Nokia type */
> -static void alc_headset_mode_omtp(struct hda_codec *codec)
> -{
> -	static const struct coef_fw coef0255[] = {
> -		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
> -		WRITE_COEF(0x1b, 0x0c2b),
> -		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
> -		{}
> -	};
> -	static const struct coef_fw coef0256[] = {
> -		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
> -		WRITE_COEF(0x1b, 0x0e6b),
> -		{}
> -	};
> -	static const struct coef_fw coef0233[] = {
> -		WRITE_COEF(0x45, 0xe429),
> -		WRITE_COEF(0x1b, 0x0c2b),
> -		WRITE_COEF(0x32, 0x4ea3),
> -		{}
> -	};
> -	static const struct coef_fw coef0288[] = {
> -		UPDATE_COEF(0x50, 0x2000, 0x2000),
> -		UPDATE_COEF(0x56, 0x0006, 0x0006),
> -		UPDATE_COEF(0x66, 0x0008, 0),
> -		UPDATE_COEF(0x67, 0x2000, 0),
> -		{}
> -	};
> -	static const struct coef_fw coef0292[] = {
> -		WRITE_COEF(0x6b, 0xe429),
> -		WRITE_COEF(0x76, 0x0008),
> -		WRITE_COEF(0x18, 0x7388),
> -		{}
> -	};
> -	static const struct coef_fw coef0293[] = {
> -		WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
> -		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
> -		{}
> -	};
> -	static const struct coef_fw coef0688[] = {
> -		WRITE_COEF(0x11, 0x0001),
> -		WRITE_COEF(0x15, 0x0d50),
> -		WRITE_COEF(0xc3, 0x0000),
> -		{}
> -	};
> -	static const struct coef_fw coef0225[] = {
> -		UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
> -		UPDATE_COEF(0x63, 3<<14, 2<<14),
> -		{}
> -	};
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0255:
> -		alc_process_coef_fw(codec, coef0255);
> -		break;
> -	case 0x10ec0230:
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x19e58326:
> -		alc_process_coef_fw(codec, coef0256);
> -		alc_hp_enable_unmute(codec, 75);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -	case 0x10ec0294:
> -		alc_write_coef_idx(codec, 0x45, 0xe689);
> -		break;
> -	case 0x10ec0233:
> -	case 0x10ec0283:
> -		alc_process_coef_fw(codec, coef0233);
> -		break;
> -	case 0x10ec0298:
> -		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
> -		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
> -		msleep(300);
> -		break;
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
> -		msleep(300);
> -		alc_process_coef_fw(codec, coef0288);
> -		break;
> -	case 0x10ec0292:
> -		alc_process_coef_fw(codec, coef0292);
> -		break;
> -	case 0x10ec0293:
> -		alc_process_coef_fw(codec, coef0293);
> -		break;
> -	case 0x10ec0668:
> -		alc_process_coef_fw(codec, coef0688);
> -		break;
> -	case 0x10ec0215:
> -	case 0x10ec0225:
> -	case 0x10ec0285:
> -	case 0x10ec0295:
> -	case 0x10ec0289:
> -	case 0x10ec0299:
> -		alc_process_coef_fw(codec, coef0225);
> -		alc_hp_enable_unmute(codec, 75);
> -		break;
> -	}
> -	codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
> -}
> -
> -static void alc_determine_headset_type(struct hda_codec *codec)
> -{
> -	int val;
> -	bool is_ctia = false;
> -	struct alc_spec *spec = codec->spec;
> -	static const struct coef_fw coef0255[] = {
> -		WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
> -		WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
> - conteol) */
> -		{}
> -	};
> -	static const struct coef_fw coef0288[] = {
> -		UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
> -		{}
> -	};
> -	static const struct coef_fw coef0298[] = {
> -		UPDATE_COEF(0x50, 0x2000, 0x2000),
> -		UPDATE_COEF(0x56, 0x0006, 0x0006),
> -		UPDATE_COEF(0x66, 0x0008, 0),
> -		UPDATE_COEF(0x67, 0x2000, 0),
> -		UPDATE_COEF(0x19, 0x1300, 0x1300),
> -		{}
> -	};
> -	static const struct coef_fw coef0293[] = {
> -		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
> -		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
> -		{}
> -	};
> -	static const struct coef_fw coef0688[] = {
> -		WRITE_COEF(0x11, 0x0001),
> -		WRITE_COEF(0xb7, 0x802b),
> -		WRITE_COEF(0x15, 0x0d60),
> -		WRITE_COEF(0xc3, 0x0c00),
> -		{}
> -	};
> -	static const struct coef_fw coef0274[] = {
> -		UPDATE_COEF(0x4a, 0x0010, 0),
> -		UPDATE_COEF(0x4a, 0x8000, 0),
> -		WRITE_COEF(0x45, 0xd289),
> -		UPDATE_COEF(0x49, 0x0300, 0x0300),
> -		{}
> -	};
> -
> -	if (spec->no_internal_mic_pin) {
> -		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
> -		return;
> -	}
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0255:
> -		alc_process_coef_fw(codec, coef0255);
> -		msleep(300);
> -		val = alc_read_coef_idx(codec, 0x46);
> -		is_ctia = (val & 0x0070) == 0x0070;
> -		break;
> -	case 0x10ec0230:
> -	case 0x10ec0236:
> -	case 0x10ec0256:
> -	case 0x19e58326:
> -		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
> -		alc_write_coef_idx(codec, 0x06, 0x6104);
> -		alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
> -
> -		alc_process_coef_fw(codec, coef0255);
> -		msleep(300);
> -		val = alc_read_coef_idx(codec, 0x46);
> -		is_ctia = (val & 0x0070) == 0x0070;
> -		if (!is_ctia) {
> -			alc_write_coef_idx(codec, 0x45, 0xe089);
> -			msleep(100);
> -			val = alc_read_coef_idx(codec, 0x46);
> -			if ((val & 0x0070) == 0x0070)
> -				is_ctia = false;
> -			else
> -				is_ctia = true;
> -		}
> -		alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
> -		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> -		break;
> -	case 0x10ec0234:
> -	case 0x10ec0274:
> -	case 0x10ec0294:
> -		alc_process_coef_fw(codec, coef0274);
> -		msleep(850);
> -		val = alc_read_coef_idx(codec, 0x46);
> -		is_ctia = (val & 0x00f0) == 0x00f0;
> -		break;
> -	case 0x10ec0233:
> -	case 0x10ec0283:
> -		alc_write_coef_idx(codec, 0x45, 0xd029);
> -		msleep(300);
> -		val = alc_read_coef_idx(codec, 0x46);
> -		is_ctia = (val & 0x0070) == 0x0070;
> -		break;
> -	case 0x10ec0298:
> -		snd_hda_codec_write(codec, 0x21, 0,
> -			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
> -		msleep(100);
> -		snd_hda_codec_write(codec, 0x21, 0,
> -			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
> -		msleep(200);
> -
> -		val = alc_read_coef_idx(codec, 0x50);
> -		if (val & (1 << 12)) {
> -			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
> -			alc_process_coef_fw(codec, coef0288);
> -			msleep(350);
> -			val = alc_read_coef_idx(codec, 0x50);
> -			is_ctia = (val & 0x0070) == 0x0070;
> -		} else {
> -			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
> -			alc_process_coef_fw(codec, coef0288);
> -			msleep(350);
> -			val = alc_read_coef_idx(codec, 0x50);
> -			is_ctia = (val & 0x0070) == 0x0070;
> -		}
> -		alc_process_coef_fw(codec, coef0298);
> -		snd_hda_codec_write(codec, 0x21, 0,
> -			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
> -		msleep(75);
> -		snd_hda_codec_write(codec, 0x21, 0,
> -			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
> -		break;
> -	case 0x10ec0286:
> -	case 0x10ec0288:
> -		alc_process_coef_fw(codec, coef0288);
> -		msleep(350);
> -		val = alc_read_coef_idx(codec, 0x50);
> -		is_ctia = (val & 0x0070) == 0x0070;
> -		break;
> -	case 0x10ec0292:
> -		alc_write_coef_idx(codec, 0x6b, 0xd429);
> -		msleep(300);
> -		val = alc_read_coef_idx(codec, 0x6c);
> -		is_ctia = (val & 0x001c) == 0x001c;
> -		break;
> -	case 0x10ec0293:
> -		alc_process_coef_fw(codec, coef0293);
> -		msleep(300);
> -		val = alc_read_coef_idx(codec, 0x46);
> -		is_ctia = (val & 0x0070) == 0x0070;
> -		break;
> -	case 0x10ec0668:
> -		alc_process_coef_fw(codec, coef0688);
> -		msleep(300);
> -		val = alc_read_coef_idx(codec, 0xbe);
> -		is_ctia = (val & 0x1c02) == 0x1c02;
> -		break;
> -	case 0x10ec0215:
> -	case 0x10ec0225:
> -	case 0x10ec0285:
> -	case 0x10ec0295:
> -	case 0x10ec0289:
> -	case 0x10ec0299:
> -		alc_process_coef_fw(codec, alc225_pre_hsmode);
> -		alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
> -		val = alc_read_coef_idx(codec, 0x45);
> -		if (val & (1 << 9)) {
> -			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
> -			alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
> -			msleep(800);
> -			val = alc_read_coef_idx(codec, 0x46);
> -			is_ctia = (val & 0x00f0) == 0x00f0;
> -		} else {
> -			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
> -			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
> -			msleep(800);
> -			val = alc_read_coef_idx(codec, 0x46);
> -			is_ctia = (val & 0x00f0) == 0x00f0;
> -		}
> -		if (!is_ctia) {
> -			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
> -			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
> -			msleep(100);
> -			val = alc_read_coef_idx(codec, 0x46);
> -			if ((val & 0x00f0) == 0x00f0)
> -				is_ctia = false;
> -			else
> -				is_ctia = true;
> -		}
> -		alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
> -		alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
> -		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
> -		break;
> -	case 0x10ec0867:
> -		is_ctia = true;
> -		break;
> -	}
> -
> -	codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
> -		  str_yes_no(is_ctia));
> -	spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
> -}
> -
> -static void alc_update_headset_mode(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
> -	hda_nid_t hp_pin = alc_get_hp_pin(spec);
> -
> -	int new_headset_mode;
> -
> -	if (!snd_hda_jack_detect(codec, hp_pin))
> -		new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
> -	else if (mux_pin == spec->headset_mic_pin)
> -		new_headset_mode = ALC_HEADSET_MODE_HEADSET;
> -	else if (mux_pin == spec->headphone_mic_pin)
> -		new_headset_mode = ALC_HEADSET_MODE_MIC;
> -	else
> -		new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
> -
> -	if (new_headset_mode == spec->current_headset_mode) {
> -		snd_hda_gen_update_outputs(codec);
> -		return;
> -	}
> -
> -	switch (new_headset_mode) {
> -	case ALC_HEADSET_MODE_UNPLUGGED:
> -		alc_headset_mode_unplugged(codec);
> -		spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
> -		spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
> -		spec->gen.hp_jack_present = false;
> -		break;
> -	case ALC_HEADSET_MODE_HEADSET:
> -		if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
> -			alc_determine_headset_type(codec);
> -		if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
> -			alc_headset_mode_ctia(codec);
> -		else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
> -			alc_headset_mode_omtp(codec);
> -		spec->gen.hp_jack_present = true;
> -		break;
> -	case ALC_HEADSET_MODE_MIC:
> -		alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
> -		spec->gen.hp_jack_present = false;
> -		break;
> -	case ALC_HEADSET_MODE_HEADPHONE:
> -		alc_headset_mode_default(codec);
> -		spec->gen.hp_jack_present = true;
> -		break;
> -	}
> -	if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
> -		snd_hda_set_pin_ctl_cache(codec, hp_pin,
> -					  AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
> -		if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
> -			snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
> -						  PIN_VREFHIZ);
> -	}
> -	spec->current_headset_mode = new_headset_mode;
> -
> -	snd_hda_gen_update_outputs(codec);
> -}
> -
> -static void alc_update_headset_mode_hook(struct hda_codec *codec,
> -					 struct snd_kcontrol *kcontrol,
> -					 struct snd_ctl_elem_value *ucontrol)
> -{
> -	alc_update_headset_mode(codec);
> -}
> -
> -static void alc_update_headset_jack_cb(struct hda_codec *codec,
> -				       struct hda_jack_callback *jack)
> -{
> -	snd_hda_gen_hp_automute(codec, jack);
> -	alc_update_headset_mode(codec);
> -}
> -
> -static void alc_probe_headset_mode(struct hda_codec *codec)
> -{
> -	int i;
> -	struct alc_spec *spec = codec->spec;
> -	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
> -
> -	/* Find mic pins */
> -	for (i = 0; i < cfg->num_inputs; i++) {
> -		if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
> -			spec->headset_mic_pin = cfg->inputs[i].pin;
> -		if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
> -			spec->headphone_mic_pin = cfg->inputs[i].pin;
> -	}
> -
> -	WARN_ON(spec->gen.cap_sync_hook);
> -	spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
> -	spec->gen.automute_hook = alc_update_headset_mode;
> -	spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
> -}
> -
> -static void alc_fixup_headset_mode(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
> -		break;
> -	case HDA_FIXUP_ACT_PROBE:
> -		alc_probe_headset_mode(codec);
> -		break;
> -	case HDA_FIXUP_ACT_INIT:
> -		if (is_s3_resume(codec) || is_s4_resume(codec)) {
> -			spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
> -			spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
> -		}
> -		alc_update_headset_mode(codec);
> -		break;
> -	}
> -}
> -
> -static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		struct alc_spec *spec = codec->spec;
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> -	}
> -	else
> -		alc_fixup_headset_mode(codec, fix, action);
> -}
> -
>   static void alc255_set_default_jack_type(struct hda_codec *codec)
>   {
>   	/* Set to iphone type */
> @@ -6223,15 +2035,6 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
>   	}
>   }
>   
> -static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
> -					const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		struct alc_spec *spec = codec->spec;
> -		spec->gen.auto_mute_via_amp = 1;
> -	}
> -}
> -
>   static void alc_fixup_no_shutup(struct hda_codec *codec,
>   				const struct hda_fixup *fix, int action)
>   {
> @@ -6241,16 +2044,6 @@ static void alc_fixup_no_shutup(struct hda_codec *codec,
>   	}
>   }
>   
> -static void alc_fixup_disable_aamix(struct hda_codec *codec,
> -				    const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		struct alc_spec *spec = codec->spec;
> -		/* Disable AA-loopback as it causes white noise */
> -		spec->gen.mixer_nid = 0;
> -	}
> -}
> -
>   /* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */
>   static void alc_fixup_tpt440_dock(struct hda_codec *codec,
>   				  const struct hda_fixup *fix, int action)
> @@ -6321,94 +2114,6 @@ static void alc295_fixup_asus_dacs(struct hda_codec *codec,
>   		spec->gen.preferred_dacs = preferred_pairs;
>   }
>   
> -static void alc_shutup_dell_xps13(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	int hp_pin = alc_get_hp_pin(spec);
> -
> -	/* Prevent pop noises when headphones are plugged in */
> -	snd_hda_codec_write(codec, hp_pin, 0,
> -			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
> -	msleep(20);
> -}
> -
> -static void alc_fixup_dell_xps13(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	struct hda_input_mux *imux = &spec->gen.input_mux;
> -	int i;
> -
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		/* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
> -		 * it causes a click noise at start up
> -		 */
> -		snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
> -		spec->shutup = alc_shutup_dell_xps13;
> -		break;
> -	case HDA_FIXUP_ACT_PROBE:
> -		/* Make the internal mic the default input source. */
> -		for (i = 0; i < imux->num_items; i++) {
> -			if (spec->gen.imux_pins[i] == 0x12) {
> -				spec->gen.cur_mux[0] = i;
> -				break;
> -			}
> -		}
> -		break;
> -	}
> -}
> -
> -static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> -		spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
> -
> -		/* Disable boost for mic-in permanently. (This code is only called
> -		   from quirks that guarantee that the headphone is at NID 0x1b.) */
> -		snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
> -		snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
> -	} else
> -		alc_fixup_headset_mode(codec, fix, action);
> -}
> -
> -static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		alc_write_coef_idx(codec, 0xc4, 0x8000);
> -		alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
> -		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
> -	}
> -	alc_fixup_headset_mode(codec, fix, action);
> -}
> -
> -/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
> -static int find_ext_mic_pin(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
> -	hda_nid_t nid;
> -	unsigned int defcfg;
> -	int i;
> -
> -	for (i = 0; i < cfg->num_inputs; i++) {
> -		if (cfg->inputs[i].type != AUTO_PIN_MIC)
> -			continue;
> -		nid = cfg->inputs[i].pin;
> -		defcfg = snd_hda_codec_get_pincfg(codec, nid);
> -		if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
> -			continue;
> -		return nid;
> -	}
> -
> -	return 0;
> -}
> -
>   static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
>   				    const struct hda_fixup *fix,
>   				    int action)
> @@ -6416,7 +2121,7 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
>   	struct alc_spec *spec = codec->spec;
>   
>   	if (action == HDA_FIXUP_ACT_PROBE) {
> -		int mic_pin = find_ext_mic_pin(codec);
> +		int mic_pin = alc_find_ext_mic_pin(codec);
>   		int hp_pin = alc_get_hp_pin(spec);
>   
>   		if (snd_BUG_ON(!mic_pin || !hp_pin))
> @@ -6694,30 +2399,6 @@ static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec,
>   	}
>   }
>   
> -static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
> -					 const struct hda_fixup *fix,
> -					 int action)
> -{
> -	alc_fixup_dual_codecs(codec, fix, action);
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		/* override card longname to provide a unique UCM profile */
> -		strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
> -		break;
> -	case HDA_FIXUP_ACT_BUILD:
> -		/* rename Capture controls depending on the codec */
> -		rename_ctl(codec, "Capture Volume",
> -			   codec->addr == 0 ?
> -			   "Rear-Panel Capture Volume" :
> -			   "Front-Panel Capture Volume");
> -		rename_ctl(codec, "Capture Switch",
> -			   codec->addr == 0 ?
> -			   "Rear-Panel Capture Switch" :
> -			   "Front-Panel Capture Switch");
> -		break;
> -	}
> -}
> -
>   static void alc225_fixup_s3_pop_noise(struct hda_codec *codec,
>   				      const struct hda_fixup *fix, int action)
>   {
> @@ -7120,7 +2801,7 @@ static void alc285_fixup_hp_beep(struct hda_codec *codec,
>   }
>   
>   /* for hda_fixup_thinkpad_acpi() */
> -#include "helpers/thinkpad.c"
> +#include "../helpers/thinkpad.c"
>   
>   static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
>   				    const struct hda_fixup *fix, int action)
> @@ -7130,7 +2811,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
>   }
>   
>   /* for hda_fixup_ideapad_acpi() */
> -#include "helpers/ideapad_hotkey_led.c"
> +#include "../helpers/ideapad_hotkey_led.c"
>   
>   static void alc_fixup_ideapad_acpi(struct hda_codec *codec,
>   				   const struct hda_fixup *fix, int action)
> @@ -7362,10 +3043,10 @@ static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
>   
>   
>   /* for alc295_fixup_hp_top_speakers */
> -#include "helpers/hp_x360.c"
> +#include "../helpers/hp_x360.c"
>   
>   /* for alc285_fixup_ideapad_s740_coef() */
> -#include "helpers/ideapad_s740.c"
> +#include "../helpers/ideapad_s740.c"
>   
>   static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
>   	WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
> @@ -7567,9 +3248,10 @@ static void alc287_fixup_bind_dacs(struct hda_codec *codec,
>   					0x0); /* Make sure 0x14 was disable */
>   	}
>   }
> +
>   /* Fix none verb table of Headset Mic pin */
> -static void alc_fixup_headset_mic(struct hda_codec *codec,
> -				   const struct hda_fixup *fix, int action)
> +static void alc2xx_fixup_headset_mic(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
>   {
>   	struct alc_spec *spec = codec->spec;
>   	static const struct hda_pintbl pincfgs[] = {
> @@ -8164,7 +3846,7 @@ static const struct hda_fixup alc269_fixups[] = {
>   	},
>   	[ALC269_FIXUP_HEADSET_MIC] = {
>   		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc269_fixup_headset_mic,
> +		.v.func = alc_fixup_headset_mic,
>   	},
>   	[ALC269_FIXUP_QUANTA_MUTE] = {
>   		.type = HDA_FIXUP_FUNC,
> @@ -10324,7 +6006,7 @@ static const struct hda_fixup alc269_fixups[] = {
>   	},
>   	[ALC2XX_FIXUP_HEADSET_MIC] = {
>   		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_headset_mic,
> +		.v.func = alc2xx_fixup_headset_mic,
>   	},
>   	[ALC289_FIXUP_DELL_CS35L41_SPI_2] = {
>   		.type = HDA_FIXUP_FUNC,
> @@ -12159,6 +7841,16 @@ static void alc269_fill_coef(struct hda_codec *codec)
>   	alc_update_coef_idx(codec, 0x4, 0, 1<<11);
>   }
>   
> +static void alc269_free(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (spec)
> +		hda_component_manager_free(&spec->comps, &comp_master_ops);
> +
> +	alc_free(codec);
> +}
> +
>   /*
>    */
>   static int patch_alc269(struct hda_codec *codec)
> @@ -12177,6 +7869,7 @@ static int patch_alc269(struct hda_codec *codec)
>   
>   	codec->patch_ops.suspend = alc269_suspend;
>   	codec->patch_ops.resume = alc269_resume;
> +	codec->patch_ops.free = alc269_free;
>   	spec->shutup = alc_default_shutup;
>   	spec->init_hook = alc_default_init;
>   
> @@ -12379,1327 +8072,9 @@ static int patch_alc269(struct hda_codec *codec)
>   }
>   
>   /*
> - * ALC861
> + * driver entries
>    */
> -
> -static int alc861_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
> -	static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
> -	return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
> -}
> -
> -/* Pin config fixes */
> -enum {
> -	ALC861_FIXUP_FSC_AMILO_PI1505,
> -	ALC861_FIXUP_AMP_VREF_0F,
> -	ALC861_FIXUP_NO_JACK_DETECT,
> -	ALC861_FIXUP_ASUS_A6RP,
> -	ALC660_FIXUP_ASUS_W7J,
> -};
> -
> -/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
> -static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
> -			const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	unsigned int val;
> -
> -	if (action != HDA_FIXUP_ACT_INIT)
> -		return;
> -	val = snd_hda_codec_get_pin_target(codec, 0x0f);
> -	if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
> -		val |= AC_PINCTL_IN_EN;
> -	val |= AC_PINCTL_VREF_50;
> -	snd_hda_set_pin_ctl(codec, 0x0f, val);
> -	spec->gen.keep_vref_in_automute = 1;
> -}
> -
> -/* suppress the jack-detection */
> -static void alc_fixup_no_jack_detect(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> -		codec->no_jack_detect = 1;
> -}
> -
> -static const struct hda_fixup alc861_fixups[] = {
> -	[ALC861_FIXUP_FSC_AMILO_PI1505] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x0b, 0x0221101f }, /* HP */
> -			{ 0x0f, 0x90170310 }, /* speaker */
> -			{ }
> -		}
> -	},
> -	[ALC861_FIXUP_AMP_VREF_0F] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc861_fixup_asus_amp_vref_0f,
> -	},
> -	[ALC861_FIXUP_NO_JACK_DETECT] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_no_jack_detect,
> -	},
> -	[ALC861_FIXUP_ASUS_A6RP] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc861_fixup_asus_amp_vref_0f,
> -		.chained = true,
> -		.chain_id = ALC861_FIXUP_NO_JACK_DETECT,
> -	},
> -	[ALC660_FIXUP_ASUS_W7J] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			/* ASUS W7J needs a magic pin setup on unused NID 0x10
> -			 * for enabling outputs
> -			 */
> -			{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
> -			{ }
> -		},
> -	}
> -};
> -
> -static const struct hda_quirk alc861_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
> -	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
> -	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
> -	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
> -	SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
> -	SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
> -	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
> -	{}
> -};
> -
> -/*
> - */
> -static int patch_alc861(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x15);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -	if (has_cdefine_beep(codec))
> -		spec->gen.beep_nid = 0x23;
> -
> -	spec->power_hook = alc_power_eapd;
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc861_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog) {
> -		err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -/*
> - * ALC861-VD support
> - *
> - * Based on ALC882
> - *
> - * In addition, an independent DAC
> - */
> -static int alc861vd_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
> -	static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> -	return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
> -}
> -
> -enum {
> -	ALC660VD_FIX_ASUS_GPIO1,
> -	ALC861VD_FIX_DALLAS,
> -};
> -
> -/* exclude VREF80 */
> -static void alc861vd_fixup_dallas(struct hda_codec *codec,
> -				  const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
> -		snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
> -	}
> -}
> -
> -/* reset GPIO1 */
> -static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
> -				      const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> -		spec->gpio_mask |= 0x02;
> -	alc_fixup_gpio(codec, action, 0x01);
> -}
> -
> -static const struct hda_fixup alc861vd_fixups[] = {
> -	[ALC660VD_FIX_ASUS_GPIO1] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc660vd_fixup_asus_gpio1,
> -	},
> -	[ALC861VD_FIX_DALLAS] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc861vd_fixup_dallas,
> -	},
> -};
> -
> -static const struct hda_quirk alc861vd_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
> -	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
> -	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
> -	{}
> -};
> -
> -/*
> - */
> -static int patch_alc861vd(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x0b);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -	if (has_cdefine_beep(codec))
> -		spec->gen.beep_nid = 0x23;
> -
> -	spec->shutup = alc_eapd_shutup;
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc861vd_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog) {
> -		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -/*
> - * ALC662 support
> - *
> - * ALC662 is almost identical with ALC880 but has cleaner and more flexible
> - * configuration.  Each pin widget can choose any input DACs and a mixer.
> - * Each ADC is connected from a mixer of all inputs.  This makes possible
> - * 6-channel independent captures.
> - *
> - * In addition, an independent DAC for the multi-playback (not used in this
> - * driver yet).
> - */
> -
> -/*
> - * BIOS auto configuration
> - */
> -
> -static int alc662_parse_auto_config(struct hda_codec *codec)
> -{
> -	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
> -	static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
> -	static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> -	const hda_nid_t *ssids;
> -
> -	if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
> -	    codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
> -	    codec->core.vendor_id == 0x10ec0671)
> -		ssids = alc663_ssids;
> -	else
> -		ssids = alc662_ssids;
> -	return alc_parse_auto_config(codec, alc662_ignore, ssids);
> -}
> -
> -static void alc272_fixup_mario(struct hda_codec *codec,
> -			       const struct hda_fixup *fix, int action)
> -{
> -	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> -		return;
> -	if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
> -				      (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
> -				      (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
> -				      (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
> -				      (0 << AC_AMPCAP_MUTE_SHIFT)))
> -		codec_warn(codec, "failed to override amp caps for NID 0x2\n");
> -}
> -
> -static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
> -	{ .channels = 2,
> -	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
> -	{ .channels = 4,
> -	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
> -		   SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
> -	{ }
> -};
> -
> -/* override the 2.1 chmap */
> -static void alc_fixup_bass_chmap(struct hda_codec *codec,
> -				    const struct hda_fixup *fix, int action)
> -{
> -	if (action == HDA_FIXUP_ACT_BUILD) {
> -		struct alc_spec *spec = codec->spec;
> -		spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
> -	}
> -}
> -
> -/* avoid D3 for keeping GPIO up */
> -static unsigned int gpio_led_power_filter(struct hda_codec *codec,
> -					  hda_nid_t nid,
> -					  unsigned int power_state)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
> -		return AC_PWRST_D0;
> -	return power_state;
> -}
> -
> -static void alc662_fixup_led_gpio1(struct hda_codec *codec,
> -				   const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->mute_led_polarity = 1;
> -		codec->power_filter = gpio_led_power_filter;
> -	}
> -}
> -
> -static void alc662_usi_automute_hook(struct hda_codec *codec,
> -					 struct hda_jack_callback *jack)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	int vref;
> -	msleep(200);
> -	snd_hda_gen_hp_automute(codec, jack);
> -
> -	vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
> -	msleep(100);
> -	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
> -			    vref);
> -}
> -
> -static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> -		spec->gen.hp_automute_hook = alc662_usi_automute_hook;
> -	}
> -}
> -
> -static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
> -					struct hda_jack_callback *cb)
> -{
> -	/* surround speakers at 0x1b already get muted automatically when
> -	 * headphones are plugged in, but we have to mute/unmute the remaining
> -	 * channels manually:
> -	 * 0x15 - front left/front right
> -	 * 0x18 - front center/ LFE
> -	 */
> -	if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
> -		snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
> -		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
> -	} else {
> -		snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
> -		snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
> -	}
> -}
> -
> -static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
> -					const struct hda_fixup *fix, int action)
> -{
> -    /* Pin 0x1b: shared headphones jack and surround speakers */
> -	if (!is_jack_detectable(codec, 0x1b))
> -		return;
> -
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		snd_hda_jack_detect_enable_callback(codec, 0x1b,
> -				alc662_aspire_ethos_mute_speakers);
> -		/* subwoofer needs an extra GPIO setting to become audible */
> -		alc_setup_gpio(codec, 0x02);
> -		break;
> -	case HDA_FIXUP_ACT_INIT:
> -		/* Make sure to start in a correct state, i.e. if
> -		 * headphones have been plugged in before powering up the system
> -		 */
> -		alc662_aspire_ethos_mute_speakers(codec, NULL);
> -		break;
> -	}
> -}
> -
> -static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
> -					     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	static const struct hda_pintbl pincfgs[] = {
> -		{ 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
> -		{ 0x1b, 0x0181304f },
> -		{ }
> -	};
> -
> -	switch (action) {
> -	case HDA_FIXUP_ACT_PRE_PROBE:
> -		spec->gen.mixer_nid = 0;
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> -		snd_hda_apply_pincfgs(codec, pincfgs);
> -		break;
> -	case HDA_FIXUP_ACT_INIT:
> -		alc_write_coef_idx(codec, 0x19, 0xa054);
> -		break;
> -	}
> -}
> -
> -static void alc897_hp_automute_hook(struct hda_codec *codec,
> -					 struct hda_jack_callback *jack)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	int vref;
> -
> -	snd_hda_gen_hp_automute(codec, jack);
> -	vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
> -	snd_hda_set_pin_ctl(codec, 0x1b, vref);
> -}
> -
> -static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
> -		spec->no_shutup_pins = 1;
> -	}
> -	if (action == HDA_FIXUP_ACT_PROBE) {
> -		snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
> -	}
> -}
> -
> -static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
> -				     const struct hda_fixup *fix, int action)
> -{
> -	struct alc_spec *spec = codec->spec;
> -
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> -		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> -		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
> -	}
> -}
> -
> -static const struct coef_fw alc668_coefs[] = {
> -	WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
> -	WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
> -	WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b,    0x0),
> -	WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
> -	WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
> -	WRITE_COEF(0x13,    0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
> -	WRITE_COEF(0x19,    0x0), WRITE_COEF(0x1a,    0x0), WRITE_COEF(0x1b,    0x0),
> -	WRITE_COEF(0x1c,    0x0), WRITE_COEF(0x1d,    0x0), WRITE_COEF(0x1e, 0x7418),
> -	WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
> -	WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
> -	WRITE_COEF(0x27,    0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
> -	WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
> -	WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac,    0x0),
> -	WRITE_COEF(0xad,    0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
> -	WRITE_COEF(0xb0,    0x0), WRITE_COEF(0xb1,    0x0), WRITE_COEF(0xb2,    0x0),
> -	WRITE_COEF(0xb3,    0x0), WRITE_COEF(0xb4,    0x0), WRITE_COEF(0xb5, 0x1040),
> -	WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
> -	WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
> -	WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
> -	WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
> -	{}
> -};
> -
> -static void alc668_restore_default_value(struct hda_codec *codec)
> -{
> -	alc_process_coef_fw(codec, alc668_coefs);
> -}
> -
> -enum {
> -	ALC662_FIXUP_ASPIRE,
> -	ALC662_FIXUP_LED_GPIO1,
> -	ALC662_FIXUP_IDEAPAD,
> -	ALC272_FIXUP_MARIO,
> -	ALC662_FIXUP_CZC_ET26,
> -	ALC662_FIXUP_CZC_P10T,
> -	ALC662_FIXUP_SKU_IGNORE,
> -	ALC662_FIXUP_HP_RP5800,
> -	ALC662_FIXUP_ASUS_MODE1,
> -	ALC662_FIXUP_ASUS_MODE2,
> -	ALC662_FIXUP_ASUS_MODE3,
> -	ALC662_FIXUP_ASUS_MODE4,
> -	ALC662_FIXUP_ASUS_MODE5,
> -	ALC662_FIXUP_ASUS_MODE6,
> -	ALC662_FIXUP_ASUS_MODE7,
> -	ALC662_FIXUP_ASUS_MODE8,
> -	ALC662_FIXUP_NO_JACK_DETECT,
> -	ALC662_FIXUP_ZOTAC_Z68,
> -	ALC662_FIXUP_INV_DMIC,
> -	ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
> -	ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
> -	ALC662_FIXUP_HEADSET_MODE,
> -	ALC668_FIXUP_HEADSET_MODE,
> -	ALC662_FIXUP_BASS_MODE4_CHMAP,
> -	ALC662_FIXUP_BASS_16,
> -	ALC662_FIXUP_BASS_1A,
> -	ALC662_FIXUP_BASS_CHMAP,
> -	ALC668_FIXUP_AUTO_MUTE,
> -	ALC668_FIXUP_DELL_DISABLE_AAMIX,
> -	ALC668_FIXUP_DELL_XPS13,
> -	ALC662_FIXUP_ASUS_Nx50,
> -	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
> -	ALC668_FIXUP_ASUS_Nx51,
> -	ALC668_FIXUP_MIC_COEF,
> -	ALC668_FIXUP_ASUS_G751,
> -	ALC891_FIXUP_HEADSET_MODE,
> -	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
> -	ALC662_FIXUP_ACER_VERITON,
> -	ALC892_FIXUP_ASROCK_MOBO,
> -	ALC662_FIXUP_USI_FUNC,
> -	ALC662_FIXUP_USI_HEADSET_MODE,
> -	ALC662_FIXUP_LENOVO_MULTI_CODECS,
> -	ALC669_FIXUP_ACER_ASPIRE_ETHOS,
> -	ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
> -	ALC671_FIXUP_HP_HEADSET_MIC2,
> -	ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
> -	ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
> -	ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
> -	ALC668_FIXUP_HEADSET_MIC,
> -	ALC668_FIXUP_MIC_DET_COEF,
> -	ALC897_FIXUP_LENOVO_HEADSET_MIC,
> -	ALC897_FIXUP_HEADSET_MIC_PIN,
> -	ALC897_FIXUP_HP_HSMIC_VERB,
> -	ALC897_FIXUP_LENOVO_HEADSET_MODE,
> -	ALC897_FIXUP_HEADSET_MIC_PIN2,
> -	ALC897_FIXUP_UNIS_H3C_X500S,
> -	ALC897_FIXUP_HEADSET_MIC_PIN3,
> -};
> -
> -static const struct hda_fixup alc662_fixups[] = {
> -	[ALC662_FIXUP_ASPIRE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x99130112 }, /* subwoofer */
> -			{ }
> -		}
> -	},
> -	[ALC662_FIXUP_LED_GPIO1] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc662_fixup_led_gpio1,
> -	},
> -	[ALC662_FIXUP_IDEAPAD] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x17, 0x99130112 }, /* subwoofer */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_LED_GPIO1,
> -	},
> -	[ALC272_FIXUP_MARIO] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc272_fixup_mario,
> -	},
> -	[ALC662_FIXUP_CZC_ET26] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{0x12, 0x403cc000},
> -			{0x14, 0x90170110}, /* speaker */
> -			{0x15, 0x411111f0},
> -			{0x16, 0x411111f0},
> -			{0x18, 0x01a19030}, /* mic */
> -			{0x19, 0x90a7013f}, /* int-mic */
> -			{0x1a, 0x01014020},
> -			{0x1b, 0x0121401f},
> -			{0x1c, 0x411111f0},
> -			{0x1d, 0x411111f0},
> -			{0x1e, 0x40478e35},
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_CZC_P10T] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
> -			{}
> -		}
> -	},
> -	[ALC662_FIXUP_SKU_IGNORE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_sku_ignore,
> -	},
> -	[ALC662_FIXUP_HP_RP5800] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x0221201f }, /* HP out */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE1] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x18, 0x01a19c20 }, /* mic */
> -			{ 0x19, 0x99a3092f }, /* int-mic */
> -			{ 0x21, 0x0121401f }, /* HP out */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE2] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x18, 0x01a19820 }, /* mic */
> -			{ 0x19, 0x99a3092f }, /* int-mic */
> -			{ 0x1b, 0x0121401f }, /* HP out */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE3] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x15, 0x0121441f }, /* HP */
> -			{ 0x18, 0x01a19840 }, /* mic */
> -			{ 0x19, 0x99a3094f }, /* int-mic */
> -			{ 0x21, 0x01211420 }, /* HP2 */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE4] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x16, 0x99130111 }, /* speaker */
> -			{ 0x18, 0x01a19840 }, /* mic */
> -			{ 0x19, 0x99a3094f }, /* int-mic */
> -			{ 0x21, 0x0121441f }, /* HP */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE5] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x15, 0x0121441f }, /* HP */
> -			{ 0x16, 0x99130111 }, /* speaker */
> -			{ 0x18, 0x01a19840 }, /* mic */
> -			{ 0x19, 0x99a3094f }, /* int-mic */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE6] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x15, 0x01211420 }, /* HP2 */
> -			{ 0x18, 0x01a19840 }, /* mic */
> -			{ 0x19, 0x99a3094f }, /* int-mic */
> -			{ 0x1b, 0x0121441f }, /* HP */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE7] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x17, 0x99130111 }, /* speaker */
> -			{ 0x18, 0x01a19840 }, /* mic */
> -			{ 0x19, 0x99a3094f }, /* int-mic */
> -			{ 0x1b, 0x01214020 }, /* HP */
> -			{ 0x21, 0x0121401f }, /* HP */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_ASUS_MODE8] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x14, 0x99130110 }, /* speaker */
> -			{ 0x12, 0x99a30970 }, /* int-mic */
> -			{ 0x15, 0x01214020 }, /* HP */
> -			{ 0x17, 0x99130111 }, /* speaker */
> -			{ 0x18, 0x01a19840 }, /* mic */
> -			{ 0x21, 0x0121401f }, /* HP */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_SKU_IGNORE
> -	},
> -	[ALC662_FIXUP_NO_JACK_DETECT] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_no_jack_detect,
> -	},
> -	[ALC662_FIXUP_ZOTAC_Z68] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1b, 0x02214020 }, /* Front HP */
> -			{ }
> -		}
> -	},
> -	[ALC662_FIXUP_INV_DMIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_inv_dmic,
> -	},
> -	[ALC668_FIXUP_DELL_XPS13] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_dell_xps13,
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
> -	},
> -	[ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_disable_aamix,
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
> -	},
> -	[ALC668_FIXUP_AUTO_MUTE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_auto_mute_via_amp,
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
> -	},
> -	[ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> -			/* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_HEADSET_MODE
> -	},
> -	[ALC662_FIXUP_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_headset_mode_alc662,
> -	},
> -	[ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
> -			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_HEADSET_MODE
> -	},
> -	[ALC668_FIXUP_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_headset_mode_alc668,
> -	},
> -	[ALC662_FIXUP_BASS_MODE4_CHMAP] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_bass_chmap,
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_ASUS_MODE4
> -	},
> -	[ALC662_FIXUP_BASS_16] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{0x16, 0x80106111}, /* bass speaker */
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_BASS_CHMAP,
> -	},
> -	[ALC662_FIXUP_BASS_1A] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{0x1a, 0x80106111}, /* bass speaker */
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_BASS_CHMAP,
> -	},
> -	[ALC662_FIXUP_BASS_CHMAP] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_bass_chmap,
> -	},
> -	[ALC662_FIXUP_ASUS_Nx50] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_auto_mute_via_amp,
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_BASS_1A
> -	},
> -	[ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_headset_mode_alc668,
> -		.chain_id = ALC662_FIXUP_BASS_CHMAP
> -	},
> -	[ALC668_FIXUP_ASUS_Nx51] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
> -			{ 0x1a, 0x90170151 }, /* bass speaker */
> -			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
> -	},
> -	[ALC668_FIXUP_MIC_COEF] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
> -			{}
> -		},
> -	},
> -	[ALC668_FIXUP_ASUS_G751] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x16, 0x0421101f }, /* HP */
> -			{}
> -		},
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_MIC_COEF
> -	},
> -	[ALC891_FIXUP_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc_fixup_headset_mode,
> -	},
> -	[ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
> -			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC891_FIXUP_HEADSET_MODE
> -	},
> -	[ALC662_FIXUP_ACER_VERITON] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x50170120 }, /* no internal speaker */
> -			{ }
> -		}
> -	},
> -	[ALC892_FIXUP_ASROCK_MOBO] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x40f000f0 }, /* disabled */
> -			{ 0x16, 0x40f000f0 }, /* disabled */
> -			{ }
> -		}
> -	},
> -	[ALC662_FIXUP_USI_FUNC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc662_fixup_usi_headset_mic,
> -	},
> -	[ALC662_FIXUP_USI_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
> -			{ 0x18, 0x01a1903d },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_USI_FUNC
> -	},
> -	[ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc233_alc662_fixup_lenovo_dual_codecs,
> -	},
> -	[ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc662_fixup_aspire_ethos_hp,
> -	},
> -	[ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x15, 0x92130110 }, /* front speakers */
> -			{ 0x18, 0x99130111 }, /* center/subwoofer */
> -			{ 0x1b, 0x11130012 }, /* surround plus jack for HP */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
> -	},
> -	[ALC671_FIXUP_HP_HEADSET_MIC2] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc671_fixup_hp_headset_mic2,
> -	},
> -	[ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_USI_FUNC
> -	},
> -	[ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
> -			{ 0x1b, 0x0221144f },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC662_FIXUP_USI_FUNC
> -	},
> -	[ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1b, 0x04a1112c },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_HEADSET_MIC
> -	},
> -	[ALC668_FIXUP_HEADSET_MIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc269_fixup_headset_mic,
> -		.chained = true,
> -		.chain_id = ALC668_FIXUP_MIC_DET_COEF
> -	},
> -	[ALC668_FIXUP_MIC_DET_COEF] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
> -			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
> -			{}
> -		},
> -	},
> -	[ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc897_fixup_lenovo_headset_mic,
> -	},
> -	[ALC897_FIXUP_HEADSET_MIC_PIN] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1a, 0x03a11050 },
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
> -	},
> -	[ALC897_FIXUP_HP_HSMIC_VERB] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
> -			{ }
> -		},
> -	},
> -	[ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
> -		.type = HDA_FIXUP_FUNC,
> -		.v.func = alc897_fixup_lenovo_headset_mode,
> -	},
> -	[ALC897_FIXUP_HEADSET_MIC_PIN2] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
> -			{ }
> -		},
> -		.chained = true,
> -		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
> -	},
> -	[ALC897_FIXUP_UNIS_H3C_X500S] = {
> -		.type = HDA_FIXUP_VERBS,
> -		.v.verbs = (const struct hda_verb[]) {
> -			{ 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
> -			{}
> -		},
> -	},
> -	[ALC897_FIXUP_HEADSET_MIC_PIN3] = {
> -		.type = HDA_FIXUP_PINS,
> -		.v.pins = (const struct hda_pintbl[]) {
> -			{ 0x19, 0x03a11050 }, /* use as headset mic */
> -			{ }
> -		},
> -	},
> -};
> -
> -static const struct hda_quirk alc662_fixup_tbl[] = {
> -	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
> -	SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
> -	SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
> -	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
> -	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
> -	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
> -	SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
> -	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
> -	SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
> -	SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
> -	SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
> -	SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
> -	SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
> -	SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
> -	SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> -	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
> -	SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
> -	SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
> -	SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
> -	SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
> -	SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
> -	SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
> -	SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
> -	SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
> -	SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
> -	SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
> -	SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
> -	SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
> -	SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
> -	SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
> -	SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
> -	SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
> -	SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
> -	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
> -	SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
> -	SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
> -	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
> -	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
> -	SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
> -	SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
> -	SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
> -	SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
> -	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
> -	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
> -	SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
> -	SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
> -	SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
> -	SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
> -	SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
> -	SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
> -
> -#if 0
> -	/* Below is a quirk table taken from the old code.
> -	 * Basically the device should work as is without the fixup table.
> -	 * If BIOS doesn't give a proper info, enable the corresponding
> -	 * fixup entry.
> -	 */
> -	SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
> -	SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
> -	SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
> -	SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
> -	SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
> -	SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
> -	SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
> -	SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
> -	SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
> -	SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> -	SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
> -#endif
> -	{}
> -};
> -
> -static const struct hda_model_fixup alc662_fixup_models[] = {
> -	{.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
> -	{.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
> -	{.id = ALC272_FIXUP_MARIO, .name = "mario"},
> -	{.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
> -	{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
> -	{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
> -	{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
> -	{.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
> -	{.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
> -	{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
> -	{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
> -	{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
> -	{.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
> -	{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
> -	{.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
> -	{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
> -	{.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
> -	{.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
> -	{.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
> -	{.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
> -	{.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
> -	{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
> -	{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
> -	{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
> -	{.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
> -	{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
> -	{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
> -	{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
> -	{.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
> -	{.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
> -	{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
> -	{.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
> -	{.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
> -	{}
> -};
> -
> -static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
> -	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
> -		{0x17, 0x02211010},
> -		{0x18, 0x01a19030},
> -		{0x1a, 0x01813040},
> -		{0x21, 0x01014020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
> -		{0x16, 0x01813030},
> -		{0x17, 0x02211010},
> -		{0x18, 0x01a19040},
> -		{0x21, 0x01014020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
> -		{0x14, 0x01014010},
> -		{0x18, 0x01a19020},
> -		{0x1a, 0x0181302f},
> -		{0x1b, 0x0221401f}),
> -	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> -		{0x12, 0x99a30130},
> -		{0x14, 0x90170110},
> -		{0x15, 0x0321101f},
> -		{0x16, 0x03011020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> -		{0x12, 0x99a30140},
> -		{0x14, 0x90170110},
> -		{0x15, 0x0321101f},
> -		{0x16, 0x03011020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> -		{0x12, 0x99a30150},
> -		{0x14, 0x90170110},
> -		{0x15, 0x0321101f},
> -		{0x16, 0x03011020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> -		{0x14, 0x90170110},
> -		{0x15, 0x0321101f},
> -		{0x16, 0x03011020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
> -		{0x12, 0x90a60130},
> -		{0x14, 0x90170110},
> -		{0x15, 0x0321101f}),
> -	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
> -		{0x14, 0x01014010},
> -		{0x17, 0x90170150},
> -		{0x19, 0x02a11060},
> -		{0x1b, 0x01813030},
> -		{0x21, 0x02211020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
> -		{0x14, 0x01014010},
> -		{0x18, 0x01a19040},
> -		{0x1b, 0x01813030},
> -		{0x21, 0x02211020}),
> -	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
> -		{0x14, 0x01014020},
> -		{0x17, 0x90170110},
> -		{0x18, 0x01a19050},
> -		{0x1b, 0x01813040},
> -		{0x21, 0x02211030}),
> -	{}
> -};
> -
> -/*
> - */
> -static int patch_alc662(struct hda_codec *codec)
> -{
> -	struct alc_spec *spec;
> -	int err;
> -
> -	err = alc_alloc_spec(codec, 0x0b);
> -	if (err < 0)
> -		return err;
> -
> -	spec = codec->spec;
> -
> -	spec->shutup = alc_eapd_shutup;
> -
> -	/* handle multiple HPs as is */
> -	spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
> -
> -	alc_fix_pll_init(codec, 0x20, 0x04, 15);
> -
> -	switch (codec->core.vendor_id) {
> -	case 0x10ec0668:
> -		spec->init_hook = alc668_restore_default_value;
> -		break;
> -	}
> -
> -	alc_pre_init(codec);
> -
> -	snd_hda_pick_fixup(codec, alc662_fixup_models,
> -		       alc662_fixup_tbl, alc662_fixups);
> -	snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> -
> -	alc_auto_parse_customize_define(codec);
> -
> -	if (has_cdefine_beep(codec))
> -		spec->gen.beep_nid = 0x01;
> -
> -	if ((alc_get_coef0(codec) & (1 << 14)) &&
> -	    codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
> -	    spec->cdefine.platform_type == 1) {
> -		err = alc_codec_rename(codec, "ALC272X");
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc662_parse_auto_config(codec);
> -	if (err < 0)
> -		goto error;
> -
> -	if (!spec->gen.no_analog && spec->gen.beep_nid) {
> -		switch (codec->core.vendor_id) {
> -		case 0x10ec0662:
> -			err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> -			break;
> -		case 0x10ec0272:
> -		case 0x10ec0663:
> -		case 0x10ec0665:
> -		case 0x10ec0668:
> -			err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
> -			break;
> -		case 0x10ec0273:
> -			err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
> -			break;
> -		}
> -		if (err < 0)
> -			goto error;
> -	}
> -
> -	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> -
> -	return 0;
> -
> - error:
> -	alc_free(codec);
> -	return err;
> -}
> -
> -/*
> - * ALC680 support
> - */
> -
> -static int alc680_parse_auto_config(struct hda_codec *codec)
> -{
> -	return alc_parse_auto_config(codec, NULL, NULL);
> -}
> -
> -/*
> - */
> -static int patch_alc680(struct hda_codec *codec)
> -{
> -	int err;
> -
> -	/* ALC680 has no aa-loopback mixer */
> -	err = alc_alloc_spec(codec, 0);
> -	if (err < 0)
> -		return err;
> -
> -	/* automatic parse from the BIOS config */
> -	err = alc680_parse_auto_config(codec);
> -	if (err < 0) {
> -		alc_free(codec);
> -		return err;
> -	}
> -
> -	return 0;
> -}
> -
> -/*
> - * patch entries
> - */
> -static const struct hda_device_id snd_hda_id_realtek[] = {
> +static const struct hda_device_id snd_hda_id_alc269[] = {
>   	HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
> @@ -13714,13 +8089,8 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
>   	HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
> -	HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
> -	HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
> -	HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
> -	HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
>   	HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
> -	HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
>   	HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
> @@ -13742,53 +8112,22 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
>   	HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269),
> -	HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
> -	HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
> -	HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
> -	HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
> -	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
> -	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
> -	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
>   	HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
>   	HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269),
> -	HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
> -	HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
> -	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
> -	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
> -	HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
> -	HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
> -	HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
>   	HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269),
>   	{} /* terminator */
>   };
> -MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc269);
>   
>   MODULE_LICENSE("GPL");
> -MODULE_DESCRIPTION("Realtek HD-audio codec");
> +MODULE_DESCRIPTION("Realtek ALC269 and compatible HD-audio codecs");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
>   MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
>   
> -static struct hda_codec_driver realtek_driver = {
> -	.id = snd_hda_id_realtek,
> +static struct hda_codec_driver alc269_driver = {
> +	.id = snd_hda_id_alc269,
>   };
>   
> -module_hda_codec_driver(realtek_driver);
> +module_hda_codec_driver(alc269_driver);
> diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
> new file mode 100644
> index 000000000000..94e4a313e5e2
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc662.c
> @@ -0,0 +1,1102 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC662 and compatible codecs
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +/*
> + * ALC662 support
> + *
> + * ALC662 is almost identical with ALC880 but has cleaner and more flexible
> + * configuration.  Each pin widget can choose any input DACs and a mixer.
> + * Each ADC is connected from a mixer of all inputs.  This makes possible
> + * 6-channel independent captures.
> + *
> + * In addition, an independent DAC for the multi-playback (not used in this
> + * driver yet).
> + */
> +
> +/*
> + * BIOS auto configuration
> + */
> +
> +static int alc662_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
> +	static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
> +	static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> +	const hda_nid_t *ssids;
> +
> +	if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
> +	    codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
> +	    codec->core.vendor_id == 0x10ec0671)
> +		ssids = alc663_ssids;
> +	else
> +		ssids = alc662_ssids;
> +	return alc_parse_auto_config(codec, alc662_ignore, ssids);
> +}
> +
> +static void alc272_fixup_mario(struct hda_codec *codec,
> +			       const struct hda_fixup *fix, int action)
> +{
> +	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> +		return;
> +	if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
> +				      (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
> +				      (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
> +				      (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
> +				      (0 << AC_AMPCAP_MUTE_SHIFT)))
> +		codec_warn(codec, "failed to override amp caps for NID 0x2\n");
> +}
> +
> +/* avoid D3 for keeping GPIO up */
> +static unsigned int gpio_led_power_filter(struct hda_codec *codec,
> +					  hda_nid_t nid,
> +					  unsigned int power_state)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
> +		return AC_PWRST_D0;
> +	return power_state;
> +}
> +
> +static void alc662_fixup_led_gpio1(struct hda_codec *codec,
> +				   const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->mute_led_polarity = 1;
> +		codec->power_filter = gpio_led_power_filter;
> +	}
> +}
> +
> +static void alc662_usi_automute_hook(struct hda_codec *codec,
> +					 struct hda_jack_callback *jack)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	int vref;
> +	msleep(200);
> +	snd_hda_gen_hp_automute(codec, jack);
> +
> +	vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
> +	msleep(100);
> +	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
> +			    vref);
> +}
> +
> +static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +		spec->gen.hp_automute_hook = alc662_usi_automute_hook;
> +	}
> +}
> +
> +static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
> +					struct hda_jack_callback *cb)
> +{
> +	/* surround speakers at 0x1b already get muted automatically when
> +	 * headphones are plugged in, but we have to mute/unmute the remaining
> +	 * channels manually:
> +	 * 0x15 - front left/front right
> +	 * 0x18 - front center/ LFE
> +	 */
> +	if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
> +		snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
> +		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
> +	} else {
> +		snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
> +		snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
> +	}
> +}
> +
> +static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
> +					const struct hda_fixup *fix, int action)
> +{
> +    /* Pin 0x1b: shared headphones jack and surround speakers */
> +	if (!is_jack_detectable(codec, 0x1b))
> +		return;
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		snd_hda_jack_detect_enable_callback(codec, 0x1b,
> +				alc662_aspire_ethos_mute_speakers);
> +		/* subwoofer needs an extra GPIO setting to become audible */
> +		alc_setup_gpio(codec, 0x02);
> +		break;
> +	case HDA_FIXUP_ACT_INIT:
> +		/* Make sure to start in a correct state, i.e. if
> +		 * headphones have been plugged in before powering up the system
> +		 */
> +		alc662_aspire_ethos_mute_speakers(codec, NULL);
> +		break;
> +	}
> +}
> +
> +static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
> +					     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	static const struct hda_pintbl pincfgs[] = {
> +		{ 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
> +		{ 0x1b, 0x0181304f },
> +		{ }
> +	};
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		spec->gen.mixer_nid = 0;
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +		snd_hda_apply_pincfgs(codec, pincfgs);
> +		break;
> +	case HDA_FIXUP_ACT_INIT:
> +		alc_write_coef_idx(codec, 0x19, 0xa054);
> +		break;
> +	}
> +}
> +
> +static void alc897_hp_automute_hook(struct hda_codec *codec,
> +					 struct hda_jack_callback *jack)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	int vref;
> +
> +	snd_hda_gen_hp_automute(codec, jack);
> +	vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
> +	snd_hda_set_pin_ctl(codec, 0x1b, vref);
> +}
> +
> +static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
> +		spec->no_shutup_pins = 1;
> +	}
> +	if (action == HDA_FIXUP_ACT_PROBE) {
> +		snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
> +	}
> +}
> +
> +static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +		spec->gen.hp_automute_hook = alc897_hp_automute_hook;
> +	}
> +}
> +
> +static const struct coef_fw alc668_coefs[] = {
> +	WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
> +	WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
> +	WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b,    0x0),
> +	WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
> +	WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
> +	WRITE_COEF(0x13,    0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
> +	WRITE_COEF(0x19,    0x0), WRITE_COEF(0x1a,    0x0), WRITE_COEF(0x1b,    0x0),
> +	WRITE_COEF(0x1c,    0x0), WRITE_COEF(0x1d,    0x0), WRITE_COEF(0x1e, 0x7418),
> +	WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
> +	WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
> +	WRITE_COEF(0x27,    0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
> +	WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
> +	WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac,    0x0),
> +	WRITE_COEF(0xad,    0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
> +	WRITE_COEF(0xb0,    0x0), WRITE_COEF(0xb1,    0x0), WRITE_COEF(0xb2,    0x0),
> +	WRITE_COEF(0xb3,    0x0), WRITE_COEF(0xb4,    0x0), WRITE_COEF(0xb5, 0x1040),
> +	WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
> +	WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
> +	WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
> +	WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
> +	{}
> +};
> +
> +static void alc668_restore_default_value(struct hda_codec *codec)
> +{
> +	alc_process_coef_fw(codec, alc668_coefs);
> +}
> +
> +static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
> +				const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +		spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
> +
> +		/* Disable boost for mic-in permanently. (This code is only called
> +		   from quirks that guarantee that the headphone is at NID 0x1b.) */
> +		snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
> +		snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
> +	} else
> +		alc_fixup_headset_mode(codec, fix, action);
> +}
> +
> +static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
> +				const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		alc_write_coef_idx(codec, 0xc4, 0x8000);
> +		alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
> +		snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
> +	}
> +	alc_fixup_headset_mode(codec, fix, action);
> +}
> +
> +enum {
> +	ALC662_FIXUP_ASPIRE,
> +	ALC662_FIXUP_LED_GPIO1,
> +	ALC662_FIXUP_IDEAPAD,
> +	ALC272_FIXUP_MARIO,
> +	ALC662_FIXUP_CZC_ET26,
> +	ALC662_FIXUP_CZC_P10T,
> +	ALC662_FIXUP_SKU_IGNORE,
> +	ALC662_FIXUP_HP_RP5800,
> +	ALC662_FIXUP_ASUS_MODE1,
> +	ALC662_FIXUP_ASUS_MODE2,
> +	ALC662_FIXUP_ASUS_MODE3,
> +	ALC662_FIXUP_ASUS_MODE4,
> +	ALC662_FIXUP_ASUS_MODE5,
> +	ALC662_FIXUP_ASUS_MODE6,
> +	ALC662_FIXUP_ASUS_MODE7,
> +	ALC662_FIXUP_ASUS_MODE8,
> +	ALC662_FIXUP_NO_JACK_DETECT,
> +	ALC662_FIXUP_ZOTAC_Z68,
> +	ALC662_FIXUP_INV_DMIC,
> +	ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
> +	ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
> +	ALC662_FIXUP_HEADSET_MODE,
> +	ALC668_FIXUP_HEADSET_MODE,
> +	ALC662_FIXUP_BASS_MODE4_CHMAP,
> +	ALC662_FIXUP_BASS_16,
> +	ALC662_FIXUP_BASS_1A,
> +	ALC662_FIXUP_BASS_CHMAP,
> +	ALC668_FIXUP_AUTO_MUTE,
> +	ALC668_FIXUP_DELL_DISABLE_AAMIX,
> +	ALC668_FIXUP_DELL_XPS13,
> +	ALC662_FIXUP_ASUS_Nx50,
> +	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
> +	ALC668_FIXUP_ASUS_Nx51,
> +	ALC668_FIXUP_MIC_COEF,
> +	ALC668_FIXUP_ASUS_G751,
> +	ALC891_FIXUP_HEADSET_MODE,
> +	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
> +	ALC662_FIXUP_ACER_VERITON,
> +	ALC892_FIXUP_ASROCK_MOBO,
> +	ALC662_FIXUP_USI_FUNC,
> +	ALC662_FIXUP_USI_HEADSET_MODE,
> +	ALC662_FIXUP_LENOVO_MULTI_CODECS,
> +	ALC669_FIXUP_ACER_ASPIRE_ETHOS,
> +	ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
> +	ALC671_FIXUP_HP_HEADSET_MIC2,
> +	ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
> +	ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
> +	ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
> +	ALC668_FIXUP_HEADSET_MIC,
> +	ALC668_FIXUP_MIC_DET_COEF,
> +	ALC897_FIXUP_LENOVO_HEADSET_MIC,
> +	ALC897_FIXUP_HEADSET_MIC_PIN,
> +	ALC897_FIXUP_HP_HSMIC_VERB,
> +	ALC897_FIXUP_LENOVO_HEADSET_MODE,
> +	ALC897_FIXUP_HEADSET_MIC_PIN2,
> +	ALC897_FIXUP_UNIS_H3C_X500S,
> +	ALC897_FIXUP_HEADSET_MIC_PIN3,
> +};
> +
> +static const struct hda_fixup alc662_fixups[] = {
> +	[ALC662_FIXUP_ASPIRE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x99130112 }, /* subwoofer */
> +			{ }
> +		}
> +	},
> +	[ALC662_FIXUP_LED_GPIO1] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc662_fixup_led_gpio1,
> +	},
> +	[ALC662_FIXUP_IDEAPAD] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x17, 0x99130112 }, /* subwoofer */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_LED_GPIO1,
> +	},
> +	[ALC272_FIXUP_MARIO] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc272_fixup_mario,
> +	},
> +	[ALC662_FIXUP_CZC_ET26] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{0x12, 0x403cc000},
> +			{0x14, 0x90170110}, /* speaker */
> +			{0x15, 0x411111f0},
> +			{0x16, 0x411111f0},
> +			{0x18, 0x01a19030}, /* mic */
> +			{0x19, 0x90a7013f}, /* int-mic */
> +			{0x1a, 0x01014020},
> +			{0x1b, 0x0121401f},
> +			{0x1c, 0x411111f0},
> +			{0x1d, 0x411111f0},
> +			{0x1e, 0x40478e35},
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_CZC_P10T] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
> +			{}
> +		}
> +	},
> +	[ALC662_FIXUP_SKU_IGNORE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_sku_ignore,
> +	},
> +	[ALC662_FIXUP_HP_RP5800] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x0221201f }, /* HP out */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE1] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x18, 0x01a19c20 }, /* mic */
> +			{ 0x19, 0x99a3092f }, /* int-mic */
> +			{ 0x21, 0x0121401f }, /* HP out */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE2] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x18, 0x01a19820 }, /* mic */
> +			{ 0x19, 0x99a3092f }, /* int-mic */
> +			{ 0x1b, 0x0121401f }, /* HP out */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE3] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x15, 0x0121441f }, /* HP */
> +			{ 0x18, 0x01a19840 }, /* mic */
> +			{ 0x19, 0x99a3094f }, /* int-mic */
> +			{ 0x21, 0x01211420 }, /* HP2 */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE4] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x16, 0x99130111 }, /* speaker */
> +			{ 0x18, 0x01a19840 }, /* mic */
> +			{ 0x19, 0x99a3094f }, /* int-mic */
> +			{ 0x21, 0x0121441f }, /* HP */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE5] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x15, 0x0121441f }, /* HP */
> +			{ 0x16, 0x99130111 }, /* speaker */
> +			{ 0x18, 0x01a19840 }, /* mic */
> +			{ 0x19, 0x99a3094f }, /* int-mic */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE6] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x15, 0x01211420 }, /* HP2 */
> +			{ 0x18, 0x01a19840 }, /* mic */
> +			{ 0x19, 0x99a3094f }, /* int-mic */
> +			{ 0x1b, 0x0121441f }, /* HP */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE7] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x17, 0x99130111 }, /* speaker */
> +			{ 0x18, 0x01a19840 }, /* mic */
> +			{ 0x19, 0x99a3094f }, /* int-mic */
> +			{ 0x1b, 0x01214020 }, /* HP */
> +			{ 0x21, 0x0121401f }, /* HP */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_ASUS_MODE8] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x99130110 }, /* speaker */
> +			{ 0x12, 0x99a30970 }, /* int-mic */
> +			{ 0x15, 0x01214020 }, /* HP */
> +			{ 0x17, 0x99130111 }, /* speaker */
> +			{ 0x18, 0x01a19840 }, /* mic */
> +			{ 0x21, 0x0121401f }, /* HP */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_SKU_IGNORE
> +	},
> +	[ALC662_FIXUP_NO_JACK_DETECT] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_no_jack_detect,
> +	},
> +	[ALC662_FIXUP_ZOTAC_Z68] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1b, 0x02214020 }, /* Front HP */
> +			{ }
> +		}
> +	},
> +	[ALC662_FIXUP_INV_DMIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_inv_dmic,
> +	},
> +	[ALC668_FIXUP_DELL_XPS13] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_dell_xps13,
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
> +	},
> +	[ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_disable_aamix,
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
> +	},
> +	[ALC668_FIXUP_AUTO_MUTE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_auto_mute_via_amp,
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
> +	},
> +	[ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> +			/* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_HEADSET_MODE
> +	},
> +	[ALC662_FIXUP_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_headset_mode_alc662,
> +	},
> +	[ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
> +			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_HEADSET_MODE
> +	},
> +	[ALC668_FIXUP_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_headset_mode_alc668,
> +	},
> +	[ALC662_FIXUP_BASS_MODE4_CHMAP] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_bass_chmap,
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_ASUS_MODE4
> +	},
> +	[ALC662_FIXUP_BASS_16] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{0x16, 0x80106111}, /* bass speaker */
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_BASS_CHMAP,
> +	},
> +	[ALC662_FIXUP_BASS_1A] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{0x1a, 0x80106111}, /* bass speaker */
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_BASS_CHMAP,
> +	},
> +	[ALC662_FIXUP_BASS_CHMAP] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_bass_chmap,
> +	},
> +	[ALC662_FIXUP_ASUS_Nx50] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_auto_mute_via_amp,
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_BASS_1A
> +	},
> +	[ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_headset_mode_alc668,
> +		.chain_id = ALC662_FIXUP_BASS_CHMAP
> +	},
> +	[ALC668_FIXUP_ASUS_Nx51] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
> +			{ 0x1a, 0x90170151 }, /* bass speaker */
> +			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
> +	},
> +	[ALC668_FIXUP_MIC_COEF] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
> +			{}
> +		},
> +	},
> +	[ALC668_FIXUP_ASUS_G751] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x16, 0x0421101f }, /* HP */
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_MIC_COEF
> +	},
> +	[ALC891_FIXUP_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_headset_mode,
> +	},
> +	[ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
> +			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC891_FIXUP_HEADSET_MODE
> +	},
> +	[ALC662_FIXUP_ACER_VERITON] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x50170120 }, /* no internal speaker */
> +			{ }
> +		}
> +	},
> +	[ALC892_FIXUP_ASROCK_MOBO] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x40f000f0 }, /* disabled */
> +			{ 0x16, 0x40f000f0 }, /* disabled */
> +			{ }
> +		}
> +	},
> +	[ALC662_FIXUP_USI_FUNC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc662_fixup_usi_headset_mic,
> +	},
> +	[ALC662_FIXUP_USI_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
> +			{ 0x18, 0x01a1903d },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_USI_FUNC
> +	},
> +	[ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc233_alc662_fixup_lenovo_dual_codecs,
> +	},
> +	[ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc662_fixup_aspire_ethos_hp,
> +	},
> +	[ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x92130110 }, /* front speakers */
> +			{ 0x18, 0x99130111 }, /* center/subwoofer */
> +			{ 0x1b, 0x11130012 }, /* surround plus jack for HP */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
> +	},
> +	[ALC671_FIXUP_HP_HEADSET_MIC2] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc671_fixup_hp_headset_mic2,
> +	},
> +	[ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_USI_FUNC
> +	},
> +	[ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
> +			{ 0x1b, 0x0221144f },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC662_FIXUP_USI_FUNC
> +	},
> +	[ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1b, 0x04a1112c },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_HEADSET_MIC
> +	},
> +	[ALC668_FIXUP_HEADSET_MIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_headset_mic,
> +		.chained = true,
> +		.chain_id = ALC668_FIXUP_MIC_DET_COEF
> +	},
> +	[ALC668_FIXUP_MIC_DET_COEF] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
> +			{}
> +		},
> +	},
> +	[ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc897_fixup_lenovo_headset_mic,
> +	},
> +	[ALC897_FIXUP_HEADSET_MIC_PIN] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1a, 0x03a11050 },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
> +	},
> +	[ALC897_FIXUP_HP_HSMIC_VERB] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
> +			{ }
> +		},
> +	},
> +	[ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc897_fixup_lenovo_headset_mode,
> +	},
> +	[ALC897_FIXUP_HEADSET_MIC_PIN2] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
> +	},
> +	[ALC897_FIXUP_UNIS_H3C_X500S] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
> +			{}
> +		},
> +	},
> +	[ALC897_FIXUP_HEADSET_MIC_PIN3] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x03a11050 }, /* use as headset mic */
> +			{ }
> +		},
> +	},
> +};
> +
> +static const struct hda_quirk alc662_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
> +	SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
> +	SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
> +	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
> +	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
> +	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
> +	SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
> +	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
> +	SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
> +	SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
> +	SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
> +	SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
> +	SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
> +	SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
> +	SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
> +	SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
> +	SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
> +	SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
> +	SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
> +	SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
> +	SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
> +	SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
> +	SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
> +	SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
> +	SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
> +	SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
> +	SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
> +	SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
> +	SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
> +	SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
> +	SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
> +	SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
> +	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
> +	SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
> +	SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
> +	SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
> +	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
> +	SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
> +	SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
> +	SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
> +	SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
> +	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
> +	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
> +	SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
> +	SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
> +	SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
> +	SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
> +	SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
> +	SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
> +
> +#if 0
> +	/* Below is a quirk table taken from the old code.
> +	 * Basically the device should work as is without the fixup table.
> +	 * If BIOS doesn't give a proper info, enable the corresponding
> +	 * fixup entry.
> +	 */
> +	SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
> +	SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
> +	SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
> +	SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
> +	SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
> +	SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
> +	SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
> +	SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
> +	SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
> +	SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
> +	SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
> +#endif
> +	{}
> +};
> +
> +static const struct hda_model_fixup alc662_fixup_models[] = {
> +	{.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
> +	{.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
> +	{.id = ALC272_FIXUP_MARIO, .name = "mario"},
> +	{.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
> +	{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
> +	{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
> +	{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
> +	{.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
> +	{.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
> +	{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
> +	{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
> +	{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
> +	{.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
> +	{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
> +	{.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
> +	{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
> +	{.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
> +	{.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
> +	{.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
> +	{.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
> +	{.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
> +	{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
> +	{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
> +	{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
> +	{.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
> +	{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
> +	{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
> +	{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
> +	{.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
> +	{.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
> +	{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
> +	{.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
> +	{.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
> +	{}
> +};
> +
> +static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
> +	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
> +		{0x17, 0x02211010},
> +		{0x18, 0x01a19030},
> +		{0x1a, 0x01813040},
> +		{0x21, 0x01014020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
> +		{0x16, 0x01813030},
> +		{0x17, 0x02211010},
> +		{0x18, 0x01a19040},
> +		{0x21, 0x01014020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
> +		{0x14, 0x01014010},
> +		{0x18, 0x01a19020},
> +		{0x1a, 0x0181302f},
> +		{0x1b, 0x0221401f}),
> +	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> +		{0x12, 0x99a30130},
> +		{0x14, 0x90170110},
> +		{0x15, 0x0321101f},
> +		{0x16, 0x03011020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> +		{0x12, 0x99a30140},
> +		{0x14, 0x90170110},
> +		{0x15, 0x0321101f},
> +		{0x16, 0x03011020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> +		{0x12, 0x99a30150},
> +		{0x14, 0x90170110},
> +		{0x15, 0x0321101f},
> +		{0x16, 0x03011020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
> +		{0x14, 0x90170110},
> +		{0x15, 0x0321101f},
> +		{0x16, 0x03011020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
> +		{0x12, 0x90a60130},
> +		{0x14, 0x90170110},
> +		{0x15, 0x0321101f}),
> +	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
> +		{0x14, 0x01014010},
> +		{0x17, 0x90170150},
> +		{0x19, 0x02a11060},
> +		{0x1b, 0x01813030},
> +		{0x21, 0x02211020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
> +		{0x14, 0x01014010},
> +		{0x18, 0x01a19040},
> +		{0x1b, 0x01813030},
> +		{0x21, 0x02211020}),
> +	SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
> +		{0x14, 0x01014020},
> +		{0x17, 0x90170110},
> +		{0x18, 0x01a19050},
> +		{0x1b, 0x01813040},
> +		{0x21, 0x02211030}),
> +	{}
> +};
> +
> +/*
> + */
> +static int patch_alc662(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x0b);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +
> +	spec->shutup = alc_eapd_shutup;
> +
> +	/* handle multiple HPs as is */
> +	spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
> +
> +	alc_fix_pll_init(codec, 0x20, 0x04, 15);
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0668:
> +		spec->init_hook = alc668_restore_default_value;
> +		break;
> +	}
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, alc662_fixup_models,
> +		       alc662_fixup_tbl, alc662_fixups);
> +	snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	alc_auto_parse_customize_define(codec);
> +
> +	if (has_cdefine_beep(codec))
> +		spec->gen.beep_nid = 0x01;
> +
> +	if ((alc_get_coef0(codec) & (1 << 14)) &&
> +	    codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
> +	    spec->cdefine.platform_type == 1) {
> +		err = alc_codec_rename(codec, "ALC272X");
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc662_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog && spec->gen.beep_nid) {
> +		switch (codec->core.vendor_id) {
> +		case 0x10ec0662:
> +			err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> +			break;
> +		case 0x10ec0272:
> +		case 0x10ec0663:
> +		case 0x10ec0665:
> +		case 0x10ec0668:
> +			err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
> +			break;
> +		case 0x10ec0273:
> +			err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
> +			break;
> +		}
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc662[] = {
> +	HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
> +	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
> +	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
> +	HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc662);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC662 and compatible HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc662_driver = {
> +	.id = snd_hda_id_alc662,
> +};
> +
> +module_hda_codec_driver(alc662_driver);
> diff --git a/sound/hda/codecs/realtek/alc680.c b/sound/hda/codecs/realtek/alc680.c
> new file mode 100644
> index 000000000000..baf19ee3bc2f
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc680.c
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC680 codec
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +static int alc680_parse_auto_config(struct hda_codec *codec)
> +{
> +	return alc_parse_auto_config(codec, NULL, NULL);
> +}
> +
> +/*
> + */
> +static int patch_alc680(struct hda_codec *codec)
> +{
> +	int err;
> +
> +	/* ALC680 has no aa-loopback mixer */
> +	err = alc_alloc_spec(codec, 0);
> +	if (err < 0)
> +		return err;
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc680_parse_auto_config(codec);
> +	if (err < 0) {
> +		alc_free(codec);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc680[] = {
> +	HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc680);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC680 HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc680_driver = {
> +	.id = snd_hda_id_alc680,
> +};
> +
> +module_hda_codec_driver(alc680_driver);
> diff --git a/sound/hda/codecs/realtek/alc861.c b/sound/hda/codecs/realtek/alc861.c
> new file mode 100644
> index 000000000000..0eb70b44dc05
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc861.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC861 codec
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +static int alc861_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
> +	static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
> +	return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
> +}
> +
> +/* Pin config fixes */
> +enum {
> +	ALC861_FIXUP_FSC_AMILO_PI1505,
> +	ALC861_FIXUP_AMP_VREF_0F,
> +	ALC861_FIXUP_NO_JACK_DETECT,
> +	ALC861_FIXUP_ASUS_A6RP,
> +	ALC660_FIXUP_ASUS_W7J,
> +};
> +
> +/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
> +static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
> +			const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	unsigned int val;
> +
> +	if (action != HDA_FIXUP_ACT_INIT)
> +		return;
> +	val = snd_hda_codec_get_pin_target(codec, 0x0f);
> +	if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
> +		val |= AC_PINCTL_IN_EN;
> +	val |= AC_PINCTL_VREF_50;
> +	snd_hda_set_pin_ctl(codec, 0x0f, val);
> +	spec->gen.keep_vref_in_automute = 1;
> +}
> +
> +static const struct hda_fixup alc861_fixups[] = {
> +	[ALC861_FIXUP_FSC_AMILO_PI1505] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x0b, 0x0221101f }, /* HP */
> +			{ 0x0f, 0x90170310 }, /* speaker */
> +			{ }
> +		}
> +	},
> +	[ALC861_FIXUP_AMP_VREF_0F] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc861_fixup_asus_amp_vref_0f,
> +	},
> +	[ALC861_FIXUP_NO_JACK_DETECT] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_no_jack_detect,
> +	},
> +	[ALC861_FIXUP_ASUS_A6RP] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc861_fixup_asus_amp_vref_0f,
> +		.chained = true,
> +		.chain_id = ALC861_FIXUP_NO_JACK_DETECT,
> +	},
> +	[ALC660_FIXUP_ASUS_W7J] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* ASUS W7J needs a magic pin setup on unused NID 0x10
> +			 * for enabling outputs
> +			 */
> +			{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
> +			{ }
> +		},
> +	}
> +};
> +
> +static const struct hda_quirk alc861_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
> +	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
> +	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
> +	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
> +	SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
> +	SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
> +	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
> +	{}
> +};
> +
> +/*
> + */
> +static int patch_alc861(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x15);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +	if (has_cdefine_beep(codec))
> +		spec->gen.beep_nid = 0x23;
> +
> +	spec->power_hook = alc_power_eapd;
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc861_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog) {
> +		err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc861[] = {
> +	HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
> +	HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC861 HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc861_driver = {
> +	.id = snd_hda_id_alc861,
> +};
> +
> +module_hda_codec_driver(alc861_driver);
> diff --git a/sound/hda/codecs/realtek/alc861vd.c b/sound/hda/codecs/realtek/alc861vd.c
> new file mode 100644
> index 000000000000..ebf274ad730b
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc861vd.c
> @@ -0,0 +1,123 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC861-VD codec
> +// Based on ALC882
> +// In addition, an independent DAC
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +static int alc861vd_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
> +	static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> +	return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
> +}
> +
> +enum {
> +	ALC660VD_FIX_ASUS_GPIO1,
> +	ALC861VD_FIX_DALLAS,
> +};
> +
> +/* exclude VREF80 */
> +static void alc861vd_fixup_dallas(struct hda_codec *codec,
> +				  const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
> +		snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
> +	}
> +}
> +
> +/* reset GPIO1 */
> +static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
> +				      const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +		spec->gpio_mask |= 0x02;
> +	alc_fixup_gpio(codec, action, 0x01);
> +}
> +
> +static const struct hda_fixup alc861vd_fixups[] = {
> +	[ALC660VD_FIX_ASUS_GPIO1] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc660vd_fixup_asus_gpio1,
> +	},
> +	[ALC861VD_FIX_DALLAS] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc861vd_fixup_dallas,
> +	},
> +};
> +
> +static const struct hda_quirk alc861vd_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
> +	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
> +	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
> +	{}
> +};
> +
> +/*
> + */
> +static int patch_alc861vd(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x0b);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +	if (has_cdefine_beep(codec))
> +		spec->gen.beep_nid = 0x23;
> +
> +	spec->shutup = alc_eapd_shutup;
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc861vd_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog) {
> +		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc861vd[] = {
> +	HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
> +	HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc861vd);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC861-VD HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc861vd_driver = {
> +	.id = snd_hda_id_alc861vd,
> +};
> +
> +module_hda_codec_driver(alc861vd_driver);
> diff --git a/sound/hda/codecs/realtek/alc880.c b/sound/hda/codecs/realtek/alc880.c
> new file mode 100644
> index 000000000000..2e828ab96dc5
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc880.c
> @@ -0,0 +1,497 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC880 codec
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
> +{
> +	/* For some reason, the res given from ALC880 is broken.
> +	   Here we adjust it properly. */
> +	snd_hda_jack_unsol_event(codec, res >> 2);
> +}
> +
> +static int alc880_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
> +	static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> +	return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
> +}
> +
> +/*
> + * ALC880 fix-ups
> + */
> +enum {
> +	ALC880_FIXUP_GPIO1,
> +	ALC880_FIXUP_GPIO2,
> +	ALC880_FIXUP_MEDION_RIM,
> +	ALC880_FIXUP_LG,
> +	ALC880_FIXUP_LG_LW25,
> +	ALC880_FIXUP_W810,
> +	ALC880_FIXUP_EAPD_COEF,
> +	ALC880_FIXUP_TCL_S700,
> +	ALC880_FIXUP_VOL_KNOB,
> +	ALC880_FIXUP_FUJITSU,
> +	ALC880_FIXUP_F1734,
> +	ALC880_FIXUP_UNIWILL,
> +	ALC880_FIXUP_UNIWILL_DIG,
> +	ALC880_FIXUP_Z71V,
> +	ALC880_FIXUP_ASUS_W5A,
> +	ALC880_FIXUP_3ST_BASE,
> +	ALC880_FIXUP_3ST,
> +	ALC880_FIXUP_3ST_DIG,
> +	ALC880_FIXUP_5ST_BASE,
> +	ALC880_FIXUP_5ST,
> +	ALC880_FIXUP_5ST_DIG,
> +	ALC880_FIXUP_6ST_BASE,
> +	ALC880_FIXUP_6ST,
> +	ALC880_FIXUP_6ST_DIG,
> +	ALC880_FIXUP_6ST_AUTOMUTE,
> +};
> +
> +/* enable the volume-knob widget support on NID 0x21 */
> +static void alc880_fixup_vol_knob(struct hda_codec *codec,
> +				  const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PROBE)
> +		snd_hda_jack_detect_enable_callback(codec, 0x21,
> +						    alc_update_knob_master);
> +}
> +
> +static const struct hda_fixup alc880_fixups[] = {
> +	[ALC880_FIXUP_GPIO1] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio1,
> +	},
> +	[ALC880_FIXUP_GPIO2] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio2,
> +	},
> +	[ALC880_FIXUP_MEDION_RIM] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_GPIO2,
> +	},
> +	[ALC880_FIXUP_LG] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			/* disable bogus unused pins */
> +			{ 0x16, 0x411111f0 },
> +			{ 0x18, 0x411111f0 },
> +			{ 0x1a, 0x411111f0 },
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_LG_LW25] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1a, 0x0181344f }, /* line-in */
> +			{ 0x1b, 0x0321403f }, /* headphone */
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_W810] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			/* disable bogus unused pins */
> +			{ 0x17, 0x411111f0 },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_GPIO2,
> +	},
> +	[ALC880_FIXUP_EAPD_COEF] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* change to EAPD mode */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
> +			{}
> +		},
> +	},
> +	[ALC880_FIXUP_TCL_S700] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* change to EAPD mode */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_GPIO2,
> +	},
> +	[ALC880_FIXUP_VOL_KNOB] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc880_fixup_vol_knob,
> +	},
> +	[ALC880_FIXUP_FUJITSU] = {
> +		/* override all pins as BIOS on old Amilo is broken */
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x0121401f }, /* HP */
> +			{ 0x15, 0x99030120 }, /* speaker */
> +			{ 0x16, 0x99030130 }, /* bass speaker */
> +			{ 0x17, 0x411111f0 }, /* N/A */
> +			{ 0x18, 0x411111f0 }, /* N/A */
> +			{ 0x19, 0x01a19950 }, /* mic-in */
> +			{ 0x1a, 0x411111f0 }, /* N/A */
> +			{ 0x1b, 0x411111f0 }, /* N/A */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			{ 0x1e, 0x01454140 }, /* SPDIF out */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_VOL_KNOB,
> +	},
> +	[ALC880_FIXUP_F1734] = {
> +		/* almost compatible with FUJITSU, but no bass and SPDIF */
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x0121401f }, /* HP */
> +			{ 0x15, 0x99030120 }, /* speaker */
> +			{ 0x16, 0x411111f0 }, /* N/A */
> +			{ 0x17, 0x411111f0 }, /* N/A */
> +			{ 0x18, 0x411111f0 }, /* N/A */
> +			{ 0x19, 0x01a19950 }, /* mic-in */
> +			{ 0x1a, 0x411111f0 }, /* N/A */
> +			{ 0x1b, 0x411111f0 }, /* N/A */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			{ 0x1e, 0x411111f0 }, /* N/A */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_VOL_KNOB,
> +	},
> +	[ALC880_FIXUP_UNIWILL] = {
> +		/* need to fix HP and speaker pins to be parsed correctly */
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x0121411f }, /* HP */
> +			{ 0x15, 0x99030120 }, /* speaker */
> +			{ 0x16, 0x99030130 }, /* bass speaker */
> +			{ }
> +		},
> +	},
> +	[ALC880_FIXUP_UNIWILL_DIG] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			/* disable bogus unused pins */
> +			{ 0x17, 0x411111f0 },
> +			{ 0x19, 0x411111f0 },
> +			{ 0x1b, 0x411111f0 },
> +			{ 0x1f, 0x411111f0 },
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_Z71V] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			/* set up the whole pins as BIOS is utterly broken */
> +			{ 0x14, 0x99030120 }, /* speaker */
> +			{ 0x15, 0x0121411f }, /* HP */
> +			{ 0x16, 0x411111f0 }, /* N/A */
> +			{ 0x17, 0x411111f0 }, /* N/A */
> +			{ 0x18, 0x01a19950 }, /* mic-in */
> +			{ 0x19, 0x411111f0 }, /* N/A */
> +			{ 0x1a, 0x01813031 }, /* line-in */
> +			{ 0x1b, 0x411111f0 }, /* N/A */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			{ 0x1e, 0x0144111e }, /* SPDIF */
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_ASUS_W5A] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			/* set up the whole pins as BIOS is utterly broken */
> +			{ 0x14, 0x0121411f }, /* HP */
> +			{ 0x15, 0x411111f0 }, /* N/A */
> +			{ 0x16, 0x411111f0 }, /* N/A */
> +			{ 0x17, 0x411111f0 }, /* N/A */
> +			{ 0x18, 0x90a60160 }, /* mic */
> +			{ 0x19, 0x411111f0 }, /* N/A */
> +			{ 0x1a, 0x411111f0 }, /* N/A */
> +			{ 0x1b, 0x411111f0 }, /* N/A */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			{ 0x1e, 0xb743111e }, /* SPDIF out */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_GPIO1,
> +	},
> +	[ALC880_FIXUP_3ST_BASE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x01014010 }, /* line-out */
> +			{ 0x15, 0x411111f0 }, /* N/A */
> +			{ 0x16, 0x411111f0 }, /* N/A */
> +			{ 0x17, 0x411111f0 }, /* N/A */
> +			{ 0x18, 0x01a19c30 }, /* mic-in */
> +			{ 0x19, 0x0121411f }, /* HP */
> +			{ 0x1a, 0x01813031 }, /* line-in */
> +			{ 0x1b, 0x02a19c40 }, /* front-mic */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			/* 0x1e is filled in below */
> +			{ 0x1f, 0x411111f0 }, /* N/A */
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_3ST] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x411111f0 }, /* N/A */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_3ST_BASE,
> +	},
> +	[ALC880_FIXUP_3ST_DIG] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x0144111e }, /* SPDIF */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_3ST_BASE,
> +	},
> +	[ALC880_FIXUP_5ST_BASE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x01014010 }, /* front */
> +			{ 0x15, 0x411111f0 }, /* N/A */
> +			{ 0x16, 0x01011411 }, /* CLFE */
> +			{ 0x17, 0x01016412 }, /* surr */
> +			{ 0x18, 0x01a19c30 }, /* mic-in */
> +			{ 0x19, 0x0121411f }, /* HP */
> +			{ 0x1a, 0x01813031 }, /* line-in */
> +			{ 0x1b, 0x02a19c40 }, /* front-mic */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			/* 0x1e is filled in below */
> +			{ 0x1f, 0x411111f0 }, /* N/A */
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_5ST] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x411111f0 }, /* N/A */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_5ST_BASE,
> +	},
> +	[ALC880_FIXUP_5ST_DIG] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x0144111e }, /* SPDIF */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_5ST_BASE,
> +	},
> +	[ALC880_FIXUP_6ST_BASE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x14, 0x01014010 }, /* front */
> +			{ 0x15, 0x01016412 }, /* surr */
> +			{ 0x16, 0x01011411 }, /* CLFE */
> +			{ 0x17, 0x01012414 }, /* side */
> +			{ 0x18, 0x01a19c30 }, /* mic-in */
> +			{ 0x19, 0x02a19c40 }, /* front-mic */
> +			{ 0x1a, 0x01813031 }, /* line-in */
> +			{ 0x1b, 0x0121411f }, /* HP */
> +			{ 0x1c, 0x411111f0 }, /* N/A */
> +			{ 0x1d, 0x411111f0 }, /* N/A */
> +			/* 0x1e is filled in below */
> +			{ 0x1f, 0x411111f0 }, /* N/A */
> +			{ }
> +		}
> +	},
> +	[ALC880_FIXUP_6ST] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x411111f0 }, /* N/A */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_6ST_BASE,
> +	},
> +	[ALC880_FIXUP_6ST_DIG] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1e, 0x0144111e }, /* SPDIF */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC880_FIXUP_6ST_BASE,
> +	},
> +	[ALC880_FIXUP_6ST_AUTOMUTE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1b, 0x0121401f }, /* HP with jack detect */
> +			{ }
> +		},
> +		.chained_before = true,
> +		.chain_id = ALC880_FIXUP_6ST_BASE,
> +	},
> +};
> +
> +static const struct hda_quirk alc880_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
> +	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
> +	SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
> +	SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
> +	SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
> +	SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
> +	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
> +	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
> +	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
> +	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
> +	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
> +	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
> +	SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
> +	SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
> +	SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
> +	SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
> +	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
> +	SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
> +	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
> +	SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
> +	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
> +	SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
> +	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
> +
> +	/* Below is the copied entries from alc880_quirks.c.
> +	 * It's not quite sure whether BIOS sets the correct pin-config table
> +	 * on these machines, thus they are kept to be compatible with
> +	 * the old static quirks.  Once when it's confirmed to work without
> +	 * these overrides, it'd be better to remove.
> +	 */
> +	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
> +	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
> +	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
> +	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
> +	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
> +	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
> +	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
> +	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
> +	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
> +	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
> +	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
> +	/* default Intel */
> +	SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
> +	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
> +	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
> +	{}
> +};
> +
> +static const struct hda_model_fixup alc880_fixup_models[] = {
> +	{.id = ALC880_FIXUP_3ST, .name = "3stack"},
> +	{.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
> +	{.id = ALC880_FIXUP_5ST, .name = "5stack"},
> +	{.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
> +	{.id = ALC880_FIXUP_6ST, .name = "6stack"},
> +	{.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
> +	{.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
> +	{}
> +};
> +
> +
> +/*
> + * OK, here we have finally the patch for ALC880
> + */
> +static int patch_alc880(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x0b);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +	spec->gen.need_dac_fix = 1;
> +	spec->gen.beep_nid = 0x01;
> +
> +	codec->patch_ops.unsol_event = alc880_unsol_event;
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
> +		       alc880_fixups);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc880_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog) {
> +		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc880[] = {
> +	HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc880);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC880 HD-audio codec");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc880_driver = {
> +	.id = snd_hda_id_alc880,
> +};
> +
> +module_hda_codec_driver(alc880_driver);
> diff --git a/sound/hda/codecs/realtek/alc882.c b/sound/hda/codecs/realtek/alc882.c
> new file mode 100644
> index 000000000000..6af2f7fcc6bb
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/alc882.c
> @@ -0,0 +1,847 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek ALC882/883/885/888/889 codec support
> +//
> +// ALC882 is almost identical with ALC880 but has cleaner and more flexible
> +// configuration.  Each pin widget can choose any input DACs and a mixer.
> +// Each ADC is connected from a mixer of all inputs.  This makes possible
> +// 6-channel independent captures.
> +//
> +// In addition, an independent DAC for the multi-playback (not used in this
> +// driver yet).
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +/*
> + * Pin config fixes
> + */
> +enum {
> +	ALC882_FIXUP_ABIT_AW9D_MAX,
> +	ALC882_FIXUP_LENOVO_Y530,
> +	ALC882_FIXUP_PB_M5210,
> +	ALC882_FIXUP_ACER_ASPIRE_7736,
> +	ALC882_FIXUP_ASUS_W90V,
> +	ALC889_FIXUP_CD,
> +	ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
> +	ALC889_FIXUP_VAIO_TT,
> +	ALC888_FIXUP_EEE1601,
> +	ALC886_FIXUP_EAPD,
> +	ALC882_FIXUP_EAPD,
> +	ALC883_FIXUP_EAPD,
> +	ALC883_FIXUP_ACER_EAPD,
> +	ALC882_FIXUP_GPIO1,
> +	ALC882_FIXUP_GPIO2,
> +	ALC882_FIXUP_GPIO3,
> +	ALC889_FIXUP_COEF,
> +	ALC882_FIXUP_ASUS_W2JC,
> +	ALC882_FIXUP_ACER_ASPIRE_4930G,
> +	ALC882_FIXUP_ACER_ASPIRE_8930G,
> +	ALC882_FIXUP_ASPIRE_8930G_VERBS,
> +	ALC885_FIXUP_MACPRO_GPIO,
> +	ALC889_FIXUP_DAC_ROUTE,
> +	ALC889_FIXUP_MBP_VREF,
> +	ALC889_FIXUP_IMAC91_VREF,
> +	ALC889_FIXUP_MBA11_VREF,
> +	ALC889_FIXUP_MBA21_VREF,
> +	ALC889_FIXUP_MP11_VREF,
> +	ALC889_FIXUP_MP41_VREF,
> +	ALC882_FIXUP_INV_DMIC,
> +	ALC882_FIXUP_NO_PRIMARY_HP,
> +	ALC887_FIXUP_ASUS_BASS,
> +	ALC887_FIXUP_BASS_CHMAP,
> +	ALC1220_FIXUP_GB_DUAL_CODECS,
> +	ALC1220_FIXUP_GB_X570,
> +	ALC1220_FIXUP_CLEVO_P950,
> +	ALC1220_FIXUP_CLEVO_PB51ED,
> +	ALC1220_FIXUP_CLEVO_PB51ED_PINS,
> +	ALC887_FIXUP_ASUS_AUDIO,
> +	ALC887_FIXUP_ASUS_HMIC,
> +	ALCS1200A_FIXUP_MIC_VREF,
> +	ALC888VD_FIXUP_MIC_100VREF,
> +};
> +
> +static void alc889_fixup_coef(struct hda_codec *codec,
> +			      const struct hda_fixup *fix, int action)
> +{
> +	if (action != HDA_FIXUP_ACT_INIT)
> +		return;
> +	alc_update_coef_idx(codec, 7, 0, 0x2030);
> +}
> +
> +/* set up GPIO at initialization */
> +static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	spec->gpio_write_delay = true;
> +	alc_fixup_gpio3(codec, fix, action);
> +}
> +
> +/* Fix the connection of some pins for ALC889:
> + * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
> + * work correctly (bko#42740)
> + */
> +static void alc889_fixup_dac_route(struct hda_codec *codec,
> +				   const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		/* fake the connections during parsing the tree */
> +		static const hda_nid_t conn1[] = { 0x0c, 0x0d };
> +		static const hda_nid_t conn2[] = { 0x0e, 0x0f };
> +		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
> +		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
> +		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
> +		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
> +	} else if (action == HDA_FIXUP_ACT_PROBE) {
> +		/* restore the connections */
> +		static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
> +		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
> +		snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
> +		snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
> +		snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
> +	}
> +}
> +
> +/* Set VREF on HP pin */
> +static void alc889_fixup_mbp_vref(struct hda_codec *codec,
> +				  const struct hda_fixup *fix, int action)
> +{
> +	static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
> +	struct alc_spec *spec = codec->spec;
> +	int i;
> +
> +	if (action != HDA_FIXUP_ACT_INIT)
> +		return;
> +	for (i = 0; i < ARRAY_SIZE(nids); i++) {
> +		unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
> +		if (get_defcfg_device(val) != AC_JACK_HP_OUT)
> +			continue;
> +		val = snd_hda_codec_get_pin_target(codec, nids[i]);
> +		val |= AC_PINCTL_VREF_80;
> +		snd_hda_set_pin_ctl(codec, nids[i], val);
> +		spec->gen.keep_vref_in_automute = 1;
> +		break;
> +	}
> +}
> +
> +static void alc889_fixup_mac_pins(struct hda_codec *codec,
> +				  const hda_nid_t *nids, int num_nids)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	int i;
> +
> +	for (i = 0; i < num_nids; i++) {
> +		unsigned int val;
> +		val = snd_hda_codec_get_pin_target(codec, nids[i]);
> +		val |= AC_PINCTL_VREF_50;
> +		snd_hda_set_pin_ctl(codec, nids[i], val);
> +	}
> +	spec->gen.keep_vref_in_automute = 1;
> +}
> +
> +/* Set VREF on speaker pins on imac91 */
> +static void alc889_fixup_imac91_vref(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
> +{
> +	static const hda_nid_t nids[] = { 0x18, 0x1a };
> +
> +	if (action == HDA_FIXUP_ACT_INIT)
> +		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
> +}
> +
> +/* Set VREF on speaker pins on mba11 */
> +static void alc889_fixup_mba11_vref(struct hda_codec *codec,
> +				    const struct hda_fixup *fix, int action)
> +{
> +	static const hda_nid_t nids[] = { 0x18 };
> +
> +	if (action == HDA_FIXUP_ACT_INIT)
> +		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
> +}
> +
> +/* Set VREF on speaker pins on mba21 */
> +static void alc889_fixup_mba21_vref(struct hda_codec *codec,
> +				    const struct hda_fixup *fix, int action)
> +{
> +	static const hda_nid_t nids[] = { 0x18, 0x19 };
> +
> +	if (action == HDA_FIXUP_ACT_INIT)
> +		alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
> +}
> +
> +/* Don't take HP output as primary
> + * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
> + * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
> + */
> +static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
> +				       const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->gen.no_primary_hp = 1;
> +		spec->gen.no_multi_io = 1;
> +	}
> +}
> +
> +static void alc1220_fixup_gb_x570(struct hda_codec *codec,
> +				     const struct hda_fixup *fix,
> +				     int action)
> +{
> +	static const hda_nid_t conn1[] = { 0x0c };
> +	static const struct coef_fw gb_x570_coefs[] = {
> +		WRITE_COEF(0x07, 0x03c0),
> +		WRITE_COEF(0x1a, 0x01c1),
> +		WRITE_COEF(0x1b, 0x0202),
> +		WRITE_COEF(0x43, 0x3005),
> +		{}
> +	};
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
> +		snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
> +		break;
> +	case HDA_FIXUP_ACT_INIT:
> +		alc_process_coef_fw(codec, gb_x570_coefs);
> +		break;
> +	}
> +}
> +
> +static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
> +				     const struct hda_fixup *fix,
> +				     int action)
> +{
> +	static const hda_nid_t conn1[] = { 0x0c };
> +
> +	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> +		return;
> +
> +	alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
> +	/* We therefore want to make sure 0x14 (front headphone) and
> +	 * 0x1b (speakers) use the stereo DAC 0x02
> +	 */
> +	snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
> +	snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
> +}
> +
> +static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
> +				     const struct hda_fixup *fix,
> +				     int action)
> +{
> +	alc1220_fixup_clevo_p950(codec, fix, action);
> +	alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
> +}
> +
> +static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
> +					 struct hda_jack_callback *jack)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	unsigned int vref;
> +
> +	snd_hda_gen_hp_automute(codec, jack);
> +
> +	if (spec->gen.hp_jack_present)
> +		vref = AC_PINCTL_VREF_80;
> +	else
> +		vref = AC_PINCTL_VREF_HIZ;
> +	snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
> +}
> +
> +static void alc887_fixup_asus_jack(struct hda_codec *codec,
> +				     const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action != HDA_FIXUP_ACT_PROBE)
> +		return;
> +	snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
> +	spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
> +}
> +
> +static const struct hda_fixup alc882_fixups[] = {
> +	[ALC882_FIXUP_ABIT_AW9D_MAX] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x01080104 }, /* side */
> +			{ 0x16, 0x01011012 }, /* rear */
> +			{ 0x17, 0x01016011 }, /* clfe */
> +			{ }
> +		}
> +	},
> +	[ALC882_FIXUP_LENOVO_Y530] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x99130112 }, /* rear int speakers */
> +			{ 0x16, 0x99130111 }, /* subwoofer */
> +			{ }
> +		}
> +	},
> +	[ALC882_FIXUP_PB_M5210] = {
> +		.type = HDA_FIXUP_PINCTLS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, PIN_VREF50 },
> +			{}
> +		}
> +	},
> +	[ALC882_FIXUP_ACER_ASPIRE_7736] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_sku_ignore,
> +	},
> +	[ALC882_FIXUP_ASUS_W90V] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x16, 0x99130110 }, /* fix sequence for CLFE */
> +			{ }
> +		}
> +	},
> +	[ALC889_FIXUP_CD] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1c, 0x993301f0 }, /* CD */
> +			{ }
> +		}
> +	},
> +	[ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC889_FIXUP_CD,
> +	},
> +	[ALC889_FIXUP_VAIO_TT] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x17, 0x90170111 }, /* hidden surround speaker */
> +			{ }
> +		}
> +	},
> +	[ALC888_FIXUP_EEE1601] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
> +			{ 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
> +			{ }
> +		}
> +	},
> +	[ALC886_FIXUP_EAPD] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* change to EAPD mode */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
> +			{ }
> +		}
> +	},
> +	[ALC882_FIXUP_EAPD] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* change to EAPD mode */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
> +			{ }
> +		}
> +	},
> +	[ALC883_FIXUP_EAPD] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* change to EAPD mode */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
> +			{ }
> +		}
> +	},
> +	[ALC883_FIXUP_ACER_EAPD] = {
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* eanable EAPD on Acer laptops */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
> +			{ }
> +		}
> +	},
> +	[ALC882_FIXUP_GPIO1] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio1,
> +	},
> +	[ALC882_FIXUP_GPIO2] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio2,
> +	},
> +	[ALC882_FIXUP_GPIO3] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio3,
> +	},
> +	[ALC882_FIXUP_ASUS_W2JC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_gpio1,
> +		.chained = true,
> +		.chain_id = ALC882_FIXUP_EAPD,
> +	},
> +	[ALC889_FIXUP_COEF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_coef,
> +	},
> +	[ALC882_FIXUP_ACER_ASPIRE_4930G] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x16, 0x99130111 }, /* CLFE speaker */
> +			{ 0x17, 0x99130112 }, /* surround speaker */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC882_FIXUP_GPIO1,
> +	},
> +	[ALC882_FIXUP_ACER_ASPIRE_8930G] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x16, 0x99130111 }, /* CLFE speaker */
> +			{ 0x1b, 0x99130112 }, /* surround speaker */
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
> +	},
> +	[ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
> +		/* additional init verbs for Acer Aspire 8930G */
> +		.type = HDA_FIXUP_VERBS,
> +		.v.verbs = (const struct hda_verb[]) {
> +			/* Enable all DACs */
> +			/* DAC DISABLE/MUTE 1? */
> +			/*  setting bits 1-5 disables DAC nids 0x02-0x06
> +			 *  apparently. Init=0x38 */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
> +			/* DAC DISABLE/MUTE 2? */
> +			/*  some bit here disables the other DACs.
> +			 *  Init=0x4900 */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
> +			/* DMIC fix
> +			 * This laptop has a stereo digital microphone.
> +			 * The mics are only 1cm apart which makes the stereo
> +			 * useless. However, either the mic or the ALC889
> +			 * makes the signal become a difference/sum signal
> +			 * instead of standard stereo, which is annoying.
> +			 * So instead we flip this bit which makes the
> +			 * codec replicate the sum signal to both channels,
> +			 * turning it into a normal mono mic.
> +			 */
> +			/* DMIC_CONTROL? Init value = 0x0001 */
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
> +			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
> +			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
> +			{ }
> +		},
> +		.chained = true,
> +		.chain_id = ALC882_FIXUP_GPIO1,
> +	},
> +	[ALC885_FIXUP_MACPRO_GPIO] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc885_fixup_macpro_gpio,
> +	},
> +	[ALC889_FIXUP_DAC_ROUTE] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_dac_route,
> +	},
> +	[ALC889_FIXUP_MBP_VREF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_mbp_vref,
> +		.chained = true,
> +		.chain_id = ALC882_FIXUP_GPIO1,
> +	},
> +	[ALC889_FIXUP_IMAC91_VREF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_imac91_vref,
> +		.chained = true,
> +		.chain_id = ALC882_FIXUP_GPIO1,
> +	},
> +	[ALC889_FIXUP_MBA11_VREF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_mba11_vref,
> +		.chained = true,
> +		.chain_id = ALC889_FIXUP_MBP_VREF,
> +	},
> +	[ALC889_FIXUP_MBA21_VREF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_mba21_vref,
> +		.chained = true,
> +		.chain_id = ALC889_FIXUP_MBP_VREF,
> +	},
> +	[ALC889_FIXUP_MP11_VREF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_mba11_vref,
> +		.chained = true,
> +		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
> +	},
> +	[ALC889_FIXUP_MP41_VREF] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc889_fixup_mbp_vref,
> +		.chained = true,
> +		.chain_id = ALC885_FIXUP_MACPRO_GPIO,
> +	},
> +	[ALC882_FIXUP_INV_DMIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_inv_dmic,
> +	},
> +	[ALC882_FIXUP_NO_PRIMARY_HP] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc882_fixup_no_primary_hp,
> +	},
> +	[ALC887_FIXUP_ASUS_BASS] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{0x16, 0x99130130}, /* bass speaker */
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC887_FIXUP_BASS_CHMAP,
> +	},
> +	[ALC887_FIXUP_BASS_CHMAP] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc_fixup_bass_chmap,
> +	},
> +	[ALC1220_FIXUP_GB_DUAL_CODECS] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc1220_fixup_gb_dual_codecs,
> +	},
> +	[ALC1220_FIXUP_GB_X570] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc1220_fixup_gb_x570,
> +	},
> +	[ALC1220_FIXUP_CLEVO_P950] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc1220_fixup_clevo_p950,
> +	},
> +	[ALC1220_FIXUP_CLEVO_PB51ED] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc1220_fixup_clevo_pb51ed,
> +	},
> +	[ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
> +			{}
> +		},
> +		.chained = true,
> +		.chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
> +	},
> +	[ALC887_FIXUP_ASUS_AUDIO] = {
> +		.type = HDA_FIXUP_PINS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
> +			{ 0x19, 0x22219420 },
> +			{}
> +		},
> +	},
> +	[ALC887_FIXUP_ASUS_HMIC] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc887_fixup_asus_jack,
> +		.chained = true,
> +		.chain_id = ALC887_FIXUP_ASUS_AUDIO,
> +	},
> +	[ALCS1200A_FIXUP_MIC_VREF] = {
> +		.type = HDA_FIXUP_PINCTLS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x18, PIN_VREF50 }, /* rear mic */
> +			{ 0x19, PIN_VREF50 }, /* front mic */
> +			{}
> +		}
> +	},
> +	[ALC888VD_FIXUP_MIC_100VREF] = {
> +		.type = HDA_FIXUP_PINCTLS,
> +		.v.pins = (const struct hda_pintbl[]) {
> +			{ 0x18, PIN_VREF100 }, /* headset mic */
> +			{}
> +		}
> +	},
> +};
> +
> +static const struct hda_quirk alc882_fixup_tbl[] = {
> +	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
> +	SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
> +		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> +	SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
> +		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> +	SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
> +		      ALC882_FIXUP_ACER_ASPIRE_8930G),
> +	SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
> +		      ALC882_FIXUP_ACER_ASPIRE_8930G),
> +	SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
> +		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> +	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
> +	SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
> +		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> +	SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
> +		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> +	SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
> +		      ALC882_FIXUP_ACER_ASPIRE_4930G),
> +	SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
> +	SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
> +	SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
> +	SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
> +	SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
> +	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
> +	SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
> +	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
> +	SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
> +	SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
> +	SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
> +	SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
> +	SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
> +	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
> +	SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
> +	SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
> +
> +	/* All Apple entries are in codec SSIDs */
> +	SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
> +	SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
> +	SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
> +	SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
> +	SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
> +	SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
> +
> +	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
> +	SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
> +	SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
> +	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
> +	SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
> +	SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
> +	SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
> +	SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
> +	SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
> +	SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
> +	SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
> +	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
> +	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
> +	SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
> +	SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
> +	SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
> +	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
> +	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
> +	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
> +	SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
> +	{}
> +};
> +
> +static const struct hda_model_fixup alc882_fixup_models[] = {
> +	{.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
> +	{.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
> +	{.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
> +	{.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
> +	{.id = ALC889_FIXUP_CD, .name = "cd"},
> +	{.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
> +	{.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
> +	{.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
> +	{.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
> +	{.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
> +	{.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
> +	{.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
> +	{.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
> +	{.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
> +	{.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
> +	{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
> +	{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
> +	{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
> +	{.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
> +	{.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
> +	{.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
> +	{.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
> +	{.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
> +	{.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
> +	{.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
> +	{.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
> +	{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
> +	{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
> +	{.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
> +	{.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
> +	{.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
> +	{.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
> +	{}
> +};
> +
> +static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
> +	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
> +		{0x14, 0x01014010},
> +		{0x15, 0x01011012},
> +		{0x16, 0x01016011},
> +		{0x18, 0x01a19040},
> +		{0x19, 0x02a19050},
> +		{0x1a, 0x0181304f},
> +		{0x1b, 0x0221401f},
> +		{0x1e, 0x01456130}),
> +	SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
> +		{0x14, 0x01015010},
> +		{0x15, 0x01011012},
> +		{0x16, 0x01011011},
> +		{0x18, 0x01a11040},
> +		{0x19, 0x02a19050},
> +		{0x1a, 0x0181104f},
> +		{0x1b, 0x0221401f},
> +		{0x1e, 0x01451130}),
> +	{}
> +};
> +
> +/*
> + * BIOS auto configuration
> + */
> +/* almost identical with ALC880 parser... */
> +static int alc882_parse_auto_config(struct hda_codec *codec)
> +{
> +	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
> +	static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
> +	return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
> +}
> +
> +/*
> + */
> +static int patch_alc882(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec;
> +	int err;
> +
> +	err = alc_alloc_spec(codec, 0x0b);
> +	if (err < 0)
> +		return err;
> +
> +	spec = codec->spec;
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0882:
> +	case 0x10ec0885:
> +	case 0x10ec0900:
> +	case 0x10ec0b00:
> +	case 0x10ec1220:
> +		break;
> +	default:
> +		/* ALC883 and variants */
> +		alc_fix_pll_init(codec, 0x20, 0x0a, 10);
> +		break;
> +	}
> +
> +	alc_pre_init(codec);
> +
> +	snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
> +		       alc882_fixups);
> +	snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
> +
> +	alc_auto_parse_customize_define(codec);
> +
> +	if (has_cdefine_beep(codec))
> +		spec->gen.beep_nid = 0x01;
> +
> +	/* automatic parse from the BIOS config */
> +	err = alc882_parse_auto_config(codec);
> +	if (err < 0)
> +		goto error;
> +
> +	if (!spec->gen.no_analog && spec->gen.beep_nid) {
> +		err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
> +		if (err < 0)
> +			goto error;
> +	}
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
> +
> +	return 0;
> +
> + error:
> +	alc_free(codec);
> +	return err;
> +}
> +
> +/*
> + * driver entries
> + */
> +static const struct hda_device_id snd_hda_id_alc882[] = {
> +	HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
> +	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
> +	HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
> +	HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
> +	HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
> +	{} /* terminator */
> +};
> +MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_alc882);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek ALC882 and compatible HD-audio codecs");
> +MODULE_IMPORT_NS("SND_HDA_CODEC_REALTEK");
> +
> +static struct hda_codec_driver alc882_driver = {
> +	.id = snd_hda_id_alc882,
> +};
> +
> +module_hda_codec_driver(alc882_driver);
> diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c
> new file mode 100644
> index 000000000000..4ab49e76c304
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/realtek.c
> @@ -0,0 +1,2314 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek HD-audio codec support code
> +//
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include "realtek.h"
> +
> +/*
> + * COEF access helper functions
> + */
> +
> +static void coef_mutex_lock(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	snd_hda_power_up_pm(codec);
> +	mutex_lock(&spec->coef_mutex);
> +}
> +
> +static void coef_mutex_unlock(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	mutex_unlock(&spec->coef_mutex);
> +	snd_hda_power_down_pm(codec);
> +}
> +
> +static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +				 unsigned int coef_idx)
> +{
> +	unsigned int val;
> +
> +	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
> +	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
> +	return val;
> +}
> +
> +int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +			unsigned int coef_idx)
> +{
> +	unsigned int val;
> +
> +	coef_mutex_lock(codec);
> +	val = __alc_read_coefex_idx(codec, nid, coef_idx);
> +	coef_mutex_unlock(codec);
> +	return val;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_read_coefex_idx, "SND_HDA_CODEC_REALTEK");
> +
> +static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +				   unsigned int coef_idx, unsigned int coef_val)
> +{
> +	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
> +	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
> +}
> +
> +void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +			  unsigned int coef_idx, unsigned int coef_val)
> +{
> +	coef_mutex_lock(codec);
> +	__alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
> +	coef_mutex_unlock(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_write_coefex_idx, "SND_HDA_CODEC_REALTEK");
> +
> +static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +				    unsigned int coef_idx, unsigned int mask,
> +				    unsigned int bits_set)
> +{
> +	unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
> +
> +	if (val != -1)
> +		__alc_write_coefex_idx(codec, nid, coef_idx,
> +				       (val & ~mask) | bits_set);
> +}
> +
> +void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +			   unsigned int coef_idx, unsigned int mask,
> +			   unsigned int bits_set)
> +{
> +	coef_mutex_lock(codec);
> +	__alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
> +	coef_mutex_unlock(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_update_coefex_idx, "SND_HDA_CODEC_REALTEK");
> +
> +/* a special bypass for COEF 0; read the cached value at the second time */
> +unsigned int alc_get_coef0(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (!spec->coef0)
> +		spec->coef0 = alc_read_coef_idx(codec, 0);
> +	return spec->coef0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_get_coef0, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw)
> +{
> +	coef_mutex_lock(codec);
> +	for (; fw->nid; fw++) {
> +		if (fw->mask == (unsigned short)-1)
> +			__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
> +		else
> +			__alc_update_coefex_idx(codec, fw->nid, fw->idx,
> +						fw->mask, fw->val);
> +	}
> +	coef_mutex_unlock(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_process_coef_fw, "SND_HDA_CODEC_REALTEK");
> +
> +/*
> + * GPIO setup tables, used in initialization
> + */
> +
> +/* Enable GPIO mask and set output */
> +void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	spec->gpio_mask |= mask;
> +	spec->gpio_dir |= mask;
> +	spec->gpio_data |= mask;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_setup_gpio, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_write_gpio_data(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
> +			    spec->gpio_data);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_write_gpio_data, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
> +			  bool on)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	unsigned int oldval = spec->gpio_data;
> +
> +	if (on)
> +		spec->gpio_data |= mask;
> +	else
> +		spec->gpio_data &= ~mask;
> +	if (oldval != spec->gpio_data)
> +		alc_write_gpio_data(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_update_gpio_data, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_write_gpio(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (!spec->gpio_mask)
> +		return;
> +
> +	snd_hda_codec_write(codec, codec->core.afg, 0,
> +			    AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
> +	snd_hda_codec_write(codec, codec->core.afg, 0,
> +			    AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
> +	if (spec->gpio_write_delay)
> +		msleep(1);
> +	alc_write_gpio_data(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_write_gpio, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +		alc_setup_gpio(codec, mask);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_gpio1(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action)
> +{
> +	alc_fixup_gpio(codec, action, 0x01);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio1, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_gpio2(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action)
> +{
> +	alc_fixup_gpio(codec, action, 0x02);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio2, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_gpio3(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action)
> +{
> +	alc_fixup_gpio(codec, action, 0x03);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio3, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_gpio4(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action)
> +{
> +	alc_fixup_gpio(codec, action, 0x04);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_gpio4, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_micmute_led(struct hda_codec *codec,
> +			   const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +		snd_hda_gen_add_micmute_led_cdev(codec, NULL);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_micmute_led, "SND_HDA_CODEC_REALTEK");
> +
> +/*
> + * Fix hardware PLL issue
> + * On some codecs, the analog PLL gating control must be off while
> + * the default value is 1.
> + */
> +void alc_fix_pll(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (spec->pll_nid)
> +		alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
> +				      1 << spec->pll_coef_bit, 0);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fix_pll, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
> +		      unsigned int coef_idx, unsigned int coef_bit)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	spec->pll_nid = nid;
> +	spec->pll_coef_idx = coef_idx;
> +	spec->pll_coef_bit = coef_bit;
> +	alc_fix_pll(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fix_pll_init, "SND_HDA_CODEC_REALTEK");
> +
> +/* update the master volume per volume-knob's unsol event */
> +void alc_update_knob_master(struct hda_codec *codec,
> +			    struct hda_jack_callback *jack)
> +{
> +	unsigned int val;
> +	struct snd_kcontrol *kctl;
> +	struct snd_ctl_elem_value *uctl;
> +
> +	kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
> +	if (!kctl)
> +		return;
> +	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
> +	if (!uctl)
> +		return;
> +	val = snd_hda_codec_read(codec, jack->nid, 0,
> +				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
> +	val &= HDA_AMP_VOLMASK;
> +	uctl->value.integer.value[0] = val;
> +	uctl->value.integer.value[1] = val;
> +	kctl->put(kctl, uctl);
> +	kfree(uctl);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_update_knob_master, "SND_HDA_CODEC_REALTEK");
> +
> +/* Change EAPD to verb control */
> +void alc_fill_eapd_coef(struct hda_codec *codec)
> +{
> +	int coef;
> +
> +	coef = alc_get_coef0(codec);
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0262:
> +		alc_update_coef_idx(codec, 0x7, 0, 1<<5);
> +		break;
> +	case 0x10ec0267:
> +	case 0x10ec0268:
> +		alc_update_coef_idx(codec, 0x7, 0, 1<<13);
> +		break;
> +	case 0x10ec0269:
> +		if ((coef & 0x00f0) == 0x0010)
> +			alc_update_coef_idx(codec, 0xd, 0, 1<<14);
> +		if ((coef & 0x00f0) == 0x0020)
> +			alc_update_coef_idx(codec, 0x4, 1<<15, 0);
> +		if ((coef & 0x00f0) == 0x0030)
> +			alc_update_coef_idx(codec, 0x10, 1<<9, 0);
> +		break;
> +	case 0x10ec0280:
> +	case 0x10ec0284:
> +	case 0x10ec0290:
> +	case 0x10ec0292:
> +		alc_update_coef_idx(codec, 0x4, 1<<15, 0);
> +		break;
> +	case 0x10ec0225:
> +	case 0x10ec0295:
> +	case 0x10ec0299:
> +		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
> +		fallthrough;
> +	case 0x10ec0215:
> +	case 0x10ec0236:
> +	case 0x10ec0245:
> +	case 0x10ec0256:
> +	case 0x10ec0257:
> +	case 0x10ec0285:
> +	case 0x10ec0289:
> +		alc_update_coef_idx(codec, 0x36, 1<<13, 0);
> +		fallthrough;
> +	case 0x10ec0230:
> +	case 0x10ec0233:
> +	case 0x10ec0235:
> +	case 0x10ec0255:
> +	case 0x19e58326:
> +	case 0x10ec0282:
> +	case 0x10ec0283:
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +	case 0x10ec0298:
> +	case 0x10ec0300:
> +		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
> +		break;
> +	case 0x10ec0275:
> +		alc_update_coef_idx(codec, 0xe, 0, 1<<0);
> +		break;
> +	case 0x10ec0287:
> +		alc_update_coef_idx(codec, 0x10, 1<<9, 0);
> +		alc_write_coef_idx(codec, 0x8, 0x4ab7);
> +		break;
> +	case 0x10ec0293:
> +		alc_update_coef_idx(codec, 0xa, 1<<13, 0);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +		alc_write_coef_idx(codec, 0x6e, 0x0c25);
> +		fallthrough;
> +	case 0x10ec0294:
> +	case 0x10ec0700:
> +	case 0x10ec0701:
> +	case 0x10ec0703:
> +	case 0x10ec0711:
> +		alc_update_coef_idx(codec, 0x10, 1<<15, 0);
> +		break;
> +	case 0x10ec0662:
> +		if ((coef & 0x00f0) == 0x0030)
> +			alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
> +		break;
> +	case 0x10ec0272:
> +	case 0x10ec0273:
> +	case 0x10ec0663:
> +	case 0x10ec0665:
> +	case 0x10ec0670:
> +	case 0x10ec0671:
> +	case 0x10ec0672:
> +		alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
> +		break;
> +	case 0x10ec0222:
> +	case 0x10ec0623:
> +		alc_update_coef_idx(codec, 0x19, 1<<13, 0);
> +		break;
> +	case 0x10ec0668:
> +		alc_update_coef_idx(codec, 0x7, 3<<13, 0);
> +		break;
> +	case 0x10ec0867:
> +		alc_update_coef_idx(codec, 0x4, 1<<10, 0);
> +		break;
> +	case 0x10ec0888:
> +		if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
> +			alc_update_coef_idx(codec, 0x7, 1<<5, 0);
> +		break;
> +	case 0x10ec0892:
> +	case 0x10ec0897:
> +		alc_update_coef_idx(codec, 0x7, 1<<5, 0);
> +		break;
> +	case 0x10ec0899:
> +	case 0x10ec0900:
> +	case 0x10ec0b00:
> +	case 0x10ec1168:
> +	case 0x10ec1220:
> +		alc_update_coef_idx(codec, 0x7, 1<<1, 0);
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fill_eapd_coef, "SND_HDA_CODEC_REALTEK");
> +
> +/* turn on/off EAPD control (only if available) */
> +static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
> +{
> +	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
> +		return;
> +	if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
> +		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
> +				    on ? 2 : 0);
> +}
> +
> +/* turn on/off EAPD controls of the codec */
> +void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
> +{
> +	/* We currently only handle front, HP */
> +	static const hda_nid_t pins[] = {
> +		0x0f, 0x10, 0x14, 0x15, 0x17, 0
> +	};
> +	const hda_nid_t *p;
> +	for (p = pins; *p; p++)
> +		set_eapd(codec, *p, on);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_auto_setup_eapd, "SND_HDA_CODEC_REALTEK");
> +
> +/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
> +int alc_find_ext_mic_pin(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
> +	hda_nid_t nid;
> +	unsigned int defcfg;
> +	int i;
> +
> +	for (i = 0; i < cfg->num_inputs; i++) {
> +		if (cfg->inputs[i].type != AUTO_PIN_MIC)
> +			continue;
> +		nid = cfg->inputs[i].pin;
> +		defcfg = snd_hda_codec_get_pincfg(codec, nid);
> +		if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
> +			continue;
> +		return nid;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_find_ext_mic_pin, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_headset_mic_no_shutup(struct hda_codec *codec)
> +{
> +	const struct hda_pincfg *pin;
> +	int mic_pin = alc_find_ext_mic_pin(codec);
> +	int i;
> +
> +	/* don't shut up pins when unloading the driver; otherwise it breaks
> +	 * the default pin setup at the next load of the driver
> +	 */
> +	if (codec->bus->shutdown)
> +		return;
> +
> +	snd_array_for_each(&codec->init_pins, i, pin) {
> +		/* use read here for syncing after issuing each verb */
> +		if (pin->nid != mic_pin)
> +			snd_hda_codec_read(codec, pin->nid, 0,
> +					AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
> +	}
> +
> +	codec->pins_shutup = 1;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_headset_mic_no_shutup, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_shutup_pins(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (spec->no_shutup_pins)
> +		return;
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x10ec0257:
> +	case 0x19e58326:
> +	case 0x10ec0283:
> +	case 0x10ec0285:
> +	case 0x10ec0286:
> +	case 0x10ec0287:
> +	case 0x10ec0288:
> +	case 0x10ec0295:
> +	case 0x10ec0298:
> +		alc_headset_mic_no_shutup(codec);
> +		break;
> +	default:
> +		snd_hda_shutup_pins(codec);
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_shutup_pins, "SND_HDA_CODEC_REALTEK");
> +
> +/* generic shutup callback;
> + * just turning off EAPD and a little pause for avoiding pop-noise
> + */
> +void alc_eapd_shutup(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	alc_auto_setup_eapd(codec, false);
> +	if (!spec->no_depop_delay)
> +		msleep(200);
> +	alc_shutup_pins(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_eapd_shutup, "SND_HDA_CODEC_REALTEK");
> +
> +/* additional initialization for ALC888 variants */
> +static void alc888_coef_init(struct hda_codec *codec)
> +{
> +	switch (alc_get_coef0(codec) & 0x00f0) {
> +	/* alc888-VA */
> +	case 0x00:
> +	/* alc888-VB */
> +	case 0x10:
> +		alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
> +		break;
> +	}
> +}
> +
> +/* generic EAPD initialization */
> +void alc_auto_init_amp(struct hda_codec *codec, int type)
> +{
> +	alc_auto_setup_eapd(codec, true);
> +	alc_write_gpio(codec);
> +	switch (type) {
> +	case ALC_INIT_DEFAULT:
> +		switch (codec->core.vendor_id) {
> +		case 0x10ec0260:
> +			alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
> +			break;
> +		case 0x10ec0880:
> +		case 0x10ec0882:
> +		case 0x10ec0883:
> +		case 0x10ec0885:
> +			alc_update_coef_idx(codec, 7, 0, 0x2030);
> +			break;
> +		case 0x10ec0888:
> +			alc888_coef_init(codec);
> +			break;
> +		}
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_auto_init_amp, "SND_HDA_CODEC_REALTEK");
> +
> +/* get a primary headphone pin if available */
> +hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
> +{
> +	if (spec->gen.autocfg.hp_pins[0])
> +		return spec->gen.autocfg.hp_pins[0];
> +	if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
> +		return spec->gen.autocfg.line_out_pins[0];
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_get_hp_pin, "SND_HDA_CODEC_REALTEK");
> +
> +/*
> + * Realtek SSID verification
> + */
> +
> +/* Could be any non-zero and even value. When used as fixup, tells
> + * the driver to ignore any present sku defines.
> + */
> +#define ALC_FIXUP_SKU_IGNORE (2)
> +
> +void alc_fixup_sku_ignore(struct hda_codec *codec,
> +			  const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->cdefine.fixup = 1;
> +		spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_sku_ignore, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_no_depop_delay(struct hda_codec *codec,
> +			      const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action == HDA_FIXUP_ACT_PROBE) {
> +		spec->no_depop_delay = 1;
> +		codec->depop_delay = 0;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_no_depop_delay, "SND_HDA_CODEC_REALTEK");
> +
> +int alc_auto_parse_customize_define(struct hda_codec *codec)
> +{
> +	unsigned int ass, tmp, i;
> +	unsigned nid = 0;
> +	struct alc_spec *spec = codec->spec;
> +
> +	spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
> +
> +	if (spec->cdefine.fixup) {
> +		ass = spec->cdefine.sku_cfg;
> +		if (ass == ALC_FIXUP_SKU_IGNORE)
> +			return -1;
> +		goto do_sku;
> +	}
> +
> +	if (!codec->bus->pci)
> +		return -1;
> +	ass = codec->core.subsystem_id & 0xffff;
> +	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
> +		goto do_sku;
> +
> +	nid = 0x1d;
> +	if (codec->core.vendor_id == 0x10ec0260)
> +		nid = 0x17;
> +	ass = snd_hda_codec_get_pincfg(codec, nid);
> +
> +	if (!(ass & 1)) {
> +		codec_info(codec, "%s: SKU not ready 0x%08x\n",
> +			   codec->core.chip_name, ass);
> +		return -1;
> +	}
> +
> +	/* check sum */
> +	tmp = 0;
> +	for (i = 1; i < 16; i++) {
> +		if ((ass >> i) & 1)
> +			tmp++;
> +	}
> +	if (((ass >> 16) & 0xf) != tmp)
> +		return -1;
> +
> +	spec->cdefine.port_connectivity = ass >> 30;
> +	spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
> +	spec->cdefine.check_sum = (ass >> 16) & 0xf;
> +	spec->cdefine.customization = ass >> 8;
> +do_sku:
> +	spec->cdefine.sku_cfg = ass;
> +	spec->cdefine.external_amp = (ass & 0x38) >> 3;
> +	spec->cdefine.platform_type = (ass & 0x4) >> 2;
> +	spec->cdefine.swap = (ass & 0x2) >> 1;
> +	spec->cdefine.override = ass & 0x1;
> +
> +	codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
> +		   nid, spec->cdefine.sku_cfg);
> +	codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
> +		   spec->cdefine.port_connectivity);
> +	codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
> +	codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
> +	codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
> +	codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
> +	codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
> +	codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
> +	codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_auto_parse_customize_define, "SND_HDA_CODEC_REALTEK");
> +
> +/* return the position of NID in the list, or -1 if not found */
> +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
> +{
> +	int i;
> +	for (i = 0; i < nums; i++)
> +		if (list[i] == nid)
> +			return i;
> +	return -1;
> +}
> +/* return true if the given NID is found in the list */
> +static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
> +{
> +	return find_idx_in_nid_list(nid, list, nums) >= 0;
> +}
> +
> +/* check subsystem ID and set up device-specific initialization;
> + * return 1 if initialized, 0 if invalid SSID
> + */
> +/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
> + *	31 ~ 16 :	Manufacture ID
> + *	15 ~ 8	:	SKU ID
> + *	7  ~ 0	:	Assembly ID
> + *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
> + */
> +int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
> +{
> +	unsigned int ass, tmp, i;
> +	unsigned nid;
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (spec->cdefine.fixup) {
> +		ass = spec->cdefine.sku_cfg;
> +		if (ass == ALC_FIXUP_SKU_IGNORE)
> +			return 0;
> +		goto do_sku;
> +	}
> +
> +	ass = codec->core.subsystem_id & 0xffff;
> +	if (codec->bus->pci &&
> +	    ass != codec->bus->pci->subsystem_device && (ass & 1))
> +		goto do_sku;
> +
> +	/* invalid SSID, check the special NID pin defcfg instead */
> +	/*
> +	 * 31~30	: port connectivity
> +	 * 29~21	: reserve
> +	 * 20		: PCBEEP input
> +	 * 19~16	: Check sum (15:1)
> +	 * 15~1		: Custom
> +	 * 0		: override
> +	*/
> +	nid = 0x1d;
> +	if (codec->core.vendor_id == 0x10ec0260)
> +		nid = 0x17;
> +	ass = snd_hda_codec_get_pincfg(codec, nid);
> +	codec_dbg(codec,
> +		  "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
> +		   ass, nid);
> +	if (!(ass & 1))
> +		return 0;
> +	if ((ass >> 30) != 1)	/* no physical connection */
> +		return 0;
> +
> +	/* check sum */
> +	tmp = 0;
> +	for (i = 1; i < 16; i++) {
> +		if ((ass >> i) & 1)
> +			tmp++;
> +	}
> +	if (((ass >> 16) & 0xf) != tmp)
> +		return 0;
> +do_sku:
> +	codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
> +		   ass & 0xffff, codec->core.vendor_id);
> +	/*
> +	 * 0 : override
> +	 * 1 :	Swap Jack
> +	 * 2 : 0 --> Desktop, 1 --> Laptop
> +	 * 3~5 : External Amplifier control
> +	 * 7~6 : Reserved
> +	*/
> +	tmp = (ass & 0x38) >> 3;	/* external Amp control */
> +	if (spec->init_amp == ALC_INIT_UNDEFINED) {
> +		switch (tmp) {
> +		case 1:
> +			alc_setup_gpio(codec, 0x01);
> +			break;
> +		case 3:
> +			alc_setup_gpio(codec, 0x02);
> +			break;
> +		case 7:
> +			alc_setup_gpio(codec, 0x04);
> +			break;
> +		case 5:
> +		default:
> +			spec->init_amp = ALC_INIT_DEFAULT;
> +			break;
> +		}
> +	}
> +
> +	/* is laptop or Desktop and enable the function "Mute internal speaker
> +	 * when the external headphone out jack is plugged"
> +	 */
> +	if (!(ass & 0x8000))
> +		return 1;
> +	/*
> +	 * 10~8 : Jack location
> +	 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
> +	 * 14~13: Resvered
> +	 * 15   : 1 --> enable the function "Mute internal speaker
> +	 *	        when the external headphone out jack is plugged"
> +	 */
> +	if (!alc_get_hp_pin(spec)) {
> +		hda_nid_t nid;
> +		tmp = (ass >> 11) & 0x3;	/* HP to chassis */
> +		nid = ports[tmp];
> +		if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
> +				      spec->gen.autocfg.line_outs))
> +			return 1;
> +		spec->gen.autocfg.hp_pins[0] = nid;
> +	}
> +	return 1;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_subsystem_id, "SND_HDA_CODEC_REALTEK");
> +
> +/* Check the validity of ALC subsystem-id
> + * ports contains an array of 4 pin NIDs for port-A, E, D and I */
> +void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
> +{
> +	if (!alc_subsystem_id(codec, ports)) {
> +		struct alc_spec *spec = codec->spec;
> +		if (spec->init_amp == ALC_INIT_UNDEFINED) {
> +			codec_dbg(codec,
> +				  "realtek: Enable default setup for auto mode as fallback\n");
> +			spec->init_amp = ALC_INIT_DEFAULT;
> +		}
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_ssid_check, "SND_HDA_CODEC_REALTEK");
> +
> +/* inverted digital-mic */
> +void alc_fixup_inv_dmic(struct hda_codec *codec,
> +			const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	spec->gen.inv_dmic_split = 1;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_inv_dmic, "SND_HDA_CODEC_REALTEK");
> +
> +int alc_build_controls(struct hda_codec *codec)
> +{
> +	int err;
> +
> +	err = snd_hda_gen_build_controls(codec);
> +	if (err < 0)
> +		return err;
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_build_controls, "SND_HDA_CODEC_REALTEK");
> +
> +int alc_init(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	/* hibernation resume needs the full chip initialization */
> +	if (is_s4_resume(codec))
> +		alc_pre_init(codec);
> +
> +	if (spec->init_hook)
> +		spec->init_hook(codec);
> +
> +	spec->gen.skip_verbs = 1; /* applied in below */
> +	snd_hda_gen_init(codec);
> +	alc_fix_pll(codec);
> +	alc_auto_init_amp(codec, spec->init_amp);
> +	snd_hda_apply_verbs(codec); /* apply verbs here after own init */
> +
> +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_init, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_shutup(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (!snd_hda_get_bool_hint(codec, "shutup"))
> +		return; /* disabled explicitly by hints */
> +
> +	if (spec && spec->shutup)
> +		spec->shutup(codec);
> +	else
> +		alc_shutup_pins(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_shutup, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_power_eapd(struct hda_codec *codec)
> +{
> +	alc_auto_setup_eapd(codec, false);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_power_eapd, "SND_HDA_CODEC_REALTEK");
> +
> +int alc_suspend(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	alc_shutup(codec);
> +	if (spec && spec->power_hook)
> +		spec->power_hook(codec);
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_suspend, "SND_HDA_CODEC_REALTEK");
> +
> +int alc_resume(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (!spec->no_depop_delay)
> +		msleep(150); /* to avoid pop noise */
> +	codec->patch_ops.init(codec);
> +	snd_hda_regmap_sync(codec);
> +	hda_call_check_power_status(codec, 0x01);
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_resume, "SND_HDA_CODEC_REALTEK");
> +
> +/*
> + */
> +const struct hda_codec_ops alc_patch_ops = {
> +	.build_controls = alc_build_controls,
> +	.build_pcms = snd_hda_gen_build_pcms,
> +	.init = alc_init,
> +	.free = alc_free,
> +	.unsol_event = snd_hda_jack_unsol_event,
> +	.resume = alc_resume,
> +	.suspend = alc_suspend,
> +	.check_power_status = snd_hda_gen_check_power_status,
> +};
> +EXPORT_SYMBOL_NS_GPL(alc_patch_ops, "SND_HDA_CODEC_REALTEK");
> +
> +/*
> + * Rename codecs appropriately from COEF value or subvendor id
> + */
> +struct alc_codec_rename_table {
> +	unsigned int vendor_id;
> +	unsigned short coef_mask;
> +	unsigned short coef_bits;
> +	const char *name;
> +};
> +
> +struct alc_codec_rename_pci_table {
> +	unsigned int codec_vendor_id;
> +	unsigned short pci_subvendor;
> +	unsigned short pci_subdevice;
> +	const char *name;
> +};
> +
> +static const struct alc_codec_rename_table rename_tbl[] = {
> +	{ 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
> +	{ 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
> +	{ 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
> +	{ 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
> +	{ 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
> +	{ 0x10ec0269, 0xffff, 0xa023, "ALC259" },
> +	{ 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
> +	{ 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
> +	{ 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
> +	{ 0x10ec0662, 0xffff, 0x4020, "ALC656" },
> +	{ 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
> +	{ 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
> +	{ 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
> +	{ 0x10ec0899, 0x2000, 0x2000, "ALC899" },
> +	{ 0x10ec0892, 0xffff, 0x8020, "ALC661" },
> +	{ 0x10ec0892, 0xffff, 0x8011, "ALC661" },
> +	{ 0x10ec0892, 0xffff, 0x4011, "ALC656" },
> +	{ } /* terminator */
> +};
> +
> +static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
> +	{ 0x10ec0280, 0x1028, 0, "ALC3220" },
> +	{ 0x10ec0282, 0x1028, 0, "ALC3221" },
> +	{ 0x10ec0283, 0x1028, 0, "ALC3223" },
> +	{ 0x10ec0288, 0x1028, 0, "ALC3263" },
> +	{ 0x10ec0292, 0x1028, 0, "ALC3226" },
> +	{ 0x10ec0293, 0x1028, 0, "ALC3235" },
> +	{ 0x10ec0255, 0x1028, 0, "ALC3234" },
> +	{ 0x10ec0668, 0x1028, 0, "ALC3661" },
> +	{ 0x10ec0275, 0x1028, 0, "ALC3260" },
> +	{ 0x10ec0899, 0x1028, 0, "ALC3861" },
> +	{ 0x10ec0298, 0x1028, 0, "ALC3266" },
> +	{ 0x10ec0236, 0x1028, 0, "ALC3204" },
> +	{ 0x10ec0256, 0x1028, 0, "ALC3246" },
> +	{ 0x10ec0225, 0x1028, 0, "ALC3253" },
> +	{ 0x10ec0295, 0x1028, 0, "ALC3254" },
> +	{ 0x10ec0299, 0x1028, 0, "ALC3271" },
> +	{ 0x10ec0670, 0x1025, 0, "ALC669X" },
> +	{ 0x10ec0676, 0x1025, 0, "ALC679X" },
> +	{ 0x10ec0282, 0x1043, 0, "ALC3229" },
> +	{ 0x10ec0233, 0x1043, 0, "ALC3236" },
> +	{ 0x10ec0280, 0x103c, 0, "ALC3228" },
> +	{ 0x10ec0282, 0x103c, 0, "ALC3227" },
> +	{ 0x10ec0286, 0x103c, 0, "ALC3242" },
> +	{ 0x10ec0290, 0x103c, 0, "ALC3241" },
> +	{ 0x10ec0668, 0x103c, 0, "ALC3662" },
> +	{ 0x10ec0283, 0x17aa, 0, "ALC3239" },
> +	{ 0x10ec0292, 0x17aa, 0, "ALC3232" },
> +	{ 0x10ec0257, 0x12f0, 0, "ALC3328" },
> +	{ } /* terminator */
> +};
> +
> +static int alc_codec_rename_from_preset(struct hda_codec *codec)
> +{
> +	const struct alc_codec_rename_table *p;
> +	const struct alc_codec_rename_pci_table *q;
> +
> +	for (p = rename_tbl; p->vendor_id; p++) {
> +		if (p->vendor_id != codec->core.vendor_id)
> +			continue;
> +		if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
> +			return alc_codec_rename(codec, p->name);
> +	}
> +
> +	if (!codec->bus->pci)
> +		return 0;
> +	for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
> +		if (q->codec_vendor_id != codec->core.vendor_id)
> +			continue;
> +		if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
> +			continue;
> +		if (!q->pci_subdevice ||
> +		    q->pci_subdevice == codec->bus->pci->subsystem_device)
> +			return alc_codec_rename(codec, q->name);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Digital-beep handlers
> + */
> +#ifdef CONFIG_SND_HDA_INPUT_BEEP
> +
> +/* additional beep mixers; private_value will be overwritten */
> +static const struct snd_kcontrol_new alc_beep_mixer[] = {
> +	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
> +	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
> +};
> +
> +/* set up and create beep controls */
> +int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir)
> +{
> +	struct snd_kcontrol_new *knew;
> +	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
> +		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
> +					    &alc_beep_mixer[i]);
> +		if (!knew)
> +			return -ENOMEM;
> +		knew->private_value = beep_amp;
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_set_beep_amp, "SND_HDA_CODEC_REALTEK");
> +
> +static const struct snd_pci_quirk beep_allow_list[] = {
> +	SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
> +	SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
> +	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
> +	SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
> +	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
> +	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
> +	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
> +	SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
> +	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
> +	/* denylist -- no beep available */
> +	SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
> +	SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
> +	{}
> +};
> +
> +int alc_has_cdefine_beep(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	const struct snd_pci_quirk *q;
> +	q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
> +	if (q)
> +		return q->value;
> +	return spec->cdefine.enable_pcbeep;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_has_cdefine_beep, "SND_HDA_CODEC_REALTEK");
> +
> +#endif /* CONFIG_SND_HDA_INPUT_BEEP */
> +
> +/* parse the BIOS configuration and set up the alc_spec */
> +/* return 1 if successful, 0 if the proper config is not found,
> + * or a negative error code
> + */
> +int alc_parse_auto_config(struct hda_codec *codec,
> +			  const hda_nid_t *ignore_nids,
> +			  const hda_nid_t *ssid_nids)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
> +	int err;
> +
> +	err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
> +				       spec->parse_flags);
> +	if (err < 0)
> +		return err;
> +
> +	if (ssid_nids)
> +		alc_ssid_check(codec, ssid_nids);
> +
> +	err = snd_hda_gen_parse_auto_config(codec, cfg);
> +	if (err < 0)
> +		return err;
> +
> +	return 1;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_parse_auto_config, "SND_HDA_CODEC_REALTEK");
> +
> +/* common preparation job for alc_spec */
> +int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
> +{
> +	struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
> +	int err;
> +
> +	if (!spec)
> +		return -ENOMEM;
> +	codec->spec = spec;
> +	snd_hda_gen_spec_init(&spec->gen);
> +	spec->gen.mixer_nid = mixer_nid;
> +	spec->gen.own_eapd_ctl = 1;
> +	codec->single_adc_amp = 1;
> +	/* FIXME: do we need this for all Realtek codec models? */
> +	codec->spdif_status_reset = 1;
> +	codec->forced_resume = 1;
> +	codec->patch_ops = alc_patch_ops;
> +	mutex_init(&spec->coef_mutex);
> +
> +	err = alc_codec_rename_from_preset(codec);
> +	if (err < 0) {
> +		kfree(spec);
> +		return err;
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_alloc_spec, "SND_HDA_CODEC_REALTEK");
> +
> +/* For dual-codec configuration, we need to disable some features to avoid
> + * conflicts of kctls and PCM streams
> + */
> +void alc_fixup_dual_codecs(struct hda_codec *codec,
> +			   const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> +		return;
> +	/* disable vmaster */
> +	spec->gen.suppress_vmaster = 1;
> +	/* auto-mute and auto-mic switch don't work with multiple codecs */
> +	spec->gen.suppress_auto_mute = 1;
> +	spec->gen.suppress_auto_mic = 1;
> +	/* disable aamix as well */
> +	spec->gen.mixer_nid = 0;
> +	/* add location prefix to avoid conflicts */
> +	codec->force_pin_prefix = 1;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_dual_codecs, "SND_HDA_CODEC_REALTEK");
> +
> +static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
> +	{ .channels = 2,
> +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
> +	{ .channels = 4,
> +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
> +		   SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
> +	{ }
> +};
> +
> +/* override the 2.1 chmap */
> +void alc_fixup_bass_chmap(struct hda_codec *codec,
> +			  const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_BUILD) {
> +		struct alc_spec *spec = codec->spec;
> +		spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_bass_chmap, "SND_HDA_CODEC_REALTEK");
> +
> +/* exported as it's used by multiple codecs */
> +void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
> +				  const struct hda_fixup *fix,
> +				  int action)
> +{
> +	alc_fixup_dual_codecs(codec, fix, action);
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		/* override card longname to provide a unique UCM profile */
> +		strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
> +		break;
> +	case HDA_FIXUP_ACT_BUILD:
> +		/* rename Capture controls depending on the codec */
> +		rename_ctl(codec, "Capture Volume",
> +			   codec->addr == 0 ?
> +			   "Rear-Panel Capture Volume" :
> +			   "Front-Panel Capture Volume");
> +		rename_ctl(codec, "Capture Switch",
> +			   codec->addr == 0 ?
> +			   "Rear-Panel Capture Switch" :
> +			   "Front-Panel Capture Switch");
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc1220_fixup_gb_dual_codecs, "SND_HDA_CODEC_REALTEK");
> +
> +void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
> +					    const struct hda_fixup *fix,
> +					    int action)
> +{
> +	alc_fixup_dual_codecs(codec, fix, action);
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		/* override card longname to provide a unique UCM profile */
> +		strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
> +		break;
> +	case HDA_FIXUP_ACT_BUILD:
> +		/* rename Capture controls depending on the codec */
> +		rename_ctl(codec, "Capture Volume",
> +			   codec->addr == 0 ?
> +			   "Rear-Panel Capture Volume" :
> +			   "Front-Panel Capture Volume");
> +		rename_ctl(codec, "Capture Switch",
> +			   codec->addr == 0 ?
> +			   "Rear-Panel Capture Switch" :
> +			   "Front-Panel Capture Switch");
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc233_alc662_fixup_lenovo_dual_codecs, "SND_HDA_CODEC_REALTEK");
> +
> +static void alc_shutup_dell_xps13(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	int hp_pin = alc_get_hp_pin(spec);
> +
> +	/* Prevent pop noises when headphones are plugged in */
> +	snd_hda_codec_write(codec, hp_pin, 0,
> +			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
> +	msleep(20);
> +}
> +
> +void alc_fixup_dell_xps13(struct hda_codec *codec,
> +			  const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	struct hda_input_mux *imux = &spec->gen.input_mux;
> +	int i;
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		/* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
> +		 * it causes a click noise at start up
> +		 */
> +		snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
> +		spec->shutup = alc_shutup_dell_xps13;
> +		break;
> +	case HDA_FIXUP_ACT_PROBE:
> +		/* Make the internal mic the default input source. */
> +		for (i = 0; i < imux->num_items; i++) {
> +			if (spec->gen.imux_pins[i] == 0x12) {
> +				spec->gen.cur_mux[0] = i;
> +				break;
> +			}
> +		}
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_dell_xps13, "SND_HDA_CODEC_REALTEK");
> +
> +/*
> + * headset handling
> + */
> +
> +static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
> +{
> +	if (delay <= 0)
> +		delay = 75;
> +	snd_hda_codec_write(codec, 0x21, 0,
> +		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
> +	msleep(delay);
> +	snd_hda_codec_write(codec, 0x21, 0,
> +		    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
> +	msleep(delay);
> +}
> +
> +static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
> +{
> +	if (delay <= 0)
> +		delay = 75;
> +	snd_hda_codec_write(codec, 0x21, 0,
> +		    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
> +	msleep(delay);
> +	snd_hda_codec_write(codec, 0x21, 0,
> +		    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
> +	msleep(delay);
> +}
> +
> +static const struct coef_fw alc225_pre_hsmode[] = {
> +	UPDATE_COEF(0x4a, 1<<8, 0),
> +	UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
> +	UPDATE_COEF(0x63, 3<<14, 3<<14),
> +	UPDATE_COEF(0x4a, 3<<4, 2<<4),
> +	UPDATE_COEF(0x4a, 3<<10, 3<<10),
> +	UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
> +	UPDATE_COEF(0x4a, 3<<10, 0),
> +	{}
> +};
> +
> +static void alc_headset_mode_unplugged(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +	static const struct coef_fw coef0255[] = {
> +		WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
> +		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
> +		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
> +		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
> +		WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
> +		{}
> +	};
> +	static const struct coef_fw coef0256[] = {
> +		WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
> +		WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
> +		WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
> +		WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
> +		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
> +		{}
> +	};
> +	static const struct coef_fw coef0233[] = {
> +		WRITE_COEF(0x1b, 0x0c0b),
> +		WRITE_COEF(0x45, 0xc429),
> +		UPDATE_COEF(0x35, 0x4000, 0),
> +		WRITE_COEF(0x06, 0x2104),
> +		WRITE_COEF(0x1a, 0x0001),
> +		WRITE_COEF(0x26, 0x0004),
> +		WRITE_COEF(0x32, 0x42a3),
> +		{}
> +	};
> +	static const struct coef_fw coef0288[] = {
> +		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
> +		UPDATE_COEF(0x50, 0x2000, 0x2000),
> +		UPDATE_COEF(0x56, 0x0006, 0x0006),
> +		UPDATE_COEF(0x66, 0x0008, 0),
> +		UPDATE_COEF(0x67, 0x2000, 0),
> +		{}
> +	};
> +	static const struct coef_fw coef0298[] = {
> +		UPDATE_COEF(0x19, 0x1300, 0x0300),
> +		{}
> +	};
> +	static const struct coef_fw coef0292[] = {
> +		WRITE_COEF(0x76, 0x000e),
> +		WRITE_COEF(0x6c, 0x2400),
> +		WRITE_COEF(0x18, 0x7308),
> +		WRITE_COEF(0x6b, 0xc429),
> +		{}
> +	};
> +	static const struct coef_fw coef0293[] = {
> +		UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
> +		UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
> +		UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
> +		UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
> +		WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
> +		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
> +		{}
> +	};
> +	static const struct coef_fw coef0668[] = {
> +		WRITE_COEF(0x15, 0x0d40),
> +		WRITE_COEF(0xb7, 0x802b),
> +		{}
> +	};
> +	static const struct coef_fw coef0225[] = {
> +		UPDATE_COEF(0x63, 3<<14, 0),
> +		{}
> +	};
> +	static const struct coef_fw coef0274[] = {
> +		UPDATE_COEF(0x4a, 0x0100, 0),
> +		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
> +		UPDATE_COEF(0x6b, 0xf000, 0x5000),
> +		UPDATE_COEF(0x4a, 0x0010, 0),
> +		UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
> +		WRITE_COEF(0x45, 0x5289),
> +		UPDATE_COEF(0x4a, 0x0c00, 0),
> +		{}
> +	};
> +
> +	if (spec->no_internal_mic_pin) {
> +		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
> +		return;
> +	}
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0255:
> +		alc_process_coef_fw(codec, coef0255);
> +		break;
> +	case 0x10ec0230:
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x19e58326:
> +		alc_hp_mute_disable(codec, 75);
> +		alc_process_coef_fw(codec, coef0256);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +	case 0x10ec0294:
> +		alc_process_coef_fw(codec, coef0274);
> +		break;
> +	case 0x10ec0233:
> +	case 0x10ec0283:
> +		alc_process_coef_fw(codec, coef0233);
> +		break;
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +		alc_process_coef_fw(codec, coef0288);
> +		break;
> +	case 0x10ec0298:
> +		alc_process_coef_fw(codec, coef0298);
> +		alc_process_coef_fw(codec, coef0288);
> +		break;
> +	case 0x10ec0292:
> +		alc_process_coef_fw(codec, coef0292);
> +		break;
> +	case 0x10ec0293:
> +		alc_process_coef_fw(codec, coef0293);
> +		break;
> +	case 0x10ec0668:
> +		alc_process_coef_fw(codec, coef0668);
> +		break;
> +	case 0x10ec0215:
> +	case 0x10ec0225:
> +	case 0x10ec0285:
> +	case 0x10ec0295:
> +	case 0x10ec0289:
> +	case 0x10ec0299:
> +		alc_hp_mute_disable(codec, 75);
> +		alc_process_coef_fw(codec, alc225_pre_hsmode);
> +		alc_process_coef_fw(codec, coef0225);
> +		break;
> +	case 0x10ec0867:
> +		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> +		break;
> +	}
> +	codec_dbg(codec, "Headset jack set to unplugged mode.\n");
> +}
> +
> +
> +static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
> +				    hda_nid_t mic_pin)
> +{
> +	static const struct coef_fw coef0255[] = {
> +		WRITE_COEFEX(0x57, 0x03, 0x8aa6),
> +		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
> +		{}
> +	};
> +	static const struct coef_fw coef0256[] = {
> +		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
> +		WRITE_COEFEX(0x57, 0x03, 0x09a3),
> +		WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
> +		{}
> +	};
> +	static const struct coef_fw coef0233[] = {
> +		UPDATE_COEF(0x35, 0, 1<<14),
> +		WRITE_COEF(0x06, 0x2100),
> +		WRITE_COEF(0x1a, 0x0021),
> +		WRITE_COEF(0x26, 0x008c),
> +		{}
> +	};
> +	static const struct coef_fw coef0288[] = {
> +		UPDATE_COEF(0x4f, 0x00c0, 0),
> +		UPDATE_COEF(0x50, 0x2000, 0),
> +		UPDATE_COEF(0x56, 0x0006, 0),
> +		UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
> +		UPDATE_COEF(0x66, 0x0008, 0x0008),
> +		UPDATE_COEF(0x67, 0x2000, 0x2000),
> +		{}
> +	};
> +	static const struct coef_fw coef0292[] = {
> +		WRITE_COEF(0x19, 0xa208),
> +		WRITE_COEF(0x2e, 0xacf0),
> +		{}
> +	};
> +	static const struct coef_fw coef0293[] = {
> +		UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
> +		UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
> +		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
> +		{}
> +	};
> +	static const struct coef_fw coef0688[] = {
> +		WRITE_COEF(0xb7, 0x802b),
> +		WRITE_COEF(0xb5, 0x1040),
> +		UPDATE_COEF(0xc3, 0, 1<<12),
> +		{}
> +	};
> +	static const struct coef_fw coef0225[] = {
> +		UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
> +		UPDATE_COEF(0x4a, 3<<4, 2<<4),
> +		UPDATE_COEF(0x63, 3<<14, 0),
> +		{}
> +	};
> +	static const struct coef_fw coef0274[] = {
> +		UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
> +		UPDATE_COEF(0x4a, 0x0010, 0),
> +		UPDATE_COEF(0x6b, 0xf000, 0),
> +		{}
> +	};
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0255:
> +		alc_write_coef_idx(codec, 0x45, 0xc489);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0255);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0230:
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x19e58326:
> +		alc_write_coef_idx(codec, 0x45, 0xc489);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0256);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +	case 0x10ec0294:
> +		alc_write_coef_idx(codec, 0x45, 0x4689);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0274);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0233:
> +	case 0x10ec0283:
> +		alc_write_coef_idx(codec, 0x45, 0xc429);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0233);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +	case 0x10ec0298:
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0288);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0292:
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0292);
> +		break;
> +	case 0x10ec0293:
> +		/* Set to TRS mode */
> +		alc_write_coef_idx(codec, 0x45, 0xc429);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0293);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0867:
> +		alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
> +		fallthrough;
> +	case 0x10ec0221:
> +	case 0x10ec0662:
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0668:
> +		alc_write_coef_idx(codec, 0x11, 0x0001);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0688);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	case 0x10ec0215:
> +	case 0x10ec0225:
> +	case 0x10ec0285:
> +	case 0x10ec0295:
> +	case 0x10ec0289:
> +	case 0x10ec0299:
> +		alc_process_coef_fw(codec, alc225_pre_hsmode);
> +		alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
> +		alc_process_coef_fw(codec, coef0225);
> +		snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
> +		break;
> +	}
> +	codec_dbg(codec, "Headset jack set to mic-in mode.\n");
> +}
> +
> +static void alc_headset_mode_default(struct hda_codec *codec)
> +{
> +	static const struct coef_fw coef0225[] = {
> +		UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
> +		UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
> +		UPDATE_COEF(0x49, 3<<8, 0<<8),
> +		UPDATE_COEF(0x4a, 3<<4, 3<<4),
> +		UPDATE_COEF(0x63, 3<<14, 0),
> +		UPDATE_COEF(0x67, 0xf000, 0x3000),
> +		{}
> +	};
> +	static const struct coef_fw coef0255[] = {
> +		WRITE_COEF(0x45, 0xc089),
> +		WRITE_COEF(0x45, 0xc489),
> +		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
> +		WRITE_COEF(0x49, 0x0049),
> +		{}
> +	};
> +	static const struct coef_fw coef0256[] = {
> +		WRITE_COEF(0x45, 0xc489),
> +		WRITE_COEFEX(0x57, 0x03, 0x0da3),
> +		WRITE_COEF(0x49, 0x0049),
> +		UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
> +		WRITE_COEF(0x06, 0x6100),
> +		{}
> +	};
> +	static const struct coef_fw coef0233[] = {
> +		WRITE_COEF(0x06, 0x2100),
> +		WRITE_COEF(0x32, 0x4ea3),
> +		{}
> +	};
> +	static const struct coef_fw coef0288[] = {
> +		UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
> +		UPDATE_COEF(0x50, 0x2000, 0x2000),
> +		UPDATE_COEF(0x56, 0x0006, 0x0006),
> +		UPDATE_COEF(0x66, 0x0008, 0),
> +		UPDATE_COEF(0x67, 0x2000, 0),
> +		{}
> +	};
> +	static const struct coef_fw coef0292[] = {
> +		WRITE_COEF(0x76, 0x000e),
> +		WRITE_COEF(0x6c, 0x2400),
> +		WRITE_COEF(0x6b, 0xc429),
> +		WRITE_COEF(0x18, 0x7308),
> +		{}
> +	};
> +	static const struct coef_fw coef0293[] = {
> +		UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
> +		WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
> +		UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
> +		{}
> +	};
> +	static const struct coef_fw coef0688[] = {
> +		WRITE_COEF(0x11, 0x0041),
> +		WRITE_COEF(0x15, 0x0d40),
> +		WRITE_COEF(0xb7, 0x802b),
> +		{}
> +	};
> +	static const struct coef_fw coef0274[] = {
> +		WRITE_COEF(0x45, 0x4289),
> +		UPDATE_COEF(0x4a, 0x0010, 0x0010),
> +		UPDATE_COEF(0x6b, 0x0f00, 0),
> +		UPDATE_COEF(0x49, 0x0300, 0x0300),
> +		{}
> +	};
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0215:
> +	case 0x10ec0225:
> +	case 0x10ec0285:
> +	case 0x10ec0295:
> +	case 0x10ec0289:
> +	case 0x10ec0299:
> +		alc_process_coef_fw(codec, alc225_pre_hsmode);
> +		alc_process_coef_fw(codec, coef0225);
> +		alc_hp_enable_unmute(codec, 75);
> +		break;
> +	case 0x10ec0255:
> +		alc_process_coef_fw(codec, coef0255);
> +		break;
> +	case 0x10ec0230:
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x19e58326:
> +		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
> +		alc_write_coef_idx(codec, 0x45, 0xc089);
> +		msleep(50);
> +		alc_process_coef_fw(codec, coef0256);
> +		alc_hp_enable_unmute(codec, 75);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +	case 0x10ec0294:
> +		alc_process_coef_fw(codec, coef0274);
> +		break;
> +	case 0x10ec0233:
> +	case 0x10ec0283:
> +		alc_process_coef_fw(codec, coef0233);
> +		break;
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +	case 0x10ec0298:
> +		alc_process_coef_fw(codec, coef0288);
> +		break;
> +	case 0x10ec0292:
> +		alc_process_coef_fw(codec, coef0292);
> +		break;
> +	case 0x10ec0293:
> +		alc_process_coef_fw(codec, coef0293);
> +		break;
> +	case 0x10ec0668:
> +		alc_process_coef_fw(codec, coef0688);
> +		break;
> +	case 0x10ec0867:
> +		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> +		break;
> +	}
> +	codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
> +}
> +
> +/* Iphone type */
> +static void alc_headset_mode_ctia(struct hda_codec *codec)
> +{
> +	int val;
> +
> +	static const struct coef_fw coef0255[] = {
> +		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
> +		WRITE_COEF(0x1b, 0x0c2b),
> +		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
> +		{}
> +	};
> +	static const struct coef_fw coef0256[] = {
> +		WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
> +		WRITE_COEF(0x1b, 0x0e6b),
> +		{}
> +	};
> +	static const struct coef_fw coef0233[] = {
> +		WRITE_COEF(0x45, 0xd429),
> +		WRITE_COEF(0x1b, 0x0c2b),
> +		WRITE_COEF(0x32, 0x4ea3),
> +		{}
> +	};
> +	static const struct coef_fw coef0288[] = {
> +		UPDATE_COEF(0x50, 0x2000, 0x2000),
> +		UPDATE_COEF(0x56, 0x0006, 0x0006),
> +		UPDATE_COEF(0x66, 0x0008, 0),
> +		UPDATE_COEF(0x67, 0x2000, 0),
> +		{}
> +	};
> +	static const struct coef_fw coef0292[] = {
> +		WRITE_COEF(0x6b, 0xd429),
> +		WRITE_COEF(0x76, 0x0008),
> +		WRITE_COEF(0x18, 0x7388),
> +		{}
> +	};
> +	static const struct coef_fw coef0293[] = {
> +		WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
> +		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
> +		{}
> +	};
> +	static const struct coef_fw coef0688[] = {
> +		WRITE_COEF(0x11, 0x0001),
> +		WRITE_COEF(0x15, 0x0d60),
> +		WRITE_COEF(0xc3, 0x0000),
> +		{}
> +	};
> +	static const struct coef_fw coef0225_1[] = {
> +		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
> +		UPDATE_COEF(0x63, 3<<14, 2<<14),
> +		{}
> +	};
> +	static const struct coef_fw coef0225_2[] = {
> +		UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
> +		UPDATE_COEF(0x63, 3<<14, 1<<14),
> +		{}
> +	};
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0255:
> +		alc_process_coef_fw(codec, coef0255);
> +		break;
> +	case 0x10ec0230:
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x19e58326:
> +		alc_process_coef_fw(codec, coef0256);
> +		alc_hp_enable_unmute(codec, 75);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +	case 0x10ec0294:
> +		alc_write_coef_idx(codec, 0x45, 0xd689);
> +		break;
> +	case 0x10ec0233:
> +	case 0x10ec0283:
> +		alc_process_coef_fw(codec, coef0233);
> +		break;
> +	case 0x10ec0298:
> +		val = alc_read_coef_idx(codec, 0x50);
> +		if (val & (1 << 12)) {
> +			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
> +			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
> +			msleep(300);
> +		} else {
> +			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
> +			alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
> +			msleep(300);
> +		}
> +		break;
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
> +		msleep(300);
> +		alc_process_coef_fw(codec, coef0288);
> +		break;
> +	case 0x10ec0292:
> +		alc_process_coef_fw(codec, coef0292);
> +		break;
> +	case 0x10ec0293:
> +		alc_process_coef_fw(codec, coef0293);
> +		break;
> +	case 0x10ec0668:
> +		alc_process_coef_fw(codec, coef0688);
> +		break;
> +	case 0x10ec0215:
> +	case 0x10ec0225:
> +	case 0x10ec0285:
> +	case 0x10ec0295:
> +	case 0x10ec0289:
> +	case 0x10ec0299:
> +		val = alc_read_coef_idx(codec, 0x45);
> +		if (val & (1 << 9))
> +			alc_process_coef_fw(codec, coef0225_2);
> +		else
> +			alc_process_coef_fw(codec, coef0225_1);
> +		alc_hp_enable_unmute(codec, 75);
> +		break;
> +	case 0x10ec0867:
> +		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> +		break;
> +	}
> +	codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
> +}
> +
> +/* Nokia type */
> +static void alc_headset_mode_omtp(struct hda_codec *codec)
> +{
> +	static const struct coef_fw coef0255[] = {
> +		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
> +		WRITE_COEF(0x1b, 0x0c2b),
> +		WRITE_COEFEX(0x57, 0x03, 0x8ea6),
> +		{}
> +	};
> +	static const struct coef_fw coef0256[] = {
> +		WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
> +		WRITE_COEF(0x1b, 0x0e6b),
> +		{}
> +	};
> +	static const struct coef_fw coef0233[] = {
> +		WRITE_COEF(0x45, 0xe429),
> +		WRITE_COEF(0x1b, 0x0c2b),
> +		WRITE_COEF(0x32, 0x4ea3),
> +		{}
> +	};
> +	static const struct coef_fw coef0288[] = {
> +		UPDATE_COEF(0x50, 0x2000, 0x2000),
> +		UPDATE_COEF(0x56, 0x0006, 0x0006),
> +		UPDATE_COEF(0x66, 0x0008, 0),
> +		UPDATE_COEF(0x67, 0x2000, 0),
> +		{}
> +	};
> +	static const struct coef_fw coef0292[] = {
> +		WRITE_COEF(0x6b, 0xe429),
> +		WRITE_COEF(0x76, 0x0008),
> +		WRITE_COEF(0x18, 0x7388),
> +		{}
> +	};
> +	static const struct coef_fw coef0293[] = {
> +		WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
> +		UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
> +		{}
> +	};
> +	static const struct coef_fw coef0688[] = {
> +		WRITE_COEF(0x11, 0x0001),
> +		WRITE_COEF(0x15, 0x0d50),
> +		WRITE_COEF(0xc3, 0x0000),
> +		{}
> +	};
> +	static const struct coef_fw coef0225[] = {
> +		UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
> +		UPDATE_COEF(0x63, 3<<14, 2<<14),
> +		{}
> +	};
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0255:
> +		alc_process_coef_fw(codec, coef0255);
> +		break;
> +	case 0x10ec0230:
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x19e58326:
> +		alc_process_coef_fw(codec, coef0256);
> +		alc_hp_enable_unmute(codec, 75);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +	case 0x10ec0294:
> +		alc_write_coef_idx(codec, 0x45, 0xe689);
> +		break;
> +	case 0x10ec0233:
> +	case 0x10ec0283:
> +		alc_process_coef_fw(codec, coef0233);
> +		break;
> +	case 0x10ec0298:
> +		alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
> +		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
> +		msleep(300);
> +		break;
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +		alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
> +		msleep(300);
> +		alc_process_coef_fw(codec, coef0288);
> +		break;
> +	case 0x10ec0292:
> +		alc_process_coef_fw(codec, coef0292);
> +		break;
> +	case 0x10ec0293:
> +		alc_process_coef_fw(codec, coef0293);
> +		break;
> +	case 0x10ec0668:
> +		alc_process_coef_fw(codec, coef0688);
> +		break;
> +	case 0x10ec0215:
> +	case 0x10ec0225:
> +	case 0x10ec0285:
> +	case 0x10ec0295:
> +	case 0x10ec0289:
> +	case 0x10ec0299:
> +		alc_process_coef_fw(codec, coef0225);
> +		alc_hp_enable_unmute(codec, 75);
> +		break;
> +	}
> +	codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
> +}
> +
> +static void alc_determine_headset_type(struct hda_codec *codec)
> +{
> +	int val;
> +	bool is_ctia = false;
> +	struct alc_spec *spec = codec->spec;
> +	static const struct coef_fw coef0255[] = {
> +		WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
> +		WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
> + conteol) */
> +		{}
> +	};
> +	static const struct coef_fw coef0288[] = {
> +		UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
> +		{}
> +	};
> +	static const struct coef_fw coef0298[] = {
> +		UPDATE_COEF(0x50, 0x2000, 0x2000),
> +		UPDATE_COEF(0x56, 0x0006, 0x0006),
> +		UPDATE_COEF(0x66, 0x0008, 0),
> +		UPDATE_COEF(0x67, 0x2000, 0),
> +		UPDATE_COEF(0x19, 0x1300, 0x1300),
> +		{}
> +	};
> +	static const struct coef_fw coef0293[] = {
> +		UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
> +		WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
> +		{}
> +	};
> +	static const struct coef_fw coef0688[] = {
> +		WRITE_COEF(0x11, 0x0001),
> +		WRITE_COEF(0xb7, 0x802b),
> +		WRITE_COEF(0x15, 0x0d60),
> +		WRITE_COEF(0xc3, 0x0c00),
> +		{}
> +	};
> +	static const struct coef_fw coef0274[] = {
> +		UPDATE_COEF(0x4a, 0x0010, 0),
> +		UPDATE_COEF(0x4a, 0x8000, 0),
> +		WRITE_COEF(0x45, 0xd289),
> +		UPDATE_COEF(0x49, 0x0300, 0x0300),
> +		{}
> +	};
> +
> +	if (spec->no_internal_mic_pin) {
> +		alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
> +		return;
> +	}
> +
> +	switch (codec->core.vendor_id) {
> +	case 0x10ec0255:
> +		alc_process_coef_fw(codec, coef0255);
> +		msleep(300);
> +		val = alc_read_coef_idx(codec, 0x46);
> +		is_ctia = (val & 0x0070) == 0x0070;
> +		break;
> +	case 0x10ec0230:
> +	case 0x10ec0236:
> +	case 0x10ec0256:
> +	case 0x19e58326:
> +		alc_write_coef_idx(codec, 0x1b, 0x0e4b);
> +		alc_write_coef_idx(codec, 0x06, 0x6104);
> +		alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
> +
> +		alc_process_coef_fw(codec, coef0255);
> +		msleep(300);
> +		val = alc_read_coef_idx(codec, 0x46);
> +		is_ctia = (val & 0x0070) == 0x0070;
> +		if (!is_ctia) {
> +			alc_write_coef_idx(codec, 0x45, 0xe089);
> +			msleep(100);
> +			val = alc_read_coef_idx(codec, 0x46);
> +			if ((val & 0x0070) == 0x0070)
> +				is_ctia = false;
> +			else
> +				is_ctia = true;
> +		}
> +		alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
> +		alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
> +		break;
> +	case 0x10ec0234:
> +	case 0x10ec0274:
> +	case 0x10ec0294:
> +		alc_process_coef_fw(codec, coef0274);
> +		msleep(850);
> +		val = alc_read_coef_idx(codec, 0x46);
> +		is_ctia = (val & 0x00f0) == 0x00f0;
> +		break;
> +	case 0x10ec0233:
> +	case 0x10ec0283:
> +		alc_write_coef_idx(codec, 0x45, 0xd029);
> +		msleep(300);
> +		val = alc_read_coef_idx(codec, 0x46);
> +		is_ctia = (val & 0x0070) == 0x0070;
> +		break;
> +	case 0x10ec0298:
> +		snd_hda_codec_write(codec, 0x21, 0,
> +			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
> +		msleep(100);
> +		snd_hda_codec_write(codec, 0x21, 0,
> +			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
> +		msleep(200);
> +
> +		val = alc_read_coef_idx(codec, 0x50);
> +		if (val & (1 << 12)) {
> +			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
> +			alc_process_coef_fw(codec, coef0288);
> +			msleep(350);
> +			val = alc_read_coef_idx(codec, 0x50);
> +			is_ctia = (val & 0x0070) == 0x0070;
> +		} else {
> +			alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
> +			alc_process_coef_fw(codec, coef0288);
> +			msleep(350);
> +			val = alc_read_coef_idx(codec, 0x50);
> +			is_ctia = (val & 0x0070) == 0x0070;
> +		}
> +		alc_process_coef_fw(codec, coef0298);
> +		snd_hda_codec_write(codec, 0x21, 0,
> +			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
> +		msleep(75);
> +		snd_hda_codec_write(codec, 0x21, 0,
> +			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
> +		break;
> +	case 0x10ec0286:
> +	case 0x10ec0288:
> +		alc_process_coef_fw(codec, coef0288);
> +		msleep(350);
> +		val = alc_read_coef_idx(codec, 0x50);
> +		is_ctia = (val & 0x0070) == 0x0070;
> +		break;
> +	case 0x10ec0292:
> +		alc_write_coef_idx(codec, 0x6b, 0xd429);
> +		msleep(300);
> +		val = alc_read_coef_idx(codec, 0x6c);
> +		is_ctia = (val & 0x001c) == 0x001c;
> +		break;
> +	case 0x10ec0293:
> +		alc_process_coef_fw(codec, coef0293);
> +		msleep(300);
> +		val = alc_read_coef_idx(codec, 0x46);
> +		is_ctia = (val & 0x0070) == 0x0070;
> +		break;
> +	case 0x10ec0668:
> +		alc_process_coef_fw(codec, coef0688);
> +		msleep(300);
> +		val = alc_read_coef_idx(codec, 0xbe);
> +		is_ctia = (val & 0x1c02) == 0x1c02;
> +		break;
> +	case 0x10ec0215:
> +	case 0x10ec0225:
> +	case 0x10ec0285:
> +	case 0x10ec0295:
> +	case 0x10ec0289:
> +	case 0x10ec0299:
> +		alc_process_coef_fw(codec, alc225_pre_hsmode);
> +		alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
> +		val = alc_read_coef_idx(codec, 0x45);
> +		if (val & (1 << 9)) {
> +			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
> +			alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
> +			msleep(800);
> +			val = alc_read_coef_idx(codec, 0x46);
> +			is_ctia = (val & 0x00f0) == 0x00f0;
> +		} else {
> +			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
> +			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
> +			msleep(800);
> +			val = alc_read_coef_idx(codec, 0x46);
> +			is_ctia = (val & 0x00f0) == 0x00f0;
> +		}
> +		if (!is_ctia) {
> +			alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
> +			alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
> +			msleep(100);
> +			val = alc_read_coef_idx(codec, 0x46);
> +			if ((val & 0x00f0) == 0x00f0)
> +				is_ctia = false;
> +			else
> +				is_ctia = true;
> +		}
> +		alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
> +		alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
> +		alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
> +		break;
> +	case 0x10ec0867:
> +		is_ctia = true;
> +		break;
> +	}
> +
> +	codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
> +		  str_yes_no(is_ctia));
> +	spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
> +}
> +
> +static void alc_update_headset_mode(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
> +	hda_nid_t hp_pin = alc_get_hp_pin(spec);
> +
> +	int new_headset_mode;
> +
> +	if (!snd_hda_jack_detect(codec, hp_pin))
> +		new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
> +	else if (mux_pin == spec->headset_mic_pin)
> +		new_headset_mode = ALC_HEADSET_MODE_HEADSET;
> +	else if (mux_pin == spec->headphone_mic_pin)
> +		new_headset_mode = ALC_HEADSET_MODE_MIC;
> +	else
> +		new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
> +
> +	if (new_headset_mode == spec->current_headset_mode) {
> +		snd_hda_gen_update_outputs(codec);
> +		return;
> +	}
> +
> +	switch (new_headset_mode) {
> +	case ALC_HEADSET_MODE_UNPLUGGED:
> +		alc_headset_mode_unplugged(codec);
> +		spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
> +		spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
> +		spec->gen.hp_jack_present = false;
> +		break;
> +	case ALC_HEADSET_MODE_HEADSET:
> +		if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
> +			alc_determine_headset_type(codec);
> +		if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
> +			alc_headset_mode_ctia(codec);
> +		else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
> +			alc_headset_mode_omtp(codec);
> +		spec->gen.hp_jack_present = true;
> +		break;
> +	case ALC_HEADSET_MODE_MIC:
> +		alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
> +		spec->gen.hp_jack_present = false;
> +		break;
> +	case ALC_HEADSET_MODE_HEADPHONE:
> +		alc_headset_mode_default(codec);
> +		spec->gen.hp_jack_present = true;
> +		break;
> +	}
> +	if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
> +		snd_hda_set_pin_ctl_cache(codec, hp_pin,
> +					  AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
> +		if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
> +			snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
> +						  PIN_VREFHIZ);
> +	}
> +	spec->current_headset_mode = new_headset_mode;
> +
> +	snd_hda_gen_update_outputs(codec);
> +}
> +
> +static void alc_update_headset_mode_hook(struct hda_codec *codec,
> +					 struct snd_kcontrol *kcontrol,
> +					 struct snd_ctl_elem_value *ucontrol)
> +{
> +	alc_update_headset_mode(codec);
> +}
> +
> +void alc_update_headset_jack_cb(struct hda_codec *codec,
> +				struct hda_jack_callback *jack)
> +{
> +	snd_hda_gen_hp_automute(codec, jack);
> +	alc_update_headset_mode(codec);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_update_headset_jack_cb, "SND_HDA_CODEC_REALTEK");
> +
> +static void alc_probe_headset_mode(struct hda_codec *codec)
> +{
> +	int i;
> +	struct alc_spec *spec = codec->spec;
> +	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
> +
> +	/* Find mic pins */
> +	for (i = 0; i < cfg->num_inputs; i++) {
> +		if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
> +			spec->headset_mic_pin = cfg->inputs[i].pin;
> +		if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
> +			spec->headphone_mic_pin = cfg->inputs[i].pin;
> +	}
> +
> +	WARN_ON(spec->gen.cap_sync_hook);
> +	spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
> +	spec->gen.automute_hook = alc_update_headset_mode;
> +	spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
> +}
> +
> +void alc_fixup_headset_mode(struct hda_codec *codec,
> +			    const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
> +		break;
> +	case HDA_FIXUP_ACT_PROBE:
> +		alc_probe_headset_mode(codec);
> +		break;
> +	case HDA_FIXUP_ACT_INIT:
> +		if (is_s3_resume(codec) || is_s4_resume(codec)) {
> +			spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
> +			spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
> +		}
> +		alc_update_headset_mode(codec);
> +		break;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
> +				      const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		struct alc_spec *spec = codec->spec;
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +	}
> +	else
> +		alc_fixup_headset_mode(codec, fix, action);
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode_no_hp_mic, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_headset_mic(struct hda_codec *codec,
> +			   const struct hda_fixup *fix, int action)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mic, "SND_HDA_CODEC_REALTEK");
> +
> +/* update LED status via GPIO */
> +void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
> +			 int polarity, bool enabled)
> +{
> +	if (polarity)
> +		enabled = !enabled;
> +	alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_update_gpio_led, "SND_HDA_CODEC_REALTEK");
> +
> +/* turn on/off mic-mute LED via GPIO per capture hook */
> +static int micmute_led_set(struct led_classdev *led_cdev,
> +			   enum led_brightness brightness)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
> +	struct alc_spec *spec = codec->spec;
> +
> +	alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
> +			    spec->micmute_led_polarity, !brightness);
> +	return 0;
> +}
> +
> +/* turn on/off mute LED via GPIO per vmaster hook */
> +static int gpio_mute_led_set(struct led_classdev *led_cdev,
> +			     enum led_brightness brightness)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
> +	struct alc_spec *spec = codec->spec;
> +
> +	alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
> +			    spec->mute_led_polarity, !brightness);
> +	return 0;
> +}
> +
> +/* setup mute and mic-mute GPIO bits, add hooks appropriately */
> +void alc_fixup_hp_gpio_led(struct hda_codec *codec,
> +			   int action,
> +			   unsigned int mute_mask,
> +			   unsigned int micmute_mask)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
> +
> +	if (action != HDA_FIXUP_ACT_PRE_PROBE)
> +		return;
> +	if (mute_mask) {
> +		spec->gpio_mute_led_mask = mute_mask;
> +		snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
> +	}
> +	if (micmute_mask) {
> +		spec->gpio_mic_led_mask = micmute_mask;
> +		snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_hp_gpio_led, "SND_HDA_CODEC_REALTEK");
> +
> +/* suppress the jack-detection */
> +void alc_fixup_no_jack_detect(struct hda_codec *codec,
> +			      const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +		codec->no_jack_detect = 1;
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_no_jack_detect, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_disable_aamix(struct hda_codec *codec,
> +			     const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		struct alc_spec *spec = codec->spec;
> +		/* Disable AA-loopback as it causes white noise */
> +		spec->gen.mixer_nid = 0;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_disable_aamix, "SND_HDA_CODEC_REALTEK");
> +
> +void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
> +				 const struct hda_fixup *fix, int action)
> +{
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		struct alc_spec *spec = codec->spec;
> +		spec->gen.auto_mute_via_amp = 1;
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(alc_fixup_auto_mute_via_amp, "SND_HDA_CODEC_REALTEK");
> +
> +MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Realtek HD-audio codec helper");
> diff --git a/sound/hda/codecs/realtek/realtek.h b/sound/hda/codecs/realtek/realtek.h
> new file mode 100644
> index 000000000000..ac142f2540e3
> --- /dev/null
> +++ b/sound/hda/codecs/realtek/realtek.h
> @@ -0,0 +1,302 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// Realtek HD-audio codec support code
> +//
> +
> +#ifndef __HDA_REALTEK_H
> +#define __HDA_REALTEK_H
> +
> +#include <linux/acpi.h>
> +#include <linux/cleanup.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/pci.h>
> +#include <linux/dmi.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/leds.h>
> +#include <linux/ctype.h>
> +#include <linux/spi/spi.h>
> +#include <sound/core.h>
> +#include <sound/jack.h>
> +#include <sound/hda_codec.h>
> +#include "hda_local.h"
> +#include "hda_auto_parser.h"
> +#include "hda_beep.h"
> +#include "hda_jack.h"
> +#include "../generic.h"
> +#include "../side-codecs/hda_component.h"
> +
> +/* extra amp-initialization sequence types */
> +enum {
> +	ALC_INIT_UNDEFINED,
> +	ALC_INIT_NONE,
> +	ALC_INIT_DEFAULT,
> +};
> +
> +enum {
> +	ALC_HEADSET_MODE_UNKNOWN,
> +	ALC_HEADSET_MODE_UNPLUGGED,
> +	ALC_HEADSET_MODE_HEADSET,
> +	ALC_HEADSET_MODE_MIC,
> +	ALC_HEADSET_MODE_HEADPHONE,
> +};
> +
> +enum {
> +	ALC_HEADSET_TYPE_UNKNOWN,
> +	ALC_HEADSET_TYPE_CTIA,
> +	ALC_HEADSET_TYPE_OMTP,
> +};
> +
> +enum {
> +	ALC_KEY_MICMUTE_INDEX,
> +};
> +
> +struct alc_customize_define {
> +	unsigned int  sku_cfg;
> +	unsigned char port_connectivity;
> +	unsigned char check_sum;
> +	unsigned char customization;
> +	unsigned char external_amp;
> +	unsigned int  enable_pcbeep:1;
> +	unsigned int  platform_type:1;
> +	unsigned int  swap:1;
> +	unsigned int  override:1;
> +	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
> +};
> +
> +struct alc_coef_led {
> +	unsigned int idx;
> +	unsigned int mask;
> +	unsigned int on;
> +	unsigned int off;
> +};
> +
> +struct alc_spec {
> +	struct hda_gen_spec gen; /* must be at head */
> +
> +	/* codec parameterization */
> +	struct alc_customize_define cdefine;
> +	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
> +
> +	/* GPIO bits */
> +	unsigned int gpio_mask;
> +	unsigned int gpio_dir;
> +	unsigned int gpio_data;
> +	bool gpio_write_delay;	/* add a delay before writing gpio_data */
> +
> +	/* mute LED for HP laptops, see vref_mute_led_set() */
> +	int mute_led_polarity;
> +	int micmute_led_polarity;
> +	hda_nid_t mute_led_nid;
> +	hda_nid_t cap_mute_led_nid;
> +
> +	unsigned int gpio_mute_led_mask;
> +	unsigned int gpio_mic_led_mask;
> +	struct alc_coef_led mute_led_coef;
> +	struct alc_coef_led mic_led_coef;
> +	struct mutex coef_mutex;
> +
> +	hda_nid_t headset_mic_pin;
> +	hda_nid_t headphone_mic_pin;
> +	int current_headset_mode;
> +	int current_headset_type;
> +
> +	/* hooks */
> +	void (*init_hook)(struct hda_codec *codec);
> +	void (*power_hook)(struct hda_codec *codec);
> +	void (*shutup)(struct hda_codec *codec);
> +
> +	int init_amp;
> +	int codec_variant;	/* flag for other variants */
> +	unsigned int has_alc5505_dsp:1;
> +	unsigned int no_depop_delay:1;
> +	unsigned int done_hp_init:1;
> +	unsigned int no_shutup_pins:1;
> +	unsigned int ultra_low_power:1;
> +	unsigned int has_hs_key:1;
> +	unsigned int no_internal_mic_pin:1;
> +	unsigned int en_3kpull_low:1;
> +	int num_speaker_amps;
> +
> +	/* for PLL fix */
> +	hda_nid_t pll_nid;
> +	unsigned int pll_coef_idx, pll_coef_bit;
> +	unsigned int coef0;
> +	struct input_dev *kb_dev;
> +	u8 alc_mute_keycode_map[1];
> +
> +	/* component binding */
> +	struct hda_component_parent comps;
> +};
> +
> +int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +			unsigned int coef_idx);
> +void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +			  unsigned int coef_idx, unsigned int coef_val);
> +void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
> +			   unsigned int coef_idx, unsigned int mask,
> +			   unsigned int bits_set);
> +#define alc_read_coef_idx(codec, coef_idx) \
> +	alc_read_coefex_idx(codec, 0x20, coef_idx)
> +#define alc_write_coef_idx(codec, coef_idx, coef_val) \
> +	alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
> +#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)	\
> +	alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
> +
> +unsigned int alc_get_coef0(struct hda_codec *codec);
> +
> +/* coef writes/updates batch */
> +struct coef_fw {
> +	unsigned char nid;
> +	unsigned char idx;
> +	unsigned short mask;
> +	unsigned short val;
> +};
> +
> +#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
> +	{ .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
> +#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
> +#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
> +#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
> +
> +void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw);
> +
> +/*
> + * GPIO helpers
> + */
> +void alc_setup_gpio(struct hda_codec *codec, unsigned int mask);
> +void alc_write_gpio_data(struct hda_codec *codec);
> +void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
> +			  bool on);
> +void alc_write_gpio(struct hda_codec *codec);
> +
> +/* common GPIO fixups */
> +void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask);
> +void alc_fixup_gpio1(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action);
> +void alc_fixup_gpio2(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action);
> +void alc_fixup_gpio3(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action);
> +void alc_fixup_gpio4(struct hda_codec *codec,
> +		     const struct hda_fixup *fix, int action);
> +void alc_fixup_micmute_led(struct hda_codec *codec,
> +			   const struct hda_fixup *fix, int action);
> +
> +/*
> + * Common init code, callbacks and helpers
> + */
> +void alc_fix_pll(struct hda_codec *codec);
> +void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
> +		      unsigned int coef_idx, unsigned int coef_bit);
> +void alc_fill_eapd_coef(struct hda_codec *codec);
> +void alc_auto_setup_eapd(struct hda_codec *codec, bool on);
> +
> +int alc_find_ext_mic_pin(struct hda_codec *codec);
> +void alc_headset_mic_no_shutup(struct hda_codec *codec);
> +void alc_shutup_pins(struct hda_codec *codec);
> +void alc_eapd_shutup(struct hda_codec *codec);
> +void alc_auto_init_amp(struct hda_codec *codec, int type);
> +hda_nid_t alc_get_hp_pin(struct alc_spec *spec);
> +int alc_auto_parse_customize_define(struct hda_codec *codec);
> +int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports);
> +void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports);
> +int alc_build_controls(struct hda_codec *codec);
> +void alc_update_knob_master(struct hda_codec *codec,
> +			    struct hda_jack_callback *jack);
> +
> +static inline void alc_pre_init(struct hda_codec *codec)
> +{
> +	alc_fill_eapd_coef(codec);
> +}
> +
> +#define is_s3_resume(codec) \
> +	((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
> +#define is_s4_resume(codec) \
> +	((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
> +#define is_s4_suspend(codec) \
> +	((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
> +
> +int alc_init(struct hda_codec *codec);
> +void alc_shutup(struct hda_codec *codec);
> +void alc_power_eapd(struct hda_codec *codec);
> +int alc_suspend(struct hda_codec *codec);
> +int alc_resume(struct hda_codec *codec);
> +
> +#define alc_free	snd_hda_gen_free
> +
> +int alc_parse_auto_config(struct hda_codec *codec,
> +			  const hda_nid_t *ignore_nids,
> +			  const hda_nid_t *ssid_nids);
> +int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid);
> +
> +extern const struct hda_codec_ops alc_patch_ops;
> +
> +#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
> +
> +#ifdef CONFIG_SND_HDA_INPUT_BEEP
> +int alc_set_beep_amp(struct alc_spec *spec, hda_nid_t nid, int idx, int dir);
> +int alc_has_cdefine_beep(struct hda_codec *codec);
> +#define set_beep_amp		alc_set_beep_amp
> +#define has_cdefine_beep	alc_has_cdefine_beep
> +#else
> +#define set_beep_amp(spec, nid, idx, dir)	0
> +#define has_cdefine_beep(codec)		0
> +#endif
> +
> +static inline void rename_ctl(struct hda_codec *codec, const char *oldname,
> +			      const char *newname)
> +{
> +	struct snd_kcontrol *kctl;
> +
> +	kctl = snd_hda_find_mixer_ctl(codec, oldname);
> +	if (kctl)
> +		snd_ctl_rename(codec->card, kctl, newname);
> +}
> +
> +/* Common fixups */
> +void alc_fixup_sku_ignore(struct hda_codec *codec,
> +			  const struct hda_fixup *fix, int action);
> +void alc_fixup_no_depop_delay(struct hda_codec *codec,
> +			      const struct hda_fixup *fix, int action);
> +void alc_fixup_inv_dmic(struct hda_codec *codec,
> +			const struct hda_fixup *fix, int action);
> +void alc_fixup_dual_codecs(struct hda_codec *codec,
> +			   const struct hda_fixup *fix, int action);
> +void alc_fixup_bass_chmap(struct hda_codec *codec,
> +			  const struct hda_fixup *fix, int action);
> +void alc_fixup_headset_mode(struct hda_codec *codec,
> +			    const struct hda_fixup *fix, int action);
> +void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
> +				      const struct hda_fixup *fix, int action);
> +void alc_fixup_headset_mic(struct hda_codec *codec,
> +			   const struct hda_fixup *fix, int action);
> +void alc_update_headset_jack_cb(struct hda_codec *codec,
> +				struct hda_jack_callback *jack);
> +void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
> +			 int polarity, bool enabled);
> +void alc_fixup_hp_gpio_led(struct hda_codec *codec,
> +			   int action,
> +			   unsigned int mute_mask,
> +			   unsigned int micmute_mask);
> +void alc_fixup_no_jack_detect(struct hda_codec *codec,
> +			      const struct hda_fixup *fix, int action);
> +void alc_fixup_disable_aamix(struct hda_codec *codec,
> +			     const struct hda_fixup *fix, int action);
> +void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
> +				 const struct hda_fixup *fix, int action);
> +
> +/* device-specific, but used by multiple codec drivers */
> +void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
> +				  const struct hda_fixup *fix,
> +				  int action);
> +void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
> +					    const struct hda_fixup *fix,
> +					    int action);
> +void alc_fixup_dell_xps13(struct hda_codec *codec,
> +			  const struct hda_fixup *fix, int action);
> +
> +#endif /* __HDA_REALTEK_H */


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-14  8:57   ` Cezary Rojewski
@ 2025-07-14  9:04     ` Takashi Iwai
  2025-07-14  9:08       ` Cezary Rojewski
  0 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-14  9:04 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: Takashi Iwai, linux-sound, Richard Fitzgerald, Kailang,
	Kai Vehmanen, Amadeusz Sławiński, patches, Baojun Xu,
	bo liu

On Mon, 14 Jul 2025 10:57:59 +0200,
Cezary Rojewski wrote:
> 
> On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> > Now move the all remaining codec drivers from sound/pci/hda to
> > sound/hda/codecs subdirectory.  Some drivers are put under the further
> > vendor subdirectory, and the vendor helper code (*_helper.c) are put
> > under helpers subdirectory.  Also the sub-codec drivers are moved under
> > a different subdirectory, sound/hda/codecs/sub-codecs, for
> > distinguishing from the main HD-audio codec drivers.
> > 
> > The prefix patch_ and hda_ as well as the suffix _helper are dropped
> > from file names as they are mostly superfluous.
> > 
> > No functional changes but just file path shuffling.
> > 
> 
> Path: codecs/side-codecs/ looks wierd. My suggestion is to avoid the
> repeat and stay with codecs/side/.

Sorry, too late, I already merged the stuff.  (And IMO codecs/side
doesn't sound intuitive.)

Since the directory names are more or less understandable, and Cirrus
people seem OK with it, so let's leave as is.


thanks,

Takashi

> 
> In regard to 'helpers', I believe some of these .c files could be
> converted to headers and lie in sound/hda/quirks/ directory. These are
> more of a platform-level files, not sound/hda/codecs/ per-se.
> 
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > ---
> >   sound/hda/Kconfig                             |   1 +
> >   sound/hda/Makefile                            |   1 +
> >   sound/{pci/hda => hda/codecs}/Kconfig         | 158 +-----------------
> >   sound/hda/codecs/Makefile                     |  31 ++++
> >   .../patch_analog.c => hda/codecs/analog.c}    |   2 +-
> >   .../patch_ca0110.c => hda/codecs/ca0110.c}    |   2 +-
> >   .../patch_ca0132.c => hda/codecs/ca0132.c}    |   2 +-
> >   sound/{pci/hda => hda/codecs}/ca0132_regs.h   |   0
> >   sound/hda/codecs/cirrus/Kconfig               |  21 +++
> >   sound/hda/codecs/cirrus/Makefile              |   8 +
> >   .../codecs/cirrus/cirrus.c}                   |   2 +-
> >   .../codecs/cirrus/cs8409-tables.c}            |   4 +-
> >   .../codecs/cirrus/cs8409.c}                   |   2 +-
> >   .../codecs/cirrus/cs8409.h}                   |   2 +-
> >   .../patch_cmedia.c => hda/codecs/cmedia.c}    |   2 +-
> >   .../codecs/conexant.c}                        |   6 +-
> >   .../hda_generic.c => hda/codecs/generic.c}    |   2 +-
> >   .../hda_generic.h => hda/codecs/generic.h}    |   0
> >   sound/hda/codecs/hdmi/Makefile                |   6 +
> >   .../hda/hda_eld.c => hda/codecs/hdmi/eld.c}   |   0
> >   .../patch_hdmi.c => hda/codecs/hdmi/hdmi.c}   |   2 +-
> >   .../codecs/helpers/hp_x360.c}                 |   0
> >   .../codecs/helpers/ideapad_hotkey_led.c}      |   0
> >   .../codecs/helpers/ideapad_s740.c}            |   0
> >   .../codecs/helpers/thinkpad.c}                |   0
> >   .../patch_realtek.c => hda/codecs/realtek.c}  |  12 +-
> >   .../codecs/senarytech.c}                      |   4 +-
> >   .../patch_si3054.c => hda/codecs/si3054.c}    |   0
> >   sound/hda/codecs/side-codecs/Kconfig          | 128 ++++++++++++++
> >   sound/hda/codecs/side-codecs/Makefile         |  28 ++++
> >   .../codecs/side-codecs}/cirrus_scodec.c       |   0
> >   .../codecs/side-codecs}/cirrus_scodec.h       |   0
> >   .../codecs/side-codecs}/cirrus_scodec_test.c  |   0
> >   .../codecs/side-codecs}/cs35l41_hda.c         |   2 +-
> >   .../codecs/side-codecs}/cs35l41_hda.h         |   0
> >   .../codecs/side-codecs}/cs35l41_hda_i2c.c     |   0
> >   .../side-codecs}/cs35l41_hda_property.c       |   0
> >   .../side-codecs}/cs35l41_hda_property.h       |   0
> >   .../codecs/side-codecs}/cs35l41_hda_spi.c     |   0
> >   .../codecs/side-codecs}/cs35l56_hda.c         |   2 +-
> >   .../codecs/side-codecs}/cs35l56_hda.h         |   0
> >   .../codecs/side-codecs}/cs35l56_hda_i2c.c     |   0
> >   .../codecs/side-codecs}/cs35l56_hda_spi.c     |   0
> >   .../codecs/side-codecs}/hda_component.c       |   0
> >   .../codecs/side-codecs}/hda_component.h       |   0
> >   .../codecs/side-codecs}/tas2781_hda.c         |   0
> >   .../codecs/side-codecs}/tas2781_hda.h         |   0
> >   .../codecs/side-codecs}/tas2781_hda_i2c.c     |   2 +-
> >   .../codecs/side-codecs}/tas2781_hda_spi.c     |   2 +-
> >   .../codecs/sigmatel.c}                        |   4 +-
> >   .../{pci/hda/patch_via.c => hda/codecs/via.c} |   2 +-
> >   sound/pci/Kconfig                             |   2 -
> >   sound/pci/Makefile                            |   1 -
> >   sound/pci/hda/Makefile                        |  61 -------
> >   54 files changed, 257 insertions(+), 247 deletions(-)
> >   rename sound/{pci/hda => hda/codecs}/Kconfig (55%)
> >   create mode 100644 sound/hda/codecs/Makefile
> >   rename sound/{pci/hda/patch_analog.c => hda/codecs/analog.c} (99%)
> >   rename sound/{pci/hda/patch_ca0110.c => hda/codecs/ca0110.c} (98%)
> >   rename sound/{pci/hda/patch_ca0132.c => hda/codecs/ca0132.c} (99%)
> >   rename sound/{pci/hda => hda/codecs}/ca0132_regs.h (100%)
> >   create mode 100644 sound/hda/codecs/cirrus/Kconfig
> >   create mode 100644 sound/hda/codecs/cirrus/Makefile
> >   rename sound/{pci/hda/patch_cirrus.c => hda/codecs/cirrus/cirrus.c} (99%)
> >   rename sound/{pci/hda/patch_cs8409-tables.c => hda/codecs/cirrus/cs8409-tables.c} (99%)
> >   rename sound/{pci/hda/patch_cs8409.c => hda/codecs/cirrus/cs8409.c} (99%)
> >   rename sound/{pci/hda/patch_cs8409.h => hda/codecs/cirrus/cs8409.h} (99%)
> >   rename sound/{pci/hda/patch_cmedia.c => hda/codecs/cmedia.c} (99%)
> >   rename sound/{pci/hda/patch_conexant.c => hda/codecs/conexant.c} (99%)
> >   rename sound/{pci/hda/hda_generic.c => hda/codecs/generic.c} (99%)
> >   rename sound/{pci/hda/hda_generic.h => hda/codecs/generic.h} (100%)
> >   create mode 100644 sound/hda/codecs/hdmi/Makefile
> >   rename sound/{pci/hda/hda_eld.c => hda/codecs/hdmi/eld.c} (100%)
> >   rename sound/{pci/hda/patch_hdmi.c => hda/codecs/hdmi/hdmi.c} (99%)
> >   rename sound/{pci/hda/hp_x360_helper.c => hda/codecs/helpers/hp_x360.c} (100%)
> >   rename sound/{pci/hda/ideapad_hotkey_led_helper.c => hda/codecs/helpers/ideapad_hotkey_led.c} (100%)
> >   rename sound/{pci/hda/ideapad_s740_helper.c => hda/codecs/helpers/ideapad_s740.c} (100%)
> >   rename sound/{pci/hda/thinkpad_helper.c => hda/codecs/helpers/thinkpad.c} (100%)
> >   rename sound/{pci/hda/patch_realtek.c => hda/codecs/realtek.c} (99%)
> >   rename sound/{pci/hda/patch_senarytech.c => hda/codecs/senarytech.c} (98%)
> >   rename sound/{pci/hda/patch_si3054.c => hda/codecs/si3054.c} (100%)
> >   create mode 100644 sound/hda/codecs/side-codecs/Kconfig
> >   create mode 100644 sound/hda/codecs/side-codecs/Makefile
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.h (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec_test.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.c (99%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.h (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_i2c.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.h (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_spi.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.c (99%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.h (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_i2c.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_spi.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.h (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.c (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.h (100%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_i2c.c (99%)
> >   rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_spi.c (99%)
> >   rename sound/{pci/hda/patch_sigmatel.c => hda/codecs/sigmatel.c} (99%)
> >   rename sound/{pci/hda/patch_via.c => hda/codecs/via.c} (99%)
> >   delete mode 100644 sound/pci/hda/Makefile

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-14  9:04     ` Takashi Iwai
@ 2025-07-14  9:08       ` Cezary Rojewski
  2025-07-14  9:15         ` Takashi Iwai
  0 siblings, 1 reply; 48+ messages in thread
From: Cezary Rojewski @ 2025-07-14  9:08 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: linux-sound, Richard Fitzgerald, Kailang, Kai Vehmanen,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 2025-07-14 11:04 AM, Takashi Iwai wrote:
> On Mon, 14 Jul 2025 10:57:59 +0200,
> Cezary Rojewski wrote:
>>
>> On 2025-07-09 6:04 PM, Takashi Iwai wrote:
>>> Now move the all remaining codec drivers from sound/pci/hda to
>>> sound/hda/codecs subdirectory.  Some drivers are put under the further
>>> vendor subdirectory, and the vendor helper code (*_helper.c) are put
>>> under helpers subdirectory.  Also the sub-codec drivers are moved under
>>> a different subdirectory, sound/hda/codecs/sub-codecs, for
>>> distinguishing from the main HD-audio codec drivers.
>>>
>>> The prefix patch_ and hda_ as well as the suffix _helper are dropped
>>> from file names as they are mostly superfluous.
>>>
>>> No functional changes but just file path shuffling.
>>>
>>
>> Path: codecs/side-codecs/ looks wierd. My suggestion is to avoid the
>> repeat and stay with codecs/side/.
> 
> Sorry, too late, I already merged the stuff.  (And IMO codecs/side
> doesn't sound intuitive.)
> 
> Since the directory names are more or less understandable, and Cirrus
> people seem OK with it, so let's leave as is.

Oh, didn't notice. The series is large and I wasn't expecting it to get 
merged that quickly.

Guess no point in reviewing the rest then, thanks for the information!

>>
>> In regard to 'helpers', I believe some of these .c files could be
>> converted to headers and lie in sound/hda/quirks/ directory. These are
>> more of a platform-level files, not sound/hda/codecs/ per-se.
>>
>>> Signed-off-by: Takashi Iwai <tiwai@suse.de>
>>> ---
>>>    sound/hda/Kconfig                             |   1 +
>>>    sound/hda/Makefile                            |   1 +
>>>    sound/{pci/hda => hda/codecs}/Kconfig         | 158 +-----------------
>>>    sound/hda/codecs/Makefile                     |  31 ++++
>>>    .../patch_analog.c => hda/codecs/analog.c}    |   2 +-
>>>    .../patch_ca0110.c => hda/codecs/ca0110.c}    |   2 +-
>>>    .../patch_ca0132.c => hda/codecs/ca0132.c}    |   2 +-
>>>    sound/{pci/hda => hda/codecs}/ca0132_regs.h   |   0
>>>    sound/hda/codecs/cirrus/Kconfig               |  21 +++
>>>    sound/hda/codecs/cirrus/Makefile              |   8 +
>>>    .../codecs/cirrus/cirrus.c}                   |   2 +-
>>>    .../codecs/cirrus/cs8409-tables.c}            |   4 +-
>>>    .../codecs/cirrus/cs8409.c}                   |   2 +-
>>>    .../codecs/cirrus/cs8409.h}                   |   2 +-
>>>    .../patch_cmedia.c => hda/codecs/cmedia.c}    |   2 +-
>>>    .../codecs/conexant.c}                        |   6 +-
>>>    .../hda_generic.c => hda/codecs/generic.c}    |   2 +-
>>>    .../hda_generic.h => hda/codecs/generic.h}    |   0
>>>    sound/hda/codecs/hdmi/Makefile                |   6 +
>>>    .../hda/hda_eld.c => hda/codecs/hdmi/eld.c}   |   0
>>>    .../patch_hdmi.c => hda/codecs/hdmi/hdmi.c}   |   2 +-
>>>    .../codecs/helpers/hp_x360.c}                 |   0
>>>    .../codecs/helpers/ideapad_hotkey_led.c}      |   0
>>>    .../codecs/helpers/ideapad_s740.c}            |   0
>>>    .../codecs/helpers/thinkpad.c}                |   0
>>>    .../patch_realtek.c => hda/codecs/realtek.c}  |  12 +-
>>>    .../codecs/senarytech.c}                      |   4 +-
>>>    .../patch_si3054.c => hda/codecs/si3054.c}    |   0
>>>    sound/hda/codecs/side-codecs/Kconfig          | 128 ++++++++++++++
>>>    sound/hda/codecs/side-codecs/Makefile         |  28 ++++
>>>    .../codecs/side-codecs}/cirrus_scodec.c       |   0
>>>    .../codecs/side-codecs}/cirrus_scodec.h       |   0
>>>    .../codecs/side-codecs}/cirrus_scodec_test.c  |   0
>>>    .../codecs/side-codecs}/cs35l41_hda.c         |   2 +-
>>>    .../codecs/side-codecs}/cs35l41_hda.h         |   0
>>>    .../codecs/side-codecs}/cs35l41_hda_i2c.c     |   0
>>>    .../side-codecs}/cs35l41_hda_property.c       |   0
>>>    .../side-codecs}/cs35l41_hda_property.h       |   0
>>>    .../codecs/side-codecs}/cs35l41_hda_spi.c     |   0
>>>    .../codecs/side-codecs}/cs35l56_hda.c         |   2 +-
>>>    .../codecs/side-codecs}/cs35l56_hda.h         |   0
>>>    .../codecs/side-codecs}/cs35l56_hda_i2c.c     |   0
>>>    .../codecs/side-codecs}/cs35l56_hda_spi.c     |   0
>>>    .../codecs/side-codecs}/hda_component.c       |   0
>>>    .../codecs/side-codecs}/hda_component.h       |   0
>>>    .../codecs/side-codecs}/tas2781_hda.c         |   0
>>>    .../codecs/side-codecs}/tas2781_hda.h         |   0
>>>    .../codecs/side-codecs}/tas2781_hda_i2c.c     |   2 +-
>>>    .../codecs/side-codecs}/tas2781_hda_spi.c     |   2 +-
>>>    .../codecs/sigmatel.c}                        |   4 +-
>>>    .../{pci/hda/patch_via.c => hda/codecs/via.c} |   2 +-
>>>    sound/pci/Kconfig                             |   2 -
>>>    sound/pci/Makefile                            |   1 -
>>>    sound/pci/hda/Makefile                        |  61 -------
>>>    54 files changed, 257 insertions(+), 247 deletions(-)
>>>    rename sound/{pci/hda => hda/codecs}/Kconfig (55%)
>>>    create mode 100644 sound/hda/codecs/Makefile
>>>    rename sound/{pci/hda/patch_analog.c => hda/codecs/analog.c} (99%)
>>>    rename sound/{pci/hda/patch_ca0110.c => hda/codecs/ca0110.c} (98%)
>>>    rename sound/{pci/hda/patch_ca0132.c => hda/codecs/ca0132.c} (99%)
>>>    rename sound/{pci/hda => hda/codecs}/ca0132_regs.h (100%)
>>>    create mode 100644 sound/hda/codecs/cirrus/Kconfig
>>>    create mode 100644 sound/hda/codecs/cirrus/Makefile
>>>    rename sound/{pci/hda/patch_cirrus.c => hda/codecs/cirrus/cirrus.c} (99%)
>>>    rename sound/{pci/hda/patch_cs8409-tables.c => hda/codecs/cirrus/cs8409-tables.c} (99%)
>>>    rename sound/{pci/hda/patch_cs8409.c => hda/codecs/cirrus/cs8409.c} (99%)
>>>    rename sound/{pci/hda/patch_cs8409.h => hda/codecs/cirrus/cs8409.h} (99%)
>>>    rename sound/{pci/hda/patch_cmedia.c => hda/codecs/cmedia.c} (99%)
>>>    rename sound/{pci/hda/patch_conexant.c => hda/codecs/conexant.c} (99%)
>>>    rename sound/{pci/hda/hda_generic.c => hda/codecs/generic.c} (99%)
>>>    rename sound/{pci/hda/hda_generic.h => hda/codecs/generic.h} (100%)
>>>    create mode 100644 sound/hda/codecs/hdmi/Makefile
>>>    rename sound/{pci/hda/hda_eld.c => hda/codecs/hdmi/eld.c} (100%)
>>>    rename sound/{pci/hda/patch_hdmi.c => hda/codecs/hdmi/hdmi.c} (99%)
>>>    rename sound/{pci/hda/hp_x360_helper.c => hda/codecs/helpers/hp_x360.c} (100%)
>>>    rename sound/{pci/hda/ideapad_hotkey_led_helper.c => hda/codecs/helpers/ideapad_hotkey_led.c} (100%)
>>>    rename sound/{pci/hda/ideapad_s740_helper.c => hda/codecs/helpers/ideapad_s740.c} (100%)
>>>    rename sound/{pci/hda/thinkpad_helper.c => hda/codecs/helpers/thinkpad.c} (100%)
>>>    rename sound/{pci/hda/patch_realtek.c => hda/codecs/realtek.c} (99%)
>>>    rename sound/{pci/hda/patch_senarytech.c => hda/codecs/senarytech.c} (98%)
>>>    rename sound/{pci/hda/patch_si3054.c => hda/codecs/si3054.c} (100%)
>>>    create mode 100644 sound/hda/codecs/side-codecs/Kconfig
>>>    create mode 100644 sound/hda/codecs/side-codecs/Makefile
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec.h (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cirrus_scodec_test.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.c (99%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda.h (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_i2c.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_property.h (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l41_hda_spi.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.c (99%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda.h (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_i2c.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/cs35l56_hda_spi.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/hda_component.h (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.c (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda.h (100%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_i2c.c (99%)
>>>    rename sound/{pci/hda => hda/codecs/side-codecs}/tas2781_hda_spi.c (99%)
>>>    rename sound/{pci/hda/patch_sigmatel.c => hda/codecs/sigmatel.c} (99%)
>>>    rename sound/{pci/hda/patch_via.c => hda/codecs/via.c} (99%)
>>>    delete mode 100644 sound/pci/hda/Makefile


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-14  9:08       ` Cezary Rojewski
@ 2025-07-14  9:15         ` Takashi Iwai
  2025-07-14  9:35           ` Cezary Rojewski
  0 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-14  9:15 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: Takashi Iwai, linux-sound, Richard Fitzgerald, Kailang,
	Kai Vehmanen, Amadeusz Sławiński, patches, Baojun Xu,
	bo liu

On Mon, 14 Jul 2025 11:08:01 +0200,
Cezary Rojewski wrote:
> 
> On 2025-07-14 11:04 AM, Takashi Iwai wrote:
> > On Mon, 14 Jul 2025 10:57:59 +0200,
> > Cezary Rojewski wrote:
> >> 
> >> On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> >>> Now move the all remaining codec drivers from sound/pci/hda to
> >>> sound/hda/codecs subdirectory.  Some drivers are put under the further
> >>> vendor subdirectory, and the vendor helper code (*_helper.c) are put
> >>> under helpers subdirectory.  Also the sub-codec drivers are moved under
> >>> a different subdirectory, sound/hda/codecs/sub-codecs, for
> >>> distinguishing from the main HD-audio codec drivers.
> >>> 
> >>> The prefix patch_ and hda_ as well as the suffix _helper are dropped
> >>> from file names as they are mostly superfluous.
> >>> 
> >>> No functional changes but just file path shuffling.
> >>> 
> >> 
> >> Path: codecs/side-codecs/ looks wierd. My suggestion is to avoid the
> >> repeat and stay with codecs/side/.
> > 
> > Sorry, too late, I already merged the stuff.  (And IMO codecs/side
> > doesn't sound intuitive.)
> > 
> > Since the directory names are more or less understandable, and Cirrus
> > people seem OK with it, so let's leave as is.
> 
> Oh, didn't notice. The series is large and I wasn't expecting it to
> get merged that quickly.

There should be no much functional changes and the only matter is file
name shuffling, and no much regression reports from 0-day, so I
decided to merge for 6.17.  Then earlier, better.

Currently no further code change is planned from my side for 6.17.
Also some changes have been queued, they are post 6.17 materials.

> Guess no point in reviewing the rest then, thanks for the information!

We may still rename if something looks too worrisome, of course.
If you have something in mind, let me know.


Thanks!

Takashi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-14  9:15         ` Takashi Iwai
@ 2025-07-14  9:35           ` Cezary Rojewski
  2025-07-14 10:17             ` Takashi Iwai
  0 siblings, 1 reply; 48+ messages in thread
From: Cezary Rojewski @ 2025-07-14  9:35 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: linux-sound, Richard Fitzgerald, Kailang, Kai Vehmanen,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 2025-07-14 11:15 AM, Takashi Iwai wrote:
> On Mon, 14 Jul 2025 11:08:01 +0200,
> Cezary Rojewski wrote:
>>
>> On 2025-07-14 11:04 AM, Takashi Iwai wrote:
>>> On Mon, 14 Jul 2025 10:57:59 +0200,
>>> Cezary Rojewski wrote:
>>>>
>>>> On 2025-07-09 6:04 PM, Takashi Iwai wrote:
>>>>> Now move the all remaining codec drivers from sound/pci/hda to
>>>>> sound/hda/codecs subdirectory.  Some drivers are put under the further
>>>>> vendor subdirectory, and the vendor helper code (*_helper.c) are put
>>>>> under helpers subdirectory.  Also the sub-codec drivers are moved under
>>>>> a different subdirectory, sound/hda/codecs/sub-codecs, for
>>>>> distinguishing from the main HD-audio codec drivers.
>>>>>
>>>>> The prefix patch_ and hda_ as well as the suffix _helper are dropped
>>>>> from file names as they are mostly superfluous.
>>>>>
>>>>> No functional changes but just file path shuffling.
>>>>>
>>>>
>>>> Path: codecs/side-codecs/ looks wierd. My suggestion is to avoid the
>>>> repeat and stay with codecs/side/.
>>>
>>> Sorry, too late, I already merged the stuff.  (And IMO codecs/side
>>> doesn't sound intuitive.)
>>>
>>> Since the directory names are more or less understandable, and Cirrus
>>> people seem OK with it, so let's leave as is.
>>
>> Oh, didn't notice. The series is large and I wasn't expecting it to
>> get merged that quickly.
> 
> There should be no much functional changes and the only matter is file
> name shuffling, and no much regression reports from 0-day, so I
> decided to merge for 6.17.  Then earlier, better.
> 
> Currently no further code change is planned from my side for 6.17.
> Also some changes have been queued, they are post 6.17 materials.
> 
>> Guess no point in reviewing the rest then, thanks for the information!
> 
> We may still rename if something looks too worrisome, of course.
> If you have something in mind, let me know.

Thank you. I'll update my tactic a bit - rebase onto the new hda/ and 
reply/send patches separately if anything pops up.

There is a lot to look at and, at the same time it's very encouraging to 
see major work done in hda/ area :)

Kind regards,
Czarek

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory
  2025-07-14  9:35           ` Cezary Rojewski
@ 2025-07-14 10:17             ` Takashi Iwai
  0 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-07-14 10:17 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: Takashi Iwai, linux-sound, Richard Fitzgerald, Kailang,
	Kai Vehmanen, Amadeusz Sławiński, patches, Baojun Xu,
	bo liu

On Mon, 14 Jul 2025 11:35:10 +0200,
Cezary Rojewski wrote:
> 
> On 2025-07-14 11:15 AM, Takashi Iwai wrote:
> > On Mon, 14 Jul 2025 11:08:01 +0200,
> > Cezary Rojewski wrote:
> >> 
> >> On 2025-07-14 11:04 AM, Takashi Iwai wrote:
> >>> On Mon, 14 Jul 2025 10:57:59 +0200,
> >>> Cezary Rojewski wrote:
> >>>> 
> >>>> On 2025-07-09 6:04 PM, Takashi Iwai wrote:
> >>>>> Now move the all remaining codec drivers from sound/pci/hda to
> >>>>> sound/hda/codecs subdirectory.  Some drivers are put under the further
> >>>>> vendor subdirectory, and the vendor helper code (*_helper.c) are put
> >>>>> under helpers subdirectory.  Also the sub-codec drivers are moved under
> >>>>> a different subdirectory, sound/hda/codecs/sub-codecs, for
> >>>>> distinguishing from the main HD-audio codec drivers.
> >>>>> 
> >>>>> The prefix patch_ and hda_ as well as the suffix _helper are dropped
> >>>>> from file names as they are mostly superfluous.
> >>>>> 
> >>>>> No functional changes but just file path shuffling.
> >>>>> 
> >>>> 
> >>>> Path: codecs/side-codecs/ looks wierd. My suggestion is to avoid the
> >>>> repeat and stay with codecs/side/.
> >>> 
> >>> Sorry, too late, I already merged the stuff.  (And IMO codecs/side
> >>> doesn't sound intuitive.)
> >>> 
> >>> Since the directory names are more or less understandable, and Cirrus
> >>> people seem OK with it, so let's leave as is.
> >> 
> >> Oh, didn't notice. The series is large and I wasn't expecting it to
> >> get merged that quickly.
> > 
> > There should be no much functional changes and the only matter is file
> > name shuffling, and no much regression reports from 0-day, so I
> > decided to merge for 6.17.  Then earlier, better.
> > 
> > Currently no further code change is planned from my side for 6.17.
> > Also some changes have been queued, they are post 6.17 materials.
> > 
> >> Guess no point in reviewing the rest then, thanks for the information!
> > 
> > We may still rename if something looks too worrisome, of course.
> > If you have something in mind, let me know.
> 
> Thank you. I'll update my tactic a bit - rebase onto the new hda/ and
> reply/send patches separately if anything pops up.
> 
> There is a lot to look at and, at the same time it's very encouraging
> to see major work done in hda/ area :)

Great, thanks!


Takashi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* ALC887-VD line-in not visible
  2025-07-09 16:04 ` [PATCH 11/27] ALSA: hda/realtek: " Takashi Iwai
@ 2025-07-31  3:20   ` Arthur Marsh
  2025-07-31  5:33     ` Takashi Iwai
  0 siblings, 1 reply; 48+ messages in thread
From: Arthur Marsh @ 2025-07-31  3:20 UTC (permalink / raw)
  To: tiwai
  Cc: amadeuszx.slawinski, baojun.xu, bo.liu, cezary.rojewski,
	kai.vehmanen, kailang, linux-sound, patches, rf

Earlier this year I could use line-in on an Asus PRIME B350M-A motherboard,
with dmesg reporting:

 snd_hda_codec_realtek hdaudioC0D0: autoconfig for ALC887-VD: line_outs=1 (0x14/
0x0/0x0/0x0/0x0) type:line
 snd_hda_codec_realtek hdaudioC0D0:    speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
 snd_hda_codec_realtek hdaudioC0D0:    hp_outs=1 (0x1b/0x0/0x0/0x0/0x0)
 snd_hda_codec_realtek hdaudioC0D0:    mono: mono_out=0x0
 snd_hda_codec_realtek hdaudioC0D0:    dig-out=0x11/0x0
 snd_hda_codec_realtek hdaudioC0D0:    inputs:
 snd_hda_codec_realtek hdaudioC0D0:      Rear Mic=0x18
 snd_hda_codec_realtek hdaudioC0D0:      Front Mic=0x19
 snd_hda_codec_realtek hdaudioC0D0:      Line=0x1a
 input: HD-Audio Generic Rear Mic as /devices/pci0000:00/0000:00:08.1/0000:08:00
.6/sound/card0/input6
 input: HD-Audio Generic Front Mic as /devices/pci0000:00/0000:00:08.1/0000:08:0
0.6/sound/card0/input7
 input: HD-Audio Generic Line as /devices/pci0000:00/0000:00:08.1/0000:08:00.6/s
ound/card0/input8
 input: HD-Audio Generic Line Out as /devices/pci0000:00/0000:00:08.1/0000:08:00
.6/sound/card0/input9
 input: HD-Audio Generic Front Headphone as /devices/pci0000:00/0000:00:08.1/000
0:08:00.6/sound/card0/input10

After the post-6.16 updates, I now get:

 snd_hda_codec_generic hdaudioC0D0: autoconfig for Generic: line_o
uts=1 (0x14/0x0/0x0/0x0/0x0) type:line
 snd_hda_codec_generic hdaudioC0D0:    speaker_outs=0 (0x0/0x0/0x0
/0x0/0x0)
 snd_hda_codec_generic hdaudioC0D0:    hp_outs=1 (0x1b/0x0/0x0/0x0
/0x0)
 snd_hda_codec_generic hdaudioC0D0:    mono: mono_out=0x0
 snd_hda_codec_generic hdaudioC0D0:    dig-out=0x11/0x0
 snd_hda_codec_generic hdaudioC0D0:    inputs:
 snd_hda_codec_generic hdaudioC0D0:      Rear Mic=0x18
 snd_hda_codec_generic hdaudioC0D0:      Front Mic=0x19
 snd_hda_codec_generic hdaudioC0D0:      Line=0x1a
 input: HD-Audio Generic Rear Mic as /devices/pci0000:00/0000:00:0
8.1/0000:08:00.6/sound/card0/input6
 input: HD-Audio Generic Front Mic as /devices/pci0000:00/0000:00:
08.1/0000:08:00.6/sound/card0/input7
 input: HD-Audio Generic Line as /devices/pci0000:00/0000:00:08.1/
0000:08:00.6/sound/card0/input8
 input: HD-Audio Generic Line Out as /devices/pci0000:00/0000:00:0
8.1/0000:08:00.6/sound/card0/input9
 input: HD-Audio Generic Front Headphone as /devices/pci0000:00/00
00:00:08.1/0000:08:00.6/sound/card0/input10

lspci reports:

  lspci -v -s 0000:08:00.1
08:00.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Renoir Radeon High Definition Audio Controller
        Subsystem: ASUSTeK Computer Inc. Device 8809
        Flags: bus master, fast devsel, latency 0, IRQ 87, IOMMU group 11
        Memory at fca88000 (32-bit, non-prefetchable) [size=16K]
        Capabilities: [48] Vendor Specific Information: Len=08 <?>
        Capabilities: [50] Power Management version 3
        Capabilities: [64] Express Legacy Endpoint, IntMsgNum 0
        Capabilities: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit+
        Capabilities: [100] Vendor Specific Information: ID=0001 Rev=1 Len=010 <?>
        Capabilities: [2a0] Access Control Services
        Kernel driver in use: snd_hda_intel
        Kernel modules: snd_hda_intel


When using alsamixer, in the former case, I would get a "loopback" device, 
which when un-muted would enable line-in to work.

With the current git head kernel, I get no such loopback device and have been
unable to get audio via line input.

Any suggestions welcome.


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: ALC887-VD line-in not visible
  2025-07-31  3:20   ` ALC887-VD line-in not visible Arthur Marsh
@ 2025-07-31  5:33     ` Takashi Iwai
  2025-07-31 12:32       ` Arthur Marsh
  0 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-31  5:33 UTC (permalink / raw)
  To: Arthur Marsh
  Cc: tiwai, amadeuszx.slawinski, baojun.xu, bo.liu, cezary.rojewski,
	kai.vehmanen, kailang, linux-sound, patches, rf

On Thu, 31 Jul 2025 05:20:57 +0200,
Arthur Marsh wrote:
> 
> Earlier this year I could use line-in on an Asus PRIME B350M-A motherboard,
> with dmesg reporting:
> 
>  snd_hda_codec_realtek hdaudioC0D0: autoconfig for ALC887-VD: line_outs=1 (0x14/
> 0x0/0x0/0x0/0x0) type:line
>  snd_hda_codec_realtek hdaudioC0D0:    speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
>  snd_hda_codec_realtek hdaudioC0D0:    hp_outs=1 (0x1b/0x0/0x0/0x0/0x0)
>  snd_hda_codec_realtek hdaudioC0D0:    mono: mono_out=0x0
>  snd_hda_codec_realtek hdaudioC0D0:    dig-out=0x11/0x0
>  snd_hda_codec_realtek hdaudioC0D0:    inputs:
>  snd_hda_codec_realtek hdaudioC0D0:      Rear Mic=0x18
>  snd_hda_codec_realtek hdaudioC0D0:      Front Mic=0x19
>  snd_hda_codec_realtek hdaudioC0D0:      Line=0x1a
>  input: HD-Audio Generic Rear Mic as /devices/pci0000:00/0000:00:08.1/0000:08:00
> .6/sound/card0/input6
>  input: HD-Audio Generic Front Mic as /devices/pci0000:00/0000:00:08.1/0000:08:0
> 0.6/sound/card0/input7
>  input: HD-Audio Generic Line as /devices/pci0000:00/0000:00:08.1/0000:08:00.6/s
> ound/card0/input8
>  input: HD-Audio Generic Line Out as /devices/pci0000:00/0000:00:08.1/0000:08:00
> .6/sound/card0/input9
>  input: HD-Audio Generic Front Headphone as /devices/pci0000:00/0000:00:08.1/000
> 0:08:00.6/sound/card0/input10
> 
> After the post-6.16 updates, I now get:
> 
>  snd_hda_codec_generic hdaudioC0D0: autoconfig for Generic: line_o
> uts=1 (0x14/0x0/0x0/0x0/0x0) type:line
>  snd_hda_codec_generic hdaudioC0D0:    speaker_outs=0 (0x0/0x0/0x0
> /0x0/0x0)
>  snd_hda_codec_generic hdaudioC0D0:    hp_outs=1 (0x1b/0x0/0x0/0x0
> /0x0)
>  snd_hda_codec_generic hdaudioC0D0:    mono: mono_out=0x0
>  snd_hda_codec_generic hdaudioC0D0:    dig-out=0x11/0x0
>  snd_hda_codec_generic hdaudioC0D0:    inputs:
>  snd_hda_codec_generic hdaudioC0D0:      Rear Mic=0x18
>  snd_hda_codec_generic hdaudioC0D0:      Front Mic=0x19
>  snd_hda_codec_generic hdaudioC0D0:      Line=0x1a
>  input: HD-Audio Generic Rear Mic as /devices/pci0000:00/0000:00:0
> 8.1/0000:08:00.6/sound/card0/input6
>  input: HD-Audio Generic Front Mic as /devices/pci0000:00/0000:00:
> 08.1/0000:08:00.6/sound/card0/input7
>  input: HD-Audio Generic Line as /devices/pci0000:00/0000:00:08.1/
> 0000:08:00.6/sound/card0/input8
>  input: HD-Audio Generic Line Out as /devices/pci0000:00/0000:00:0
> 8.1/0000:08:00.6/sound/card0/input9
>  input: HD-Audio Generic Front Headphone as /devices/pci0000:00/00
> 00:00:08.1/0000:08:00.6/sound/card0/input10

Are you using the latest Linus tree for 6.17-rc1?
If so, there were changes related with HD-audio Kconfigs, and I guess
you didn't enable the specific HD-audio codec driver you're using
(e.g. CONFIG_SND_HDA_CODEC_ALC882).

Also, HDMI codec needs the additional Kconfig,
e.g. CONFIG_SND_HDA_CODEC_HDMI_INTEL, too.

I queued some changes to pick up those as default in for-linus branch
of sound.git tree for avoiding such a pitfall now.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* ALC887-VD line-in not visible
  2025-07-31  5:33     ` Takashi Iwai
@ 2025-07-31 12:32       ` Arthur Marsh
  2025-07-31 12:37         ` Takashi Iwai
  0 siblings, 1 reply; 48+ messages in thread
From: Arthur Marsh @ 2025-07-31 12:32 UTC (permalink / raw)
  To: tiwai
  Cc: amadeuszx.slawinski, arthur.marsh, baojun.xu, bo.liu,
	cezary.rojewski, kai.vehmanen, kailang, linux-sound, patches, rf

Thanks, I found the discussion with Linus about options and enabled:

CONFIG_SND_HDA_CODEC_ALC882

It still gets confusing that 

CONFIG_SND_HDA_CODEC_ALC882

also applies to other ALC88* codecs.

I also enabled:

CONFIG_SND_HDA_CODEC_ALC882

even though I generally don't use HDMI out on this machine.

Arthur.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: ALC887-VD line-in not visible
  2025-07-31 12:32       ` Arthur Marsh
@ 2025-07-31 12:37         ` Takashi Iwai
  2025-07-31 13:01           ` Arthur Marsh
  0 siblings, 1 reply; 48+ messages in thread
From: Takashi Iwai @ 2025-07-31 12:37 UTC (permalink / raw)
  To: Arthur Marsh
  Cc: tiwai, amadeuszx.slawinski, baojun.xu, bo.liu, cezary.rojewski,
	kai.vehmanen, kailang, linux-sound, patches, rf

On Thu, 31 Jul 2025 14:32:01 +0200,
Arthur Marsh wrote:
> 
> Thanks, I found the discussion with Linus about options and enabled:
> 
> CONFIG_SND_HDA_CODEC_ALC882
> 
> It still gets confusing that 
> 
> CONFIG_SND_HDA_CODEC_ALC882
> 
> also applies to other ALC88* codecs.

There are hundreds of different Realtek HD-audio codecs and we can't
put all in the driver names :)  Basically the driver is for ALC882 and
its compatible codecs.

> I also enabled:
> 
> CONFIG_SND_HDA_CODEC_ALC882
> 
> even though I generally don't use HDMI out on this machine.

Your problem is rather specific to Realtek codec, so it's only about
CONFIG_SND_HDA_CODEC_ALC882.  I'm not sure what made Linus' system
broken, but my wild guess is that the lack of specific HDMI codec
support caused the user-space side configuration mismatched somehow.


Takashi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* ALC887-VD line-in not visible
  2025-07-31 12:37         ` Takashi Iwai
@ 2025-07-31 13:01           ` Arthur Marsh
  0 siblings, 0 replies; 48+ messages in thread
From: Arthur Marsh @ 2025-07-31 13:01 UTC (permalink / raw)
  To: tiwai
  Cc: amadeuszx.slawinski, arthur.marsh, baojun.xu, bo.liu,
	cezary.rojewski, kai.vehmanen, kailang, linux-sound, patches, rf

> I also enabled:

> CONFIG_SND_HDA_CODEC_ALC882

> even though I generally don't use HDMI out on this machine.

Oops, I meant that I also enabled:

CONFIG_SND_HDA_CODEC_HDMI_INTEL

Regards,

Arthur.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 23/27] ALSA: hda/hdmi: Rewrite to new probe method
  2025-07-09 16:04 ` [PATCH 23/27] ALSA: hda/hdmi: " Takashi Iwai
@ 2025-08-17 10:55   ` Mikhail Paulyshka
  2025-08-18  7:18     ` Takashi Iwai
  0 siblings, 1 reply; 48+ messages in thread
From: Mikhail Paulyshka @ 2025-08-17 10:55 UTC (permalink / raw)
  To: Takashi Iwai, linux-sound
  Cc: Richard Fitzgerald, Kailang, Kai Vehmanen, Cezary Rojewski,
	Amadeusz Sławiński, patches, Baojun Xu, bo liu

On 7/9/25 7:04 PM, Takashi Iwai wrote:
> diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c
> index a88ac1f80db6..23237d527430 100644
> --- a/sound/hda/codecs/hdmi/intelhdmi.c
> +++ b/sound/hda/codecs/hdmi/intelhdmi.c
> @@ -701,51 +698,104 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
>   }
>   
>   /* Intel IronLake, SandyBIridge and IvyBridge; with eld notifier */
> -static int patch_i915_cpt_hdmi(struct hda_codec *codec)
> +static int probe_i915_cpt_hdmi(struct hda_codec *codec)
> +{
> +	return parse_intel_hdmi(codec);
> +}
> +
> +/*
> + * common driver probe
> + */
> +static int intelhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
>   {
>   	int err;
>   
>   	err = alloc_intel_hdmi(codec);
>   	if (err < 0)
>   		return err;
> -	return parse_intel_hdmi(codec);
> +
> +	switch (id->driver_data) {
> +	case MODEL_HSW:
> +		err = probe_i915_hsw_hdmi(codec);
> +		break;
> +	case MODEL_GLK:
> +		err = probe_i915_glk_hdmi(codec);
> +		break;
> +	case MODEL_ICL:
> +		err = probe_i915_icl_hdmi(codec);
> +		break;
> +	case MODEL_TGL:
> +		err = probe_i915_tgl_hdmi(codec);
> +		break;
> +	case MODEL_ADLP:
> +		err = probe_i915_adlp_hdmi(codec);
> +		break;
> +	case MODEL_BYT:
> +		err = probe_i915_byt_hdmi(codec);
> +		break;
> +	case MODEL_CPT:
> +		err = probe_i915_cpt_hdmi(codec);
> +		break;
> +	default:
> +		err = -EINVAL;
> +		break;
> +	}
> +
> +	if (err < 0) {
> +		snd_hda_hdmi_generic_spec_free(codec);

Is this the intended behavior? It modifies the codec state even when it 
does not match any Intel model. We have reports from users on 6.17-rc1 
with AMD BC-250 hardware experiencing HDMI audio detection issues. 
Adding a check for |EINVAL| resolves the problem.

 > - if (err < 0) { > + if (err < 0 && err != -EINVAL) {


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 23/27] ALSA: hda/hdmi: Rewrite to new probe method
  2025-08-17 10:55   ` Mikhail Paulyshka
@ 2025-08-18  7:18     ` Takashi Iwai
  0 siblings, 0 replies; 48+ messages in thread
From: Takashi Iwai @ 2025-08-18  7:18 UTC (permalink / raw)
  To: Mikhail Paulyshka
  Cc: Takashi Iwai, linux-sound, Richard Fitzgerald, Kailang,
	Kai Vehmanen, Cezary Rojewski, Amadeusz Sławiński,
	patches, Baojun Xu, bo liu

On Sun, 17 Aug 2025 12:55:48 +0200,
Mikhail Paulyshka wrote:
> 
> On 7/9/25 7:04 PM, Takashi Iwai wrote:
> > diff --git a/sound/hda/codecs/hdmi/intelhdmi.c b/sound/hda/codecs/hdmi/intelhdmi.c
> > index a88ac1f80db6..23237d527430 100644
> > --- a/sound/hda/codecs/hdmi/intelhdmi.c
> > +++ b/sound/hda/codecs/hdmi/intelhdmi.c
> > @@ -701,51 +698,104 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
> >   }
> >     /* Intel IronLake, SandyBIridge and IvyBridge; with eld notifier
> > */
> > -static int patch_i915_cpt_hdmi(struct hda_codec *codec)
> > +static int probe_i915_cpt_hdmi(struct hda_codec *codec)
> > +{
> > +	return parse_intel_hdmi(codec);
> > +}
> > +
> > +/*
> > + * common driver probe
> > + */
> > +static int intelhdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
> >   {
> >   	int err;
> >     	err = alloc_intel_hdmi(codec);
> >   	if (err < 0)
> >   		return err;
> > -	return parse_intel_hdmi(codec);
> > +
> > +	switch (id->driver_data) {
> > +	case MODEL_HSW:
> > +		err = probe_i915_hsw_hdmi(codec);
> > +		break;
> > +	case MODEL_GLK:
> > +		err = probe_i915_glk_hdmi(codec);
> > +		break;
> > +	case MODEL_ICL:
> > +		err = probe_i915_icl_hdmi(codec);
> > +		break;
> > +	case MODEL_TGL:
> > +		err = probe_i915_tgl_hdmi(codec);
> > +		break;
> > +	case MODEL_ADLP:
> > +		err = probe_i915_adlp_hdmi(codec);
> > +		break;
> > +	case MODEL_BYT:
> > +		err = probe_i915_byt_hdmi(codec);
> > +		break;
> > +	case MODEL_CPT:
> > +		err = probe_i915_cpt_hdmi(codec);
> > +		break;
> > +	default:
> > +		err = -EINVAL;
> > +		break;
> > +	}
> > +
> > +	if (err < 0) {
> > +		snd_hda_hdmi_generic_spec_free(codec);
> 
> Is this the intended behavior? It modifies the codec state even when
> it does not match any Intel model. We have reports from users on
> 6.17-rc1 with AMD BC-250 hardware experiencing HDMI audio detection
> issues. Adding a check for |EINVAL| resolves the problem.

Have you enabled CONFIG_SND_HDA_CODEC_HDMI_ATI?

The probe of intelhdmi.c is only for Intel chips, and no other devices
will be probed, as you can find in snd_hda_id_intelhdmi[] array.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2025-08-18  7:18 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-09 16:04 [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai
2025-07-09 16:04 ` [PATCH 01/27] ALSA: hda: Move widget capability macros into hdaudio.h Takashi Iwai
2025-07-14  8:40   ` Cezary Rojewski
2025-07-09 16:04 ` [PATCH 02/27] ALSA: hda: Move HD-audio core stuff into sound/hda/core Takashi Iwai
2025-07-14  8:41   ` Cezary Rojewski
2025-07-09 16:04 ` [PATCH 03/27] ALSA: hda: Move common codec driver into sound/hda/common directory Takashi Iwai
2025-07-09 16:04 ` [PATCH 04/27] ALSA: hda: Move CONFIG_SND_HDA_PREALLOC_SIZE into sound/hda/common Takashi Iwai
2025-07-09 16:04 ` [PATCH 05/27] ALSA: hda: Move controller drivers into sound/hda/controllers directory Takashi Iwai
2025-07-09 16:04 ` [PATCH 06/27] ALSA: hda: Move codec drivers into sound/hda/codecs directory Takashi Iwai
2025-07-10 10:05   ` Richard Fitzgerald
2025-07-14  8:57   ` Cezary Rojewski
2025-07-14  9:04     ` Takashi Iwai
2025-07-14  9:08       ` Cezary Rojewski
2025-07-14  9:15         ` Takashi Iwai
2025-07-14  9:35           ` Cezary Rojewski
2025-07-14 10:17             ` Takashi Iwai
2025-07-09 16:04 ` [PATCH 07/27] ALSA: hda: Split Realtek HD-audio codec driver Takashi Iwai
2025-07-14  9:02   ` Cezary Rojewski
2025-07-09 16:04 ` [PATCH 08/27] ALSA: hda/hdmi: Split vendor codec drivers Takashi Iwai
2025-07-09 16:04 ` [PATCH 09/27] ALSA: hda: Introduce hda_codec_driver ops Takashi Iwai
2025-07-09 16:04 ` [PATCH 10/27] ALSA: hda/generic: Rewrite to new probe method Takashi Iwai
2025-07-09 16:04 ` [PATCH 11/27] ALSA: hda/realtek: " Takashi Iwai
2025-07-31  3:20   ` ALC887-VD line-in not visible Arthur Marsh
2025-07-31  5:33     ` Takashi Iwai
2025-07-31 12:32       ` Arthur Marsh
2025-07-31 12:37         ` Takashi Iwai
2025-07-31 13:01           ` Arthur Marsh
2025-07-09 16:04 ` [PATCH 12/27] ALSA: hda/cmedia: Rewrite to new probe method Takashi Iwai
2025-07-09 16:04 ` [PATCH 13/27] ALSA: hda/analog: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 14/27] ALSA: hda/ca0110: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 15/27] ALSA: hda/cirrus: Split to cs420x and cs421x drivers Takashi Iwai
2025-07-09 16:04 ` [PATCH 16/27] ALSA: hda/cs8409: Rewrite to new probe method Takashi Iwai
2025-07-10 10:25   ` Richard Fitzgerald
2025-07-09 16:04 ` [PATCH 17/27] ALSA: hda/conexant: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 18/27] ALSA: hda/senary: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 19/27] ALSA: hda/si3054: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 20/27] ALSA: hda/via: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 21/27] ALSA: hda/sigmatel: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 22/27] ALSA: hda/ca0132: " Takashi Iwai
2025-07-09 16:04 ` [PATCH 23/27] ALSA: hda/hdmi: " Takashi Iwai
2025-08-17 10:55   ` Mikhail Paulyshka
2025-08-18  7:18     ` Takashi Iwai
2025-07-09 16:04 ` [PATCH 24/27] ALSA: hda: Drop old codec binding method Takashi Iwai
2025-07-09 16:04 ` [PATCH 25/27] ALSA: hda: Drop superfluous driver->ops NULL checks Takashi Iwai
2025-07-09 16:04 ` [PATCH 26/27] MAINTAINERS: Adjust to the new HD-audio driver paths Takashi Iwai
2025-07-10 10:30   ` Richard Fitzgerald
2025-07-09 16:04 ` [PATCH 27/27] ALSA: hda: Return the codec init error properly at snd_hda_codec_build_controls() Takashi Iwai
2025-07-11 12:55 ` [PATCH 00/27] ALSA: Reorganize HD-audio driver code Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).