2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2007-06-20 13:46:13 +00:00
|
|
|
* HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
|
|
|
|
* AD1986A, AD1988
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2007-05-18 16:21:41 +00:00
|
|
|
* Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* This driver is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This driver is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/pci.h>
|
2011-07-15 16:38:28 +00:00
|
|
|
#include <linux/module.h>
|
2006-01-16 15:34:20 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <sound/core.h>
|
|
|
|
#include "hda_codec.h"
|
|
|
|
#include "hda_local.h"
|
2012-05-07 15:42:31 +00:00
|
|
|
#include "hda_auto_parser.h"
|
2009-02-06 16:22:05 +00:00
|
|
|
#include "hda_beep.h"
|
2011-10-27 20:12:46 +00:00
|
|
|
#include "hda_jack.h"
|
2012-12-21 14:17:06 +00:00
|
|
|
#include "hda_generic.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
|
2005-04-14 11:35:51 +00:00
|
|
|
struct ad198x_spec {
|
2012-12-21 14:17:06 +00:00
|
|
|
struct hda_gen_spec gen;
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
/* for auto parser */
|
|
|
|
int smux_paths[4];
|
|
|
|
unsigned int cur_smux;
|
2013-01-22 17:18:42 +00:00
|
|
|
hda_nid_t eapd_nid;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
|
2009-02-06 16:22:05 +00:00
|
|
|
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
|
2008-01-10 15:53:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-11-16 14:35:59 +00:00
|
|
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
2009-02-06 16:22:05 +00:00
|
|
|
/* additional beep mixers; the actual parameters are overwritten at build */
|
2011-05-02 09:33:15 +00:00
|
|
|
static const struct snd_kcontrol_new ad_beep_mixer[] = {
|
2009-02-06 16:22:05 +00:00
|
|
|
HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
|
2009-10-21 12:48:23 +00:00
|
|
|
HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
|
2009-02-06 16:22:05 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define set_beep_amp(spec, nid, idx, dir) \
|
|
|
|
((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
|
2009-11-16 14:35:59 +00:00
|
|
|
#else
|
|
|
|
#define set_beep_amp(spec, nid, idx, dir) /* NOP */
|
|
|
|
#endif
|
2009-02-06 16:22:05 +00:00
|
|
|
|
2012-12-21 14:17:06 +00:00
|
|
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
|
|
|
static int create_beep_ctls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
const struct snd_kcontrol_new *knew;
|
|
|
|
|
|
|
|
if (!spec->beep_amp)
|
|
|
|
return 0;
|
|
|
|
|
2013-07-05 12:14:14 +00:00
|
|
|
for (knew = ad_beep_mixer ; knew->name; knew++) {
|
2012-12-21 14:17:06 +00:00
|
|
|
int err;
|
|
|
|
struct snd_kcontrol *kctl;
|
|
|
|
kctl = snd_ctl_new1(knew, codec);
|
|
|
|
if (!kctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
kctl->private_value = spec->beep_amp;
|
|
|
|
err = snd_hda_ctl_add(codec, 0, kctl);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define create_beep_ctls(codec) 0
|
|
|
|
#endif
|
|
|
|
|
2005-04-14 11:35:51 +00:00
|
|
|
|
2009-12-27 23:48:29 +00:00
|
|
|
static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
|
|
|
|
hda_nid_t hp)
|
|
|
|
{
|
2011-06-01 07:09:48 +00:00
|
|
|
if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
|
|
|
|
snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
2012-12-21 14:17:06 +00:00
|
|
|
!codec->inv_eapd ? 0x00 : 0x02);
|
2011-06-01 07:09:48 +00:00
|
|
|
if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
|
|
|
|
snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
2012-12-21 14:17:06 +00:00
|
|
|
!codec->inv_eapd ? 0x00 : 0x02);
|
2009-12-27 23:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ad198x_power_eapd(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
/* We currently only handle front, HP */
|
|
|
|
switch (codec->vendor_id) {
|
|
|
|
case 0x11d41882:
|
|
|
|
case 0x11d4882a:
|
|
|
|
case 0x11d41884:
|
|
|
|
case 0x11d41984:
|
|
|
|
case 0x11d41883:
|
|
|
|
case 0x11d4184a:
|
|
|
|
case 0x11d4194a:
|
|
|
|
case 0x11d4194b:
|
2011-06-03 08:05:02 +00:00
|
|
|
case 0x11d41988:
|
|
|
|
case 0x11d4198b:
|
|
|
|
case 0x11d4989a:
|
|
|
|
case 0x11d4989b:
|
2009-12-27 23:48:29 +00:00
|
|
|
ad198x_power_eapd_write(codec, 0x12, 0x11);
|
|
|
|
break;
|
|
|
|
case 0x11d41981:
|
|
|
|
case 0x11d41983:
|
|
|
|
ad198x_power_eapd_write(codec, 0x05, 0x06);
|
|
|
|
break;
|
|
|
|
case 0x11d41986:
|
|
|
|
ad198x_power_eapd_write(codec, 0x1b, 0x1a);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-26 13:18:33 +00:00
|
|
|
static void ad198x_shutup(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
snd_hda_shutup_pins(codec);
|
|
|
|
ad198x_power_eapd(codec);
|
|
|
|
}
|
|
|
|
|
2011-07-26 07:52:50 +00:00
|
|
|
#ifdef CONFIG_PM
|
2012-07-02 13:20:37 +00:00
|
|
|
static int ad198x_suspend(struct hda_codec *codec)
|
2009-12-27 23:48:29 +00:00
|
|
|
{
|
|
|
|
ad198x_shutup(codec);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-11-13 08:42:56 +00:00
|
|
|
/* follow EAPD via vmaster hook */
|
|
|
|
static void ad_vmaster_eapd_hook(void *private_data, int enabled)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = private_data;
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (!spec->eapd_nid)
|
|
|
|
return;
|
|
|
|
snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
|
|
|
|
AC_VERB_SET_EAPD_BTLENABLE,
|
|
|
|
enabled ? 0x02 : 0x00);
|
|
|
|
}
|
2006-03-13 12:49:49 +00:00
|
|
|
|
2012-12-21 14:17:06 +00:00
|
|
|
/*
|
|
|
|
* Automatic parse of I/O pins from the BIOS configuration
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int ad198x_auto_build_controls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = snd_hda_gen_build_controls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
err = create_beep_ctls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
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,
|
2013-03-18 10:25:51 +00:00
|
|
|
.free = snd_hda_gen_free,
|
2013-01-18 06:51:17 +00:00
|
|
|
.unsol_event = snd_hda_jack_unsol_event,
|
2012-12-21 14:17:06 +00:00
|
|
|
#ifdef CONFIG_PM
|
|
|
|
.check_power_status = snd_hda_gen_check_power_status,
|
|
|
|
.suspend = ad198x_suspend,
|
|
|
|
#endif
|
|
|
|
.reboot_notify = ad198x_shutup,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int ad198x_parse_auto_config(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
codec->spdif_status_reset = 1;
|
|
|
|
codec->no_trigger_sense = 1;
|
|
|
|
codec->no_sticky_stream = 1;
|
|
|
|
|
|
|
|
spec->gen.indep_hp = 1;
|
|
|
|
|
|
|
|
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
err = snd_hda_gen_parse_auto_config(codec, cfg);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
codec->patch_ops = ad198x_auto_patch_ops;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-14 11:35:51 +00:00
|
|
|
/*
|
|
|
|
* AD1986A specific
|
|
|
|
*/
|
|
|
|
|
2012-05-09 12:35:27 +00:00
|
|
|
static int alloc_ad_spec(struct hda_codec *codec)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2005-04-14 11:35:51 +00:00
|
|
|
struct ad198x_spec *spec;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 12:21:46 +00:00
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
2012-05-09 12:35:27 +00:00
|
|
|
if (!spec)
|
2005-04-14 11:35:51 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
codec->spec = spec;
|
2012-12-21 14:17:06 +00:00
|
|
|
snd_hda_gen_spec_init(&spec->gen);
|
2012-05-09 12:35:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-22 17:18:42 +00:00
|
|
|
/*
|
|
|
|
* AD1986A fixup codes
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
|
|
|
|
static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
|
|
|
|
const struct hda_fixup *fix, int action)
|
|
|
|
{
|
2013-11-13 08:39:08 +00:00
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
2013-01-22 17:18:42 +00:00
|
|
|
codec->inv_jack_detect = 1;
|
2013-11-13 08:39:08 +00:00
|
|
|
spec->gen.keep_eapd_on = 1;
|
2013-11-13 08:42:56 +00:00
|
|
|
spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
|
|
|
|
spec->eapd_nid = 0x1b;
|
2013-11-13 08:39:08 +00:00
|
|
|
}
|
2013-01-22 17:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum {
|
|
|
|
AD1986A_FIXUP_INV_JACK_DETECT,
|
2013-07-04 14:50:46 +00:00
|
|
|
AD1986A_FIXUP_ULTRA,
|
2013-07-04 15:06:04 +00:00
|
|
|
AD1986A_FIXUP_SAMSUNG,
|
2013-07-05 12:14:14 +00:00
|
|
|
AD1986A_FIXUP_3STACK,
|
|
|
|
AD1986A_FIXUP_LAPTOP,
|
|
|
|
AD1986A_FIXUP_LAPTOP_IMIC,
|
2013-01-22 17:18:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_fixup ad1986a_fixups[] = {
|
|
|
|
[AD1986A_FIXUP_INV_JACK_DETECT] = {
|
|
|
|
.type = HDA_FIXUP_FUNC,
|
|
|
|
.v.func = ad_fixup_inv_jack_detect,
|
|
|
|
},
|
2013-07-04 14:50:46 +00:00
|
|
|
[AD1986A_FIXUP_ULTRA] = {
|
|
|
|
.type = HDA_FIXUP_PINS,
|
|
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
|
|
{ 0x1b, 0x90170110 }, /* speaker */
|
|
|
|
{ 0x1d, 0x90a7013e }, /* int mic */
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
},
|
2013-07-04 15:06:04 +00:00
|
|
|
[AD1986A_FIXUP_SAMSUNG] = {
|
|
|
|
.type = HDA_FIXUP_PINS,
|
|
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
|
|
{ 0x1b, 0x90170110 }, /* speaker */
|
|
|
|
{ 0x1d, 0x90a7013e }, /* int mic */
|
|
|
|
{ 0x20, 0x411111f0 }, /* N/A */
|
|
|
|
{ 0x24, 0x411111f0 }, /* N/A */
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
},
|
2013-07-05 12:14:14 +00:00
|
|
|
[AD1986A_FIXUP_3STACK] = {
|
|
|
|
.type = HDA_FIXUP_PINS,
|
|
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
|
|
{ 0x1a, 0x02214021 }, /* headphone */
|
|
|
|
{ 0x1b, 0x01014011 }, /* front */
|
|
|
|
{ 0x1c, 0x01013012 }, /* surround */
|
|
|
|
{ 0x1d, 0x01019015 }, /* clfe */
|
|
|
|
{ 0x1e, 0x411111f0 }, /* N/A */
|
|
|
|
{ 0x1f, 0x02a190f0 }, /* mic */
|
|
|
|
{ 0x20, 0x018130f0 }, /* line-in */
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[AD1986A_FIXUP_LAPTOP] = {
|
|
|
|
.type = HDA_FIXUP_PINS,
|
|
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
|
|
{ 0x1a, 0x02214021 }, /* headphone */
|
|
|
|
{ 0x1b, 0x90170110 }, /* speaker */
|
|
|
|
{ 0x1c, 0x411111f0 }, /* N/A */
|
|
|
|
{ 0x1d, 0x411111f0 }, /* N/A */
|
|
|
|
{ 0x1e, 0x411111f0 }, /* N/A */
|
|
|
|
{ 0x1f, 0x02a191f0 }, /* mic */
|
|
|
|
{ 0x20, 0x411111f0 }, /* N/A */
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[AD1986A_FIXUP_LAPTOP_IMIC] = {
|
|
|
|
.type = HDA_FIXUP_PINS,
|
|
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
|
|
{ 0x1d, 0x90a7013e }, /* int mic */
|
|
|
|
{}
|
|
|
|
},
|
|
|
|
.chained_before = 1,
|
|
|
|
.chain_id = AD1986A_FIXUP_LAPTOP,
|
|
|
|
},
|
2013-01-22 17:18:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
|
2013-07-05 12:14:14 +00:00
|
|
|
SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
|
|
|
|
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
|
|
|
|
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
|
|
|
|
SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
|
|
|
|
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
|
2013-07-04 15:06:04 +00:00
|
|
|
SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
|
2013-07-04 14:50:46 +00:00
|
|
|
SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
|
2013-01-22 17:18:42 +00:00
|
|
|
SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
|
2013-07-05 12:14:14 +00:00
|
|
|
SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
|
|
|
|
SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_model_fixup ad1986a_fixup_models[] = {
|
|
|
|
{ .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
|
|
|
|
{ .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
|
|
|
|
{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
|
|
|
|
{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
|
2013-01-22 17:18:42 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2012-12-21 14:17:06 +00:00
|
|
|
/*
|
|
|
|
*/
|
2013-07-05 12:14:14 +00:00
|
|
|
static int patch_ad1986a(struct hda_codec *codec)
|
2012-12-21 14:17:06 +00:00
|
|
|
{
|
2013-01-22 15:45:58 +00:00
|
|
|
int err;
|
|
|
|
struct ad198x_spec *spec;
|
|
|
|
|
|
|
|
err = alloc_ad_spec(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
2012-12-21 14:17:06 +00:00
|
|
|
|
|
|
|
/* AD1986A has the inverted EAPD implementation */
|
|
|
|
codec->inv_eapd = 1;
|
|
|
|
|
2013-01-21 15:40:16 +00:00
|
|
|
spec->gen.mixer_nid = 0x07;
|
2013-03-18 10:25:51 +00:00
|
|
|
spec->gen.beep_nid = 0x19;
|
2012-12-21 14:17:06 +00:00
|
|
|
set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
|
|
|
|
|
|
|
|
/* AD1986A has a hardware problem that it can't share a stream
|
|
|
|
* with multiple output pins. The copy of front to surrounds
|
|
|
|
* causes noisy or silent outputs at a certain timing, e.g.
|
|
|
|
* changing the volume.
|
|
|
|
* So, let's disable the shared stream.
|
|
|
|
*/
|
|
|
|
spec->gen.multiout.no_share_stream = 1;
|
|
|
|
|
2013-07-05 12:14:14 +00:00
|
|
|
snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
|
|
|
|
ad1986a_fixups);
|
2013-01-22 17:18:42 +00:00
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
err = ad198x_parse_auto_config(codec);
|
|
|
|
if (err < 0) {
|
2013-03-18 10:25:51 +00:00
|
|
|
snd_hda_gen_free(codec);
|
2013-01-22 15:45:58 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-01-22 17:18:42 +00:00
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
|
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
return 0;
|
2012-12-21 14:17:06 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
2005-04-14 11:35:51 +00:00
|
|
|
* AD1983 specific
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
/*
|
|
|
|
* SPDIF mux control for AD1983 auto-parser
|
|
|
|
*/
|
|
|
|
static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
static const char * const texts2[] = { "PCM", "ADC" };
|
|
|
|
static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
|
|
|
|
hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
|
|
|
|
int num_conns = snd_hda_get_num_conns(codec, dig_out);
|
|
|
|
|
|
|
|
if (num_conns == 2)
|
|
|
|
return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
|
|
|
|
else if (num_conns == 3)
|
|
|
|
return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
|
|
|
|
else
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_smux;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
unsigned int val = ucontrol->value.enumerated.item[0];
|
|
|
|
hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
|
|
|
|
int num_conns = snd_hda_get_num_conns(codec, dig_out);
|
|
|
|
|
|
|
|
if (val >= num_conns)
|
|
|
|
return -EINVAL;
|
|
|
|
if (spec->cur_smux == val)
|
|
|
|
return 0;
|
|
|
|
spec->cur_smux = val;
|
|
|
|
snd_hda_codec_write_cache(codec, dig_out, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL, val);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct snd_kcontrol_new ad1983_auto_smux_mixer = {
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
.name = "IEC958 Playback Source",
|
|
|
|
.info = ad1983_auto_smux_enum_info,
|
|
|
|
.get = ad1983_auto_smux_enum_get,
|
|
|
|
.put = ad1983_auto_smux_enum_put,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
|
|
|
|
int num_conns;
|
|
|
|
|
|
|
|
if (!dig_out)
|
|
|
|
return 0;
|
|
|
|
num_conns = snd_hda_get_num_conns(codec, dig_out);
|
|
|
|
if (num_conns != 2 && num_conns != 3)
|
|
|
|
return 0;
|
|
|
|
if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
|
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-04 13:48:04 +00:00
|
|
|
static int patch_ad1983(struct hda_codec *codec)
|
2012-12-21 14:17:06 +00:00
|
|
|
{
|
2013-01-22 15:45:58 +00:00
|
|
|
struct ad198x_spec *spec;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
int err;
|
2012-12-21 14:17:06 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
err = alloc_ad_spec(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
|
|
|
|
2013-03-18 10:25:51 +00:00
|
|
|
spec->gen.beep_nid = 0x10;
|
2012-12-21 14:17:06 +00:00
|
|
|
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad198x_parse_auto_config(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad1983_add_spdif_mux_ctl(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
return 0;
|
2013-01-22 15:45:58 +00:00
|
|
|
|
|
|
|
error:
|
2013-03-18 10:25:51 +00:00
|
|
|
snd_hda_gen_free(codec);
|
2013-01-22 15:45:58 +00:00
|
|
|
return err;
|
2012-12-21 14:17:06 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2005-04-14 11:35:51 +00:00
|
|
|
/*
|
|
|
|
* AD1981 HD specific
|
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-01-22 17:18:42 +00:00
|
|
|
static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
|
|
|
|
const struct hda_fixup *fix, int action)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
|
|
|
spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
|
|
|
|
spec->eapd_nid = 0x05;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the upper-limit for mixer amp to 0dB for avoiding the possible
|
|
|
|
* damage by overloading
|
|
|
|
*/
|
|
|
|
static void ad1981_fixup_amp_override(struct hda_codec *codec,
|
|
|
|
const struct hda_fixup *fix, int action)
|
|
|
|
{
|
|
|
|
if (action == HDA_FIXUP_ACT_PRE_PROBE)
|
|
|
|
snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
|
|
|
|
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
|
|
|
|
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
|
|
|
|
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
|
|
|
|
(1 << AC_AMPCAP_MUTE_SHIFT));
|
|
|
|
}
|
|
|
|
|
|
|
|
enum {
|
|
|
|
AD1981_FIXUP_AMP_OVERRIDE,
|
|
|
|
AD1981_FIXUP_HP_EAPD,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_fixup ad1981_fixups[] = {
|
|
|
|
[AD1981_FIXUP_AMP_OVERRIDE] = {
|
|
|
|
.type = HDA_FIXUP_FUNC,
|
|
|
|
.v.func = ad1981_fixup_amp_override,
|
|
|
|
},
|
|
|
|
[AD1981_FIXUP_HP_EAPD] = {
|
|
|
|
.type = HDA_FIXUP_FUNC,
|
|
|
|
.v.func = ad1981_fixup_hp_eapd,
|
|
|
|
.chained = true,
|
|
|
|
.chain_id = AD1981_FIXUP_AMP_OVERRIDE,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
|
|
|
|
SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
|
|
|
|
SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
|
|
|
|
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
|
|
|
|
/* HP nx6320 (reversed SSID, H/W bug) */
|
|
|
|
SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2013-07-04 13:48:04 +00:00
|
|
|
static int patch_ad1981(struct hda_codec *codec)
|
2012-12-21 14:17:06 +00:00
|
|
|
{
|
2013-01-22 15:45:58 +00:00
|
|
|
struct ad198x_spec *spec;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
int err;
|
2012-12-21 14:17:06 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
err = alloc_ad_spec(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
spec = codec->spec;
|
|
|
|
|
2013-01-21 15:40:16 +00:00
|
|
|
spec->gen.mixer_nid = 0x0e;
|
2013-03-18 10:25:51 +00:00
|
|
|
spec->gen.beep_nid = 0x10;
|
2012-12-21 14:17:06 +00:00
|
|
|
set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
|
2013-01-22 17:18:42 +00:00
|
|
|
|
|
|
|
snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
|
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad198x_parse_auto_config(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad1983_add_spdif_mux_ctl(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
2013-01-22 17:18:42 +00:00
|
|
|
|
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
return 0;
|
2013-01-22 15:45:58 +00:00
|
|
|
|
|
|
|
error:
|
2013-03-18 10:25:51 +00:00
|
|
|
snd_hda_gen_free(codec);
|
2013-01-22 15:45:58 +00:00
|
|
|
return err;
|
2012-12-21 14:17:06 +00:00
|
|
|
}
|
|
|
|
|
2005-04-14 11:35:51 +00:00
|
|
|
|
2005-11-17 14:31:34 +00:00
|
|
|
/*
|
|
|
|
* AD1988
|
|
|
|
*
|
|
|
|
* Output pins and routes
|
|
|
|
*
|
2005-11-24 15:06:23 +00:00
|
|
|
* Pin Mix Sel DAC (*)
|
2005-11-17 14:31:34 +00:00
|
|
|
* port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
|
|
|
|
* port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
|
|
|
|
* port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
|
|
|
|
* port-D 0x12 (mute/hp) <- 0x29 <- 04
|
|
|
|
* port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
|
|
|
|
* port-F 0x16 (mute) <- 0x2a <- 06
|
|
|
|
* port-G 0x24 (mute) <- 0x27 <- 05
|
|
|
|
* port-H 0x25 (mute) <- 0x28 <- 0a
|
|
|
|
* mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
|
|
|
|
*
|
2005-11-24 15:06:23 +00:00
|
|
|
* DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
|
|
|
|
* (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
|
2005-11-17 14:31:34 +00:00
|
|
|
*
|
|
|
|
* Input pins and routes
|
|
|
|
*
|
|
|
|
* pin boost mix input # / adc input #
|
|
|
|
* port-A 0x11 -> 0x38 -> mix 2, ADC 0
|
|
|
|
* port-B 0x14 -> 0x39 -> mix 0, ADC 1
|
|
|
|
* port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
|
|
|
|
* port-D 0x12 -> 0x3d -> mix 3, ADC 8
|
|
|
|
* port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
|
|
|
|
* port-F 0x16 -> 0x3b -> mix 5, ADC 3
|
|
|
|
* port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
|
|
|
|
* port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* DAC assignment
|
2005-11-24 15:06:23 +00:00
|
|
|
* 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
|
2005-11-24 15:17:20 +00:00
|
|
|
* 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
|
2005-11-17 14:31:34 +00:00
|
|
|
*
|
|
|
|
* Inputs of Analog Mix (0x20)
|
|
|
|
* 0:Port-B (front mic)
|
|
|
|
* 1:Port-C/G/H (line-in)
|
|
|
|
* 2:Port-A
|
|
|
|
* 3:Port-D (line-in/2)
|
|
|
|
* 4:Port-E/G/H (mic-in)
|
|
|
|
* 5:Port-F (mic2-in)
|
|
|
|
* 6:CD
|
|
|
|
* 7:Beep
|
|
|
|
*
|
|
|
|
* ADC selection
|
|
|
|
* 0:Port-A
|
|
|
|
* 1:Port-B (front mic-in)
|
|
|
|
* 2:Port-C (line-in)
|
|
|
|
* 3:Port-F (mic2-in)
|
|
|
|
* 4:Port-E (mic-in)
|
|
|
|
* 5:CD
|
|
|
|
* 6:Port-G
|
|
|
|
* 7:Port-H
|
|
|
|
* 8:Port-D (line-in/2)
|
|
|
|
* 9:Mix
|
|
|
|
*
|
|
|
|
* Proposed pin assignments by the datasheet
|
|
|
|
*
|
|
|
|
* 6-stack
|
|
|
|
* Port-A front headphone
|
|
|
|
* B front mic-in
|
|
|
|
* C rear line-in
|
|
|
|
* D rear front-out
|
|
|
|
* E rear mic-in
|
|
|
|
* F rear surround
|
|
|
|
* G rear CLFE
|
|
|
|
* H rear side
|
|
|
|
*
|
|
|
|
* 3-stack
|
|
|
|
* Port-A front headphone
|
|
|
|
* B front mic
|
|
|
|
* C rear line-in/surround
|
|
|
|
* D rear front-out
|
|
|
|
* E rear mic-in/CLFE
|
|
|
|
*
|
|
|
|
* laptop
|
|
|
|
* Port-A headphone
|
|
|
|
* B mic-in
|
|
|
|
* C docking station
|
|
|
|
* D internal speaker (with EAPD)
|
|
|
|
* E/F quad mic array
|
|
|
|
*/
|
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
#ifdef ENABLE_AD_STATIC_QUIRKS
|
2005-11-17 14:31:34 +00:00
|
|
|
static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
|
|
|
|
spec->num_channel_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
|
|
|
|
spec->num_channel_mode, spec->multiout.max_channels);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
2006-07-28 12:47:34 +00:00
|
|
|
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
|
|
|
|
spec->num_channel_mode,
|
|
|
|
&spec->multiout.max_channels);
|
2006-10-10 17:49:31 +00:00
|
|
|
if (err >= 0 && spec->need_dac_fix)
|
2006-03-27 10:52:22 +00:00
|
|
|
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
|
2006-07-28 12:47:34 +00:00
|
|
|
return err;
|
2005-11-17 14:31:34 +00:00
|
|
|
}
|
2013-01-22 15:45:58 +00:00
|
|
|
#endif /* ENABLE_AD_STATIC_QUIRKS */
|
2005-11-17 14:31:34 +00:00
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
static const char * const texts[] = {
|
|
|
|
"PCM", "ADC1", "ADC2", "ADC3",
|
|
|
|
};
|
|
|
|
int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
|
|
|
|
if (num_conns > 4)
|
|
|
|
num_conns = 4;
|
|
|
|
return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_smux;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
unsigned int val = ucontrol->value.enumerated.item[0];
|
|
|
|
struct nid_path *path;
|
|
|
|
int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
|
|
|
|
|
|
|
|
if (val >= num_conns)
|
|
|
|
return -EINVAL;
|
|
|
|
if (spec->cur_smux == val)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
mutex_lock(&codec->control_mutex);
|
|
|
|
codec->cached_write = 1;
|
|
|
|
path = snd_hda_get_path_from_idx(codec,
|
|
|
|
spec->smux_paths[spec->cur_smux]);
|
|
|
|
if (path)
|
|
|
|
snd_hda_activate_path(codec, path, false, true);
|
|
|
|
path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
|
|
|
|
if (path)
|
|
|
|
snd_hda_activate_path(codec, path, true, true);
|
|
|
|
spec->cur_smux = val;
|
|
|
|
codec->cached_write = 0;
|
|
|
|
mutex_unlock(&codec->control_mutex);
|
|
|
|
snd_hda_codec_flush_cache(codec); /* flush the updates */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
.name = "IEC958 Playback Source",
|
|
|
|
.info = ad1988_auto_smux_enum_info,
|
|
|
|
.get = ad1988_auto_smux_enum_get,
|
|
|
|
.put = ad1988_auto_smux_enum_put,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int ad1988_auto_init(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
int i, err;
|
|
|
|
|
|
|
|
err = snd_hda_gen_init(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
if (!spec->gen.autocfg.dig_outs)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
struct nid_path *path;
|
|
|
|
path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
|
|
|
|
if (path)
|
|
|
|
snd_hda_activate_path(codec, path, path->active, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
int i, num_conns;
|
|
|
|
/* we create four static faked paths, since AD codecs have odd
|
|
|
|
* widget connections regarding the SPDIF out source
|
|
|
|
*/
|
|
|
|
static struct nid_path fake_paths[4] = {
|
|
|
|
{
|
|
|
|
.depth = 3,
|
|
|
|
.path = { 0x02, 0x1d, 0x1b },
|
|
|
|
.idx = { 0, 0, 0 },
|
|
|
|
.multi = { 0, 0, 0 },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.depth = 4,
|
|
|
|
.path = { 0x08, 0x0b, 0x1d, 0x1b },
|
|
|
|
.idx = { 0, 0, 1, 0 },
|
|
|
|
.multi = { 0, 1, 0, 0 },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.depth = 4,
|
|
|
|
.path = { 0x09, 0x0b, 0x1d, 0x1b },
|
|
|
|
.idx = { 0, 1, 1, 0 },
|
|
|
|
.multi = { 0, 1, 0, 0 },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.depth = 4,
|
|
|
|
.path = { 0x0f, 0x0b, 0x1d, 0x1b },
|
|
|
|
.idx = { 0, 2, 1, 0 },
|
|
|
|
.multi = { 0, 1, 0, 0 },
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
/* SPDIF source mux appears to be present only on AD1988A */
|
|
|
|
if (!spec->gen.autocfg.dig_outs ||
|
|
|
|
get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
|
|
|
|
if (num_conns != 3 && num_conns != 4)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < num_conns; i++) {
|
|
|
|
struct nid_path *path = snd_array_new(&spec->gen.paths);
|
|
|
|
if (!path)
|
|
|
|
return -ENOMEM;
|
|
|
|
*path = fake_paths[i];
|
|
|
|
if (!i)
|
|
|
|
path->active = 1;
|
|
|
|
spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->patch_ops.init = ad1988_auto_init;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-24 15:06:23 +00:00
|
|
|
/*
|
|
|
|
*/
|
|
|
|
|
2013-07-04 14:34:20 +00:00
|
|
|
enum {
|
|
|
|
AD1988_FIXUP_6STACK_DIG,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_fixup ad1988_fixups[] = {
|
|
|
|
[AD1988_FIXUP_6STACK_DIG] = {
|
|
|
|
.type = HDA_FIXUP_PINS,
|
|
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
|
|
{ 0x11, 0x02214130 }, /* front-hp */
|
|
|
|
{ 0x12, 0x01014010 }, /* line-out */
|
|
|
|
{ 0x14, 0x02a19122 }, /* front-mic */
|
|
|
|
{ 0x15, 0x01813021 }, /* line-in */
|
|
|
|
{ 0x16, 0x01011012 }, /* line-out */
|
|
|
|
{ 0x17, 0x01a19020 }, /* mic */
|
|
|
|
{ 0x1b, 0x0145f1f0 }, /* SPDIF */
|
|
|
|
{ 0x24, 0x01016011 }, /* line-out */
|
|
|
|
{ 0x25, 0x01012013 }, /* line-out */
|
|
|
|
{ }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_model_fixup ad1988_fixup_models[] = {
|
|
|
|
{ .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int patch_ad1988(struct hda_codec *codec)
|
2005-11-24 15:06:23 +00:00
|
|
|
{
|
2013-01-22 15:45:58 +00:00
|
|
|
struct ad198x_spec *spec;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
int err;
|
2005-11-24 15:06:23 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
err = alloc_ad_spec(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
|
|
|
|
2013-01-21 15:40:16 +00:00
|
|
|
spec->gen.mixer_nid = 0x20;
|
2013-01-23 16:00:31 +00:00
|
|
|
spec->gen.mixer_merge_nid = 0x21;
|
2013-03-18 10:25:51 +00:00
|
|
|
spec->gen.beep_nid = 0x10;
|
2012-12-21 14:17:06 +00:00
|
|
|
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
2013-07-04 14:34:20 +00:00
|
|
|
|
|
|
|
snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
|
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad198x_parse_auto_config(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad1988_add_spdif_mux_ctl(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
2013-07-04 14:34:20 +00:00
|
|
|
|
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
return 0;
|
2013-01-22 15:45:58 +00:00
|
|
|
|
|
|
|
error:
|
2013-03-18 10:25:51 +00:00
|
|
|
snd_hda_gen_free(codec);
|
2013-01-22 15:45:58 +00:00
|
|
|
return err;
|
2005-11-24 15:06:23 +00:00
|
|
|
}
|
|
|
|
|
2005-11-17 14:31:34 +00:00
|
|
|
|
2007-05-18 16:21:41 +00:00
|
|
|
/*
|
|
|
|
* AD1884 / AD1984
|
|
|
|
*
|
|
|
|
* port-B - front line/mic-in
|
|
|
|
* port-E - aux in/out
|
|
|
|
* port-F - aux in/out
|
|
|
|
* port-C - rear line/mic-in
|
|
|
|
* port-D - rear line/hp-out
|
|
|
|
* port-A - front line/hp-out
|
|
|
|
*
|
|
|
|
* AD1984 = AD1884 + two digital mic-ins
|
|
|
|
*
|
2013-07-04 13:36:56 +00:00
|
|
|
* AD1883 / AD1884A / AD1984A / AD1984B
|
|
|
|
*
|
|
|
|
* port-B (0x14) - front mic-in
|
|
|
|
* port-E (0x1c) - rear mic-in
|
|
|
|
* port-F (0x16) - CD / ext out
|
|
|
|
* port-C (0x15) - rear line-in
|
|
|
|
* port-D (0x12) - rear line-out
|
|
|
|
* port-A (0x11) - front hp-out
|
|
|
|
*
|
|
|
|
* AD1984A = AD1884A + digital-mic
|
|
|
|
* AD1883 = equivalent with AD1984A
|
|
|
|
* AD1984B = AD1984A + extra SPDIF-out
|
2007-05-18 16:21:41 +00:00
|
|
|
*/
|
2013-01-22 17:18:42 +00:00
|
|
|
|
|
|
|
/* set the upper-limit for mixer amp to 0dB for avoiding the possible
|
|
|
|
* damage by overloading
|
|
|
|
*/
|
|
|
|
static void ad1884_fixup_amp_override(struct hda_codec *codec,
|
|
|
|
const struct hda_fixup *fix, int action)
|
|
|
|
{
|
|
|
|
if (action == HDA_FIXUP_ACT_PRE_PROBE)
|
|
|
|
snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
|
|
|
|
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
|
|
|
|
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
|
|
|
|
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
|
|
|
|
(1 << AC_AMPCAP_MUTE_SHIFT));
|
|
|
|
}
|
|
|
|
|
2013-07-04 12:32:16 +00:00
|
|
|
/* toggle GPIO1 according to the mute state */
|
|
|
|
static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = private_data;
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (spec->eapd_nid)
|
|
|
|
ad_vmaster_eapd_hook(private_data, enabled);
|
|
|
|
snd_hda_codec_update_cache(codec, 0x01, 0,
|
|
|
|
AC_VERB_SET_GPIO_DATA,
|
|
|
|
enabled ? 0x00 : 0x02);
|
|
|
|
}
|
|
|
|
|
2013-01-22 17:18:42 +00:00
|
|
|
static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
|
|
|
|
const struct hda_fixup *fix, int action)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
2013-07-04 12:32:16 +00:00
|
|
|
static const struct hda_verb gpio_init_verbs[] = {
|
|
|
|
{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
|
|
|
|
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
|
|
|
|
{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
|
|
|
|
{},
|
|
|
|
};
|
2013-01-22 17:18:42 +00:00
|
|
|
|
2013-07-04 10:54:22 +00:00
|
|
|
switch (action) {
|
|
|
|
case HDA_FIXUP_ACT_PRE_PROBE:
|
2013-07-04 12:32:16 +00:00
|
|
|
spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
|
2013-12-02 12:19:45 +00:00
|
|
|
spec->gen.own_eapd_ctl = 1;
|
2013-07-04 12:32:16 +00:00
|
|
|
snd_hda_sequence_write_cache(codec, gpio_init_verbs);
|
2013-07-04 10:54:22 +00:00
|
|
|
break;
|
|
|
|
case HDA_FIXUP_ACT_PROBE:
|
2013-01-22 17:18:42 +00:00
|
|
|
if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
|
|
|
|
spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
|
|
|
|
else
|
|
|
|
spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
|
2013-07-04 10:54:22 +00:00
|
|
|
break;
|
2013-01-22 17:18:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-25 22:24:14 +00:00
|
|
|
static void ad1884_fixup_thinkpad(struct hda_codec *codec,
|
|
|
|
const struct hda_fixup *fix, int action)
|
|
|
|
{
|
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
|
|
2013-10-25 22:33:58 +00:00
|
|
|
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
2013-10-25 22:24:14 +00:00
|
|
|
spec->gen.keep_eapd_on = 1;
|
2013-10-25 22:33:58 +00:00
|
|
|
spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
|
|
|
|
spec->eapd_nid = 0x12;
|
|
|
|
}
|
2013-10-25 22:24:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-04 12:45:37 +00:00
|
|
|
/* set magic COEFs for dmic */
|
|
|
|
static const struct hda_verb ad1884_dmic_init_verbs[] = {
|
|
|
|
{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
|
|
|
|
{0x01, AC_VERB_SET_PROC_COEF, 0x08},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2013-01-22 17:18:42 +00:00
|
|
|
enum {
|
|
|
|
AD1884_FIXUP_AMP_OVERRIDE,
|
|
|
|
AD1884_FIXUP_HP_EAPD,
|
2013-07-04 12:45:37 +00:00
|
|
|
AD1884_FIXUP_DMIC_COEF,
|
2013-10-25 22:24:14 +00:00
|
|
|
AD1884_FIXUP_THINKPAD,
|
2013-07-04 13:14:17 +00:00
|
|
|
AD1884_FIXUP_HP_TOUCHSMART,
|
2013-01-22 17:18:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hda_fixup ad1884_fixups[] = {
|
|
|
|
[AD1884_FIXUP_AMP_OVERRIDE] = {
|
|
|
|
.type = HDA_FIXUP_FUNC,
|
|
|
|
.v.func = ad1884_fixup_amp_override,
|
|
|
|
},
|
|
|
|
[AD1884_FIXUP_HP_EAPD] = {
|
|
|
|
.type = HDA_FIXUP_FUNC,
|
|
|
|
.v.func = ad1884_fixup_hp_eapd,
|
|
|
|
.chained = true,
|
|
|
|
.chain_id = AD1884_FIXUP_AMP_OVERRIDE,
|
|
|
|
},
|
2013-07-04 12:45:37 +00:00
|
|
|
[AD1884_FIXUP_DMIC_COEF] = {
|
|
|
|
.type = HDA_FIXUP_VERBS,
|
|
|
|
.v.verbs = ad1884_dmic_init_verbs,
|
|
|
|
},
|
2013-10-25 22:24:14 +00:00
|
|
|
[AD1884_FIXUP_THINKPAD] = {
|
|
|
|
.type = HDA_FIXUP_FUNC,
|
|
|
|
.v.func = ad1884_fixup_thinkpad,
|
|
|
|
.chained = true,
|
|
|
|
.chain_id = AD1884_FIXUP_DMIC_COEF,
|
|
|
|
},
|
2013-07-04 13:14:17 +00:00
|
|
|
[AD1884_FIXUP_HP_TOUCHSMART] = {
|
|
|
|
.type = HDA_FIXUP_VERBS,
|
|
|
|
.v.verbs = ad1884_dmic_init_verbs,
|
|
|
|
.chained = true,
|
|
|
|
.chain_id = AD1884_FIXUP_HP_EAPD,
|
|
|
|
},
|
2013-01-22 17:18:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
|
2013-07-04 13:14:17 +00:00
|
|
|
SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
|
2013-01-22 17:18:42 +00:00
|
|
|
SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
|
2013-10-25 22:24:14 +00:00
|
|
|
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
|
2013-01-22 17:18:42 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-07-04 13:36:56 +00:00
|
|
|
static int patch_ad1884(struct hda_codec *codec)
|
2012-12-21 14:17:06 +00:00
|
|
|
{
|
2013-01-22 15:45:58 +00:00
|
|
|
struct ad198x_spec *spec;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
int err;
|
2012-12-21 14:17:06 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
err = alloc_ad_spec(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
|
|
|
|
2013-01-21 15:40:16 +00:00
|
|
|
spec->gen.mixer_nid = 0x20;
|
2013-03-18 10:25:51 +00:00
|
|
|
spec->gen.beep_nid = 0x10;
|
2012-12-21 14:17:06 +00:00
|
|
|
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
2013-01-22 17:18:42 +00:00
|
|
|
|
|
|
|
snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
|
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad198x_parse_auto_config(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad1983_add_spdif_mux_ctl(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
2013-01-22 17:18:42 +00:00
|
|
|
|
|
|
|
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
|
|
|
|
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
return 0;
|
2012-12-21 14:17:06 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
error:
|
2013-03-18 10:25:51 +00:00
|
|
|
snd_hda_gen_free(codec);
|
2013-01-22 15:45:58 +00:00
|
|
|
return err;
|
2012-12-21 14:17:06 +00:00
|
|
|
}
|
|
|
|
|
2007-06-20 13:46:13 +00:00
|
|
|
/*
|
2008-08-18 11:53:07 +00:00
|
|
|
* AD1882 / AD1882A
|
2007-06-20 13:46:13 +00:00
|
|
|
*
|
|
|
|
* port-A - front hp-out
|
|
|
|
* port-B - front mic-in
|
|
|
|
* port-C - rear line-in, shared surr-out (3stack)
|
|
|
|
* port-D - rear line-out
|
|
|
|
* port-E - rear mic-in, shared clfe-out (3stack)
|
|
|
|
* port-F - rear surr-out (6stack)
|
|
|
|
* port-G - rear clfe-out (6stack)
|
|
|
|
*/
|
|
|
|
|
2013-07-04 13:16:31 +00:00
|
|
|
static int patch_ad1882(struct hda_codec *codec)
|
2012-12-21 14:17:06 +00:00
|
|
|
{
|
2013-01-22 15:45:58 +00:00
|
|
|
struct ad198x_spec *spec;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
int err;
|
2012-12-21 14:17:06 +00:00
|
|
|
|
2013-01-22 15:45:58 +00:00
|
|
|
err = alloc_ad_spec(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec = codec->spec;
|
|
|
|
|
2013-01-21 15:40:16 +00:00
|
|
|
spec->gen.mixer_nid = 0x20;
|
2013-01-23 16:00:31 +00:00
|
|
|
spec->gen.mixer_merge_nid = 0x21;
|
2013-03-18 10:25:51 +00:00
|
|
|
spec->gen.beep_nid = 0x10;
|
2012-12-21 14:17:06 +00:00
|
|
|
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad198x_parse_auto_config(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
err = ad1988_add_spdif_mux_ctl(codec);
|
|
|
|
if (err < 0)
|
2013-01-22 15:45:58 +00:00
|
|
|
goto error;
|
ALSA: hda - Add SPDIF mux control to AD codec auto-parser
AD codecs have strange implementations for choosing the SPDIF-output
mux source: the digital audio out widget may take the sources from
multiple connections, where 0x01 indicates it's a PCM while others
point ADCs. It's obviously invalid in the HD-audio spec POV, but it's
somehow convincing, too. And, to make things more complex, AD1988A
and AD1882 have deeper connection routes that aren't expressed
correctly.
In this patch, the SPDIF mux control is implemented in two ways:
- For easier one like AD1981, AD1983, AD1884 and AD1984, where the
SPDIF audio out widget takes just two or three sources, we can
simply implement via the normal input_mux and connection verb
calls.
- For the complex routes like AD1988A (but not AD1988B) or AD1882, we
prepare "faked" paths represented statically, and switch the paths
using these static ones, instead of parsing the routes from the
widget tree.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-01-22 14:31:33 +00:00
|
|
|
return 0;
|
2013-01-22 15:45:58 +00:00
|
|
|
|
|
|
|
error:
|
2013-03-18 10:25:51 +00:00
|
|
|
snd_hda_gen_free(codec);
|
2013-01-22 15:45:58 +00:00
|
|
|
return err;
|
2012-12-21 14:17:06 +00:00
|
|
|
}
|
2007-06-20 13:46:13 +00:00
|
|
|
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* patch entries
|
|
|
|
*/
|
2011-05-02 09:33:15 +00:00
|
|
|
static const struct hda_codec_preset snd_hda_preset_analog[] = {
|
2013-07-04 13:36:56 +00:00
|
|
|
{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 },
|
2007-06-20 13:46:13 +00:00
|
|
|
{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
|
2013-07-04 13:36:56 +00:00
|
|
|
{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 },
|
2007-05-18 16:21:41 +00:00
|
|
|
{ .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
|
2013-07-04 13:36:56 +00:00
|
|
|
{ .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 },
|
|
|
|
{ .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 },
|
2005-04-14 11:35:51 +00:00
|
|
|
{ .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
|
|
|
|
{ .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
|
2013-07-04 13:36:56 +00:00
|
|
|
{ .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 },
|
2005-04-16 22:20:36 +00:00
|
|
|
{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
|
2005-11-17 14:31:34 +00:00
|
|
|
{ .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
|
2006-04-21 14:09:31 +00:00
|
|
|
{ .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
|
2008-08-18 11:53:07 +00:00
|
|
|
{ .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
|
2008-04-15 16:46:42 +00:00
|
|
|
{ .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
|
|
|
|
{ .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
|
2005-04-16 22:20:36 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
2008-11-27 14:47:11 +00:00
|
|
|
|
|
|
|
MODULE_ALIAS("snd-hda-codec-id:11d4*");
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DESCRIPTION("Analog Devices HD-audio codec");
|
|
|
|
|
|
|
|
static struct hda_codec_preset_list analog_list = {
|
|
|
|
.preset = snd_hda_preset_analog,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init patch_analog_init(void)
|
|
|
|
{
|
|
|
|
return snd_hda_add_codec_preset(&analog_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit patch_analog_exit(void)
|
|
|
|
{
|
|
|
|
snd_hda_delete_codec_preset(&analog_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(patch_analog_init)
|
|
|
|
module_exit(patch_analog_exit)
|