linux/sound/pci/hda/patch_cmedia.c
<<
>>
Prefs
   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
  20struct cmi_spec {
  21        struct hda_gen_spec gen;
  22};
  23
  24/*
  25 * stuff for auto-parser
  26 */
  27static 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
  35static 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
  64static 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, &amp_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 */
 112static 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};
 118MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
 119
 120MODULE_LICENSE("GPL");
 121MODULE_DESCRIPTION("C-Media HD-audio codec");
 122
 123static struct hda_codec_driver cmedia_driver = {
 124        .id = snd_hda_id_cmedia,
 125};
 126
 127module_hda_codec_driver(cmedia_driver);
 128