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