patch_cmedia.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Universal Interface for Intel High Definition Audio Codec
  4. *
  5. * HD audio interface patch for C-Media CMI9880
  6. *
  7. * Copyright (c) 2004 Takashi Iwai <[email protected]>
  8. */
  9. #include <linux/init.h>
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <sound/core.h>
  13. #include <sound/hda_codec.h>
  14. #include "hda_local.h"
  15. #include "hda_auto_parser.h"
  16. #include "hda_jack.h"
  17. #include "hda_generic.h"
  18. struct cmi_spec {
  19. struct hda_gen_spec gen;
  20. };
  21. /*
  22. * stuff for auto-parser
  23. */
  24. static const struct hda_codec_ops cmi_auto_patch_ops = {
  25. .build_controls = snd_hda_gen_build_controls,
  26. .build_pcms = snd_hda_gen_build_pcms,
  27. .init = snd_hda_gen_init,
  28. .free = snd_hda_gen_free,
  29. .unsol_event = snd_hda_jack_unsol_event,
  30. };
  31. static int patch_cmi9880(struct hda_codec *codec)
  32. {
  33. struct cmi_spec *spec;
  34. struct auto_pin_cfg *cfg;
  35. int err;
  36. spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  37. if (spec == NULL)
  38. return -ENOMEM;
  39. codec->spec = spec;
  40. codec->patch_ops = cmi_auto_patch_ops;
  41. cfg = &spec->gen.autocfg;
  42. snd_hda_gen_spec_init(&spec->gen);
  43. err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
  44. if (err < 0)
  45. goto error;
  46. err = snd_hda_gen_parse_auto_config(codec, cfg);
  47. if (err < 0)
  48. goto error;
  49. return 0;
  50. error:
  51. snd_hda_gen_free(codec);
  52. return err;
  53. }
  54. static int patch_cmi8888(struct hda_codec *codec)
  55. {
  56. struct cmi_spec *spec;
  57. struct auto_pin_cfg *cfg;
  58. int err;
  59. spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  60. if (!spec)
  61. return -ENOMEM;
  62. codec->spec = spec;
  63. codec->patch_ops = cmi_auto_patch_ops;
  64. cfg = &spec->gen.autocfg;
  65. snd_hda_gen_spec_init(&spec->gen);
  66. /* mask NID 0x10 from the playback volume selection;
  67. * it's a headphone boost volume handled manually below
  68. */
  69. spec->gen.out_vol_mask = (1ULL << 0x10);
  70. err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
  71. if (err < 0)
  72. goto error;
  73. err = snd_hda_gen_parse_auto_config(codec, cfg);
  74. if (err < 0)
  75. goto error;
  76. if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
  77. AC_JACK_HP_OUT) {
  78. static const struct snd_kcontrol_new amp_kctl =
  79. HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
  80. 0x10, 0, HDA_OUTPUT);
  81. if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
  82. err = -ENOMEM;
  83. goto error;
  84. }
  85. }
  86. return 0;
  87. error:
  88. snd_hda_gen_free(codec);
  89. return err;
  90. }
  91. /*
  92. * patch entries
  93. */
  94. static const struct hda_device_id snd_hda_id_cmedia[] = {
  95. HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888),
  96. HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880),
  97. HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880),
  98. {} /* terminator */
  99. };
  100. MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
  101. MODULE_LICENSE("GPL");
  102. MODULE_DESCRIPTION("C-Media HD-audio codec");
  103. static struct hda_codec_driver cmedia_driver = {
  104. .id = snd_hda_id_cmedia,
  105. };
  106. module_hda_codec_driver(cmedia_driver);