Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
January 2013
- 92 participants
- 242 discussions
18 Jan '13
Hi,
I'm new to alsa and I'm trying to do the following. I have configured my
rythm box to use the loopback device. I've written a little program to
capture everything that comes on the other side of the loopback and save
that into a file.
If I play a song on rythm box I see actual packets on the couterside of the
loopback however I save these packets in a file and try to play them back
using my sound card I hear no sound.
I use the following .asoundrc
pcm.loopplayback
{
type hw
card 1
device 1
subdevice 0
}
pcm.loopcapture
{
type hw
card 1
device 0
subdevice 0
}
pcm.play48 {
type plug
slave {
pcm loopplayback
rate 44100
channels 2
}
}
attached is my test program to do the capturing. Anyone has any idea what
I'm doing wrong ?
Kind regards
Erik
1
0
[alsa-devel] [PATCH 1/2] ASoC: wm_adsp: Set ADSP1 clock rate to match sys clock
by Chris Rattray 18 Jan '13
by Chris Rattray 18 Jan '13
18 Jan '13
Sets the ADSP1 clock rate to match the system clock
rate. To support this the codec driver provides
details of register containing the system clock
control bits.
Signed-off-by: Chris Rattray <crattray(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/wm_adsp.c | 35 +++++++++++++++++++++++++++++++++++
sound/soc/codecs/wm_adsp.h | 3 +++
2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 9a3f220..739dab6 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -75,6 +75,8 @@
#define ADSP1_CONTROL_30 0x24
#define ADSP1_CONTROL_31 0x26
+#define ADSP1_CLOCKING 38
+
/*
* ADSP1 Control 19
*/
@@ -103,6 +105,13 @@
#define ADSP1_START_SHIFT 0 /* DSP1_START */
#define ADSP1_START_WIDTH 1 /* DSP1_START */
+/*
+ * ADSP1 Control 31
+ */
+#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
+#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
+#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
+
#define ADSP2_CONTROL 0
#define ADSP2_CLOCKING 1
#define ADSP2_STATUS1 4
@@ -817,12 +826,38 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift];
int ret;
+ int val;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
ADSP1_SYS_ENA, ADSP1_SYS_ENA);
+ /*
+ * For simplicity set the DSP clock rate to be the
+ * SYSCLK rate rather than making it configurable.
+ */
+ if(dsp->sysclk_reg) {
+ ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
+ ret);
+ return ret;
+ }
+
+ val = (val & dsp->sysclk_mask)
+ >> dsp->sysclk_shift;
+
+ ret = regmap_update_bits(dsp->regmap,
+ dsp->base + ADSP1_CLOCKING,
+ ADSP1_CLK_SEL_MASK, val);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to set clock rate: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
ret = wm_adsp_load(dsp);
if (ret != 0)
goto err;
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 41206d7..cb8871a 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -40,6 +40,9 @@ struct wm_adsp {
struct regmap *regmap;
int base;
+ int sysclk_reg;
+ int sysclk_mask;
+ int sysclk_shift;
struct list_head alg_regions;
--
1.7.2.5
2
2
Re: [alsa-devel] HD-audio regression after commit 34588709af61be1550b4e2bcee5c85d0ac4f34d4
by Miro Hodak 18 Jan '13
by Miro Hodak 18 Jan '13
18 Jan '13
On Thu, Jan 17, 2013 at 3:40 PM, Manolo Díaz <diaz.manolo(a)gmail.com> wrote:
>
> branch tested: master
>
> commit d89012bef4ad6d33c1050dd2924f010f5072ff52
> Merge: ad92fbe 36c9db7
> Author: Takashi Iwai <tiwai(a)suse.de>
> Date: Thu Jan 17 17:47:19 2013 +0100
>
> Just the same: auto-mute doesn't work.
>
> alsa-info output show no differences (attached).
>
> Jack inserting event correctly detected again.
>
> #~ cat /sys/kernel/debug/tracing/trace
> # tracer: nop
> #
> # entries-in-buffer/entries-written: 1/1 #P:2
> #
> # _-----=> irqs-off
> # / _----=> need-resched
> # | / _---=> hardirq/softirq
> # || / _--=> preempt-depth
> # ||| / delay
> # TASK-PID CPU# |||| TIMESTAMP FUNCTION
> # | | | |||| | |
> <idle>-0 [001] d.h. 198.843063: hda_unsol_event: [0]
> res=4000000, res_ex=10
>
>
> Regards,
> --
> Manolo Díaz
>
Testing master branch, I got the similar results as Manolo
commit 920544e4bc95d5fb4465eb58e419a2c61074cd7e
Merge: 910fb91 ae12700
Author: Takashi Iwai <tiwai(a)suse.de>
Date: Wed Jan 16 16:26:03 2013 +0100
# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 1/1 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
<idle>-0 [000] d.h. 341.307150: hda_unsol_event: [0]
res=4000000, res_ex=10
No difference in alsa-info before and after headphones are plugged in
(other than timestamp):
http://pastebin.com/J1PiRia8
Should I test with the test/hda-gen-parser branch?
1
0
[alsa-devel] [PATCH RFC] ALSA: hda - Use generic parser for STAC/IDT codec driver
by Takashi Iwai 17 Jan '13
by Takashi Iwai 17 Jan '13
17 Jan '13
Finally we reached here. All codecs driver (except for CA0132, which
has really device-specific requirements) have been converted to use
the generic parser.
This patch appears bigger than others since it also involves with the
code shuffling, but mostly the cut-off of parser codes and adapt to
the generic parser flags. Most of fixup codecs haven't been changed
but just removed a few unnecessary codes.
The only missing stuff is the SPDIF mux control. It'll be added again
later.
Signed-off-by: Takashi Iwai <tiwai(a)suse.de>
---
sound/pci/hda/Kconfig | 1 +
sound/pci/hda/patch_sigmatel.c | 5219 ++++++++--------------------------------
2 files changed, 1019 insertions(+), 4201 deletions(-)
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 4004d40..4466bf6 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -112,6 +112,7 @@ config SND_HDA_CODEC_ANALOG
config SND_HDA_CODEC_SIGMATEL
bool "Build IDT/Sigmatel HD-audio codec support"
default y
+ select SND_HDA_GENERIC
help
Say Y here to include IDT (Sigmatel) HD-audio codec support in
snd-hda-intel driver, such as STAC9200.
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index f975735..9d2dfad 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -39,14 +39,11 @@
#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
+#include "hda_generic.h"
enum {
- STAC_VREF_EVENT = 1,
- STAC_INSERT_EVENT,
+ STAC_VREF_EVENT = 8,
STAC_PWR_EVENT,
- STAC_HP_EVENT,
- STAC_LO_EVENT,
- STAC_MIC_EVENT,
};
enum {
@@ -115,7 +112,6 @@ enum {
STAC_HP_DV4,
STAC_HP_DV5,
STAC_HP_HDX,
- STAC_HP_DV4_1222NR,
STAC_92HD71BXX_HP,
STAC_92HD71BXX_NO_DMIC,
STAC_92HD71BXX_NO_SMUX,
@@ -173,30 +169,14 @@ enum {
STAC_9872_MODELS
};
-struct sigmatel_mic_route {
- hda_nid_t pin;
- signed char mux_idx;
- signed char dmux_idx;
-};
-
-#define MAX_PINS_NUM 16
-#define MAX_ADCS_NUM 4
-#define MAX_DMICS_NUM 4
-
struct sigmatel_spec {
- struct snd_kcontrol_new *mixers[4];
- unsigned int num_mixers;
+ struct hda_gen_spec gen;
unsigned int eapd_switch: 1;
- unsigned int surr_switch: 1;
- unsigned int alt_switch: 1;
- unsigned int hp_detect: 1;
- unsigned int spdif_mute: 1;
- unsigned int check_volume_offset:1;
- unsigned int auto_mic:1;
unsigned int linear_tone_beep:1;
unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */
unsigned int volknob_init:1; /* special volume-knob initialization */
+ unsigned int powerdown_adcs:1;
/* gpio lines */
unsigned int eapd_mask;
@@ -218,6 +198,7 @@ struct sigmatel_spec {
/* analog loopback */
const struct snd_kcontrol_new *aloopback_ctl;
+ unsigned int aloopback;
unsigned char aloopback_mask;
unsigned char aloopback_shift;
@@ -225,458 +206,130 @@ struct sigmatel_spec {
unsigned int power_map_bits;
unsigned int num_pwrs;
const hda_nid_t *pwr_nids;
- const hda_nid_t *dac_list;
-
- /* playback */
- struct hda_input_mux *mono_mux;
- unsigned int cur_mmux;
- struct hda_multi_out multiout;
- hda_nid_t dac_nids[5];
- hda_nid_t hp_dacs[5];
- hda_nid_t speaker_dacs[5];
-
- int volume_offset;
-
- /* capture */
- const hda_nid_t *adc_nids;
- unsigned int num_adcs;
- const hda_nid_t *mux_nids;
- unsigned int num_muxes;
- const hda_nid_t *dmic_nids;
- unsigned int num_dmics;
- const hda_nid_t *dmux_nids;
- unsigned int num_dmuxes;
- const hda_nid_t *smux_nids;
- unsigned int num_smuxes;
- unsigned int num_analog_muxes;
-
- const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
- const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
- unsigned int num_caps; /* number of capture volume/switch elements */
-
- struct sigmatel_mic_route ext_mic;
- struct sigmatel_mic_route int_mic;
- struct sigmatel_mic_route dock_mic;
-
- const char * const *spdif_labels;
-
- hda_nid_t dig_in_nid;
- hda_nid_t mono_nid;
+ unsigned int active_adcs;
+
+ /* beep widgets */
hda_nid_t anabeep_nid;
hda_nid_t digbeep_nid;
-
- /* pin widgets */
- const hda_nid_t *pin_nids;
- unsigned int num_pins;
-
- /* codec specific stuff */
- const struct hda_verb *init;
- const struct snd_kcontrol_new *mixer;
-
- /* capture source */
- struct hda_input_mux *dinput_mux;
- unsigned int cur_dmux[2];
- struct hda_input_mux *input_mux;
- unsigned int cur_mux[3];
- struct hda_input_mux *sinput_mux;
- unsigned int cur_smux[2];
- unsigned int cur_amux;
- hda_nid_t *amp_nids;
- unsigned int powerdown_adcs;
-
- /* i/o switches */
- unsigned int io_switch[2];
- unsigned int clfe_swap;
- hda_nid_t line_switch; /* shared line-in for input and output */
- hda_nid_t mic_switch; /* shared mic-in for input and output */
- hda_nid_t hp_switch; /* NID of HP as line-out */
- unsigned int aloopback;
-
- struct hda_pcm pcm_rec[2]; /* PCM information */
-
- /* dynamic controls and input_mux */
- struct auto_pin_cfg autocfg;
- struct snd_array kctls;
- struct hda_input_mux private_dimux;
- struct hda_input_mux private_imux;
- struct hda_input_mux private_smux;
- struct hda_input_mux private_mono_mux;
-
- /* auto spec */
- unsigned auto_pin_cnt;
- hda_nid_t auto_pin_nids[MAX_PINS_NUM];
- unsigned auto_adc_cnt;
- hda_nid_t auto_adc_nids[MAX_ADCS_NUM];
- hda_nid_t auto_mux_nids[MAX_ADCS_NUM];
- hda_nid_t auto_dmux_nids[MAX_ADCS_NUM];
- unsigned long auto_capvols[MAX_ADCS_NUM];
- unsigned auto_dmic_cnt;
- hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
-
- struct hda_vmaster_mute_hook vmaster_mute;
};
#define AC_VERB_IDT_SET_POWER_MAP 0x7ec
#define AC_VERB_IDT_GET_POWER_MAP 0xfec
-static const hda_nid_t stac9200_adc_nids[1] = {
- 0x03,
-};
-
-static const hda_nid_t stac9200_mux_nids[1] = {
- 0x0c,
-};
-
-static const hda_nid_t stac9200_dac_nids[1] = {
- 0x02,
-};
-
static const hda_nid_t stac92hd73xx_pwr_nids[8] = {
0x0a, 0x0b, 0x0c, 0xd, 0x0e,
0x0f, 0x10, 0x11
};
-static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
- 0x26, 0,
-};
-
-static const hda_nid_t stac92hd73xx_adc_nids[2] = {
- 0x1a, 0x1b
-};
-
-#define STAC92HD73XX_NUM_DMICS 2
-static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
- 0x13, 0x14, 0
-};
-
-#define STAC92HD73_DAC_COUNT 5
-
-static const hda_nid_t stac92hd73xx_mux_nids[2] = {
- 0x20, 0x21,
-};
-
-static const hda_nid_t stac92hd73xx_dmux_nids[2] = {
- 0x20, 0x21,
-};
-
-static const hda_nid_t stac92hd73xx_smux_nids[2] = {
- 0x22, 0x23,
-};
-
-#define STAC92HD73XX_NUM_CAPS 2
-static const unsigned long stac92hd73xx_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-};
-#define stac92hd73xx_capsws stac92hd73xx_capvols
-
-#define STAC92HD83_DAC_COUNT 3
-
static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
0x0a, 0x0b, 0x0c, 0xd, 0x0e,
0x0f, 0x10
};
-static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
- 0x1e, 0,
-};
-
-static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
- 0x11, 0x20,
-};
-
static const hda_nid_t stac92hd71bxx_pwr_nids[3] = {
0x0a, 0x0d, 0x0f
};
-static const hda_nid_t stac92hd71bxx_adc_nids[2] = {
- 0x12, 0x13,
-};
-
-static const hda_nid_t stac92hd71bxx_mux_nids[2] = {
- 0x1a, 0x1b
-};
-
-static const hda_nid_t stac92hd71bxx_dmux_nids[2] = {
- 0x1c, 0x1d,
-};
-
-static const hda_nid_t stac92hd71bxx_smux_nids[2] = {
- 0x24, 0x25,
-};
-
-#define STAC92HD71BXX_NUM_DMICS 2
-static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
- 0x18, 0x19, 0
-};
-
-static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = {
- 0x18, 0
-};
-
-static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
- 0x22, 0
-};
-
-#define STAC92HD71BXX_NUM_CAPS 2
-static const unsigned long stac92hd71bxx_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
-};
-#define stac92hd71bxx_capsws stac92hd71bxx_capvols
-
-static const hda_nid_t stac925x_adc_nids[1] = {
- 0x03,
-};
-
-static const hda_nid_t stac925x_mux_nids[1] = {
- 0x0f,
-};
-
-static const hda_nid_t stac925x_dac_nids[1] = {
- 0x02,
-};
-
-#define STAC925X_NUM_DMICS 1
-static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
- 0x15, 0
-};
-
-static const hda_nid_t stac925x_dmux_nids[1] = {
- 0x14,
-};
-
-static const unsigned long stac925x_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
-};
-static const unsigned long stac925x_capsws[] = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
-};
-
-static const hda_nid_t stac922x_adc_nids[2] = {
- 0x06, 0x07,
-};
-
-static const hda_nid_t stac922x_mux_nids[2] = {
- 0x12, 0x13,
-};
-
-#define STAC922X_NUM_CAPS 2
-static const unsigned long stac922x_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
-};
-#define stac922x_capsws stac922x_capvols
-
-static const hda_nid_t stac927x_slave_dig_outs[2] = {
- 0x1f, 0,
-};
-
-static const hda_nid_t stac927x_adc_nids[3] = {
- 0x07, 0x08, 0x09
-};
-
-static const hda_nid_t stac927x_mux_nids[3] = {
- 0x15, 0x16, 0x17
-};
-
-static const hda_nid_t stac927x_smux_nids[1] = {
- 0x21,
-};
-
-static const hda_nid_t stac927x_dac_nids[6] = {
- 0x02, 0x03, 0x04, 0x05, 0x06, 0
-};
-
-static const hda_nid_t stac927x_dmux_nids[1] = {
- 0x1b,
-};
-
-#define STAC927X_NUM_DMICS 2
-static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
- 0x13, 0x14, 0
-};
-
-#define STAC927X_NUM_CAPS 3
-static const unsigned long stac927x_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
-};
-static const unsigned long stac927x_capsws[] = {
- HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
-};
-
-static const char * const stac927x_spdif_labels[5] = {
- "Digital Playback", "ADAT", "Analog Mux 1",
- "Analog Mux 2", "Analog Mux 3"
-};
-
-static const hda_nid_t stac9205_adc_nids[2] = {
- 0x12, 0x13
-};
-
-static const hda_nid_t stac9205_mux_nids[2] = {
- 0x19, 0x1a
-};
-
-static const hda_nid_t stac9205_dmux_nids[1] = {
- 0x1d,
-};
-
-static const hda_nid_t stac9205_smux_nids[1] = {
- 0x21,
-};
-
-#define STAC9205_NUM_DMICS 2
-static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
- 0x17, 0x18, 0
-};
-
-#define STAC9205_NUM_CAPS 2
-static const unsigned long stac9205_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
-};
-static const unsigned long stac9205_capsws[] = {
- HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
-};
-
-static const hda_nid_t stac9200_pin_nids[8] = {
- 0x08, 0x09, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x12,
-};
-
-static const hda_nid_t stac925x_pin_nids[8] = {
- 0x07, 0x08, 0x0a, 0x0b,
- 0x0c, 0x0d, 0x10, 0x11,
-};
-
-static const hda_nid_t stac922x_pin_nids[10] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x15, 0x1b,
-};
-
-static const hda_nid_t stac92hd73xx_pin_nids[13] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x12, 0x13,
- 0x14, 0x22, 0x23
-};
-
-#define STAC92HD71BXX_NUM_PINS 13
-static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x00,
- 0x00, 0x14, 0x18, 0x19, 0x1e,
- 0x1f, 0x20, 0x27
-};
-static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x14, 0x18, 0x19, 0x1e,
- 0x1f, 0x20, 0x27
-};
-
-static const hda_nid_t stac927x_pin_nids[14] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x12, 0x13,
- 0x14, 0x21, 0x22, 0x23,
-};
-
-static const hda_nid_t stac9205_pin_nids[12] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x14, 0x16, 0x17, 0x18,
- 0x21, 0x22,
-};
-static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
- unsigned char type, int data);
-static int stac_add_hp_bass_switch(struct hda_codec *codec);
-static void stac92xx_auto_set_pinctl(struct hda_codec *codec,
- hda_nid_t nid, int pin_type);
-static int hp_bnb2011_with_dock(struct hda_codec *codec);
-static int hp_blike_system(u32 subsystem_id);
-static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity);
-
-static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+/*
+ * PCM hooks
+ */
+static void stac_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
+ if (action == HDA_GEN_PCM_ACT_OPEN && spec->stream_delay)
+ msleep(spec->stream_delay);
}
-static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void stac_capture_pcm_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ int i, idx = 0;
- ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
- return 0;
-}
+ if (!spec->powerdown_adcs)
+ return;
-static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ for (i = 0; i < spec->gen.num_all_adcs; i++) {
+ if (spec->gen.all_adcs[i] == hinfo->nid) {
+ idx = i;
+ break;
+ }
+ }
- return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
- spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
+ switch (action) {
+ case HDA_GEN_PCM_ACT_OPEN:
+ msleep(40);
+ snd_hda_codec_write(codec, hinfo->nid, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ spec->active_adcs |= (1 << idx);
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
+ snd_hda_codec_write(codec, hinfo->nid, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ spec->active_adcs &= ~(1 << idx);
+ break;
+ }
}
-static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
-}
+/*
+ * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
+ * funky external mute control using GPIO pins.
+ */
-static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+ unsigned int dir_mask, unsigned int data)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ unsigned int gpiostate, gpiomask, gpiodir;
- ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
- return 0;
+ snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+
+ gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
+ gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
+
+ gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_MASK, 0);
+ gpiomask |= mask;
+
+ gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DIRECTION, 0);
+ gpiodir |= dir_mask;
+
+ /* Configure GPIOx as CMOS */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
+
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, gpiomask);
+ snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
+
+ msleep(1);
+
+ snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
-static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+/* hook for controlling mic-mute LED GPIO */
+static void stac_capture_led_hook(struct hda_codec *codec, bool enable)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- struct hda_input_mux *smux = &spec->private_smux;
- unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- int err, val;
- hda_nid_t nid;
-
- err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
- spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
- if (err < 0)
- return err;
+ bool mute = !enable;
- if (spec->spdif_mute) {
- if (smux_idx == 0)
- nid = spec->multiout.dig_out_nid;
- else
- nid = codec->slave_dig_outs[smux_idx - 1];
- if (spec->cur_smux[smux_idx] == smux->num_items - 1)
- val = HDA_AMP_MUTE;
+ if (spec->mic_mute_led_on != mute) {
+ spec->mic_mute_led_on = mute;
+ if (mute)
+ spec->gpio_data |= spec->mic_mute_led_gpio;
else
- val = 0;
- /* un/mute SPDIF out */
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, val);
+ spec->gpio_data &= ~spec->mic_mute_led_gpio;
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data);
}
- return 0;
}
static int stac_vrefout_set(struct hda_codec *codec,
@@ -702,141 +355,233 @@ static int stac_vrefout_set(struct hda_codec *codec,
return 1;
}
-static unsigned int stac92xx_vref_set(struct hda_codec *codec,
- hda_nid_t nid, unsigned int new_vref)
-{
- int error;
- unsigned int pincfg;
- pincfg = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-
- pincfg &= 0xff;
- pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
- pincfg |= new_vref;
-
- if (new_vref == AC_PINCTL_VREF_HIZ)
- pincfg |= AC_PINCTL_OUT_EN;
- else
- pincfg |= AC_PINCTL_IN_EN;
-
- error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg);
- if (error < 0)
- return error;
- else
- return 1;
-}
-
-static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
-{
- unsigned int vref;
- vref = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- vref &= AC_PINCTL_VREFEN;
- return vref;
-}
-
-static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+/* update mute-LED accoring to the master switch */
+static void stac_update_led_status(struct hda_codec *codec, int enabled)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->input_mux, uinfo);
-}
+ int muted = !enabled;
-static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (!spec->gpio_led)
+ return;
- ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
- return 0;
-}
+ /* LED state is inverted on these systems */
+ if (spec->gpio_led_polarity)
+ muted = !muted;
-static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- const struct hda_input_mux *imux = spec->input_mux;
- unsigned int idx, prev_idx, didx;
-
- idx = ucontrol->value.enumerated.item[0];
- if (idx >= imux->num_items)
- idx = imux->num_items - 1;
- prev_idx = spec->cur_mux[adc_idx];
- if (prev_idx == idx)
- return 0;
- if (idx < spec->num_analog_muxes) {
- snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0,
- AC_VERB_SET_CONNECT_SEL,
- imux->items[idx].index);
- if (prev_idx >= spec->num_analog_muxes &&
- spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) {
- imux = spec->dinput_mux;
- /* 0 = analog */
- snd_hda_codec_write_cache(codec,
- spec->dmux_nids[adc_idx], 0,
- AC_VERB_SET_CONNECT_SEL,
- imux->items[0].index);
- }
+ if (!spec->vref_mute_led_nid) {
+ if (muted)
+ spec->gpio_data |= spec->gpio_led;
+ else
+ spec->gpio_data &= ~spec->gpio_led;
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data);
} else {
- imux = spec->dinput_mux;
- /* first dimux item is hardcoded to select analog imux,
- * so lets skip it
- */
- didx = idx - spec->num_analog_muxes + 1;
- snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0,
- AC_VERB_SET_CONNECT_SEL,
- imux->items[didx].index);
+ spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
+ stac_vrefout_set(codec, spec->vref_mute_led_nid,
+ spec->vref_led);
}
- spec->cur_mux[adc_idx] = idx;
- return 1;
}
-static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+/* vmaster hook to update mute LED */
+static void stac_vmaster_hook(void *private_data, int val)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->mono_mux, uinfo);
+ stac_update_led_status(private_data, val);
}
-static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+/* automute hook to handle GPIO mute and EAPD updates */
+static void stac_update_outputs(struct hda_codec *codec)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- ucontrol->value.enumerated.item[0] = spec->cur_mmux;
- return 0;
-}
+ if (spec->gpio_mute)
+ spec->gen.master_mute =
+ !(snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
-static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
+ snd_hda_gen_update_outputs(codec);
- return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
- spec->mono_nid, &spec->cur_mmux);
+ if (spec->eapd_mask && spec->eapd_switch) {
+ unsigned int val = spec->gpio_data;
+ if (spec->gen.speaker_muted)
+ val &= ~spec->eapd_mask;
+ else
+ val |= spec->eapd_mask;
+ if (spec->gpio_data != val)
+ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir,
+ val);
+ }
}
-#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
-
-static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
+ bool enable, bool do_write)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct sigmatel_spec *spec = codec->spec;
+ unsigned int idx, val;
- ucontrol->value.integer.value[0] = !!(spec->aloopback &
- (spec->aloopback_mask << idx));
- return 0;
+ for (idx = 0; idx < spec->num_pwrs; idx++) {
+ if (spec->pwr_nids[idx] == nid)
+ break;
+ }
+ if (idx >= spec->num_pwrs)
+ return;
+
+ idx = 1 << idx;
+
+ val = spec->power_map_bits;
+ if (enable)
+ val &= ~idx;
+ else
+ val |= idx;
+
+ /* power down unused output ports */
+ if (val != spec->power_map_bits) {
+ spec->power_map_bits = val;
+ if (do_write)
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_IDT_SET_POWER_MAP, val);
+ }
+}
+
+/* update power bit per jack plug/unplug */
+static void jack_update_power(struct hda_codec *codec,
+ struct hda_jack_tbl *jack)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ if (!spec->num_pwrs)
+ return;
+
+ if (jack && jack->nid) {
+ stac_toggle_power_map(codec, jack->nid,
+ snd_hda_jack_detect(codec, jack->nid),
+ true);
+ return;
+ }
+
+ /* update all jacks */
+ for (i = 0; i < spec->num_pwrs; i++) {
+ hda_nid_t nid = spec->pwr_nids[i];
+ jack = snd_hda_jack_tbl_get(codec, nid);
+ if (!jack || !jack->action)
+ continue;
+ if (jack->action == STAC_PWR_EVENT ||
+ jack->action <= HDA_GEN_LAST_EVENT)
+ stac_toggle_power_map(codec, nid,
+ snd_hda_jack_detect(codec, nid),
+ false);
+ }
+
+ snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP,
+ spec->power_map_bits);
+}
+
+static void stac_hp_automute(struct hda_codec *codec,
+ struct hda_jack_tbl *jack)
+{
+ snd_hda_gen_hp_automute(codec, jack);
+ jack_update_power(codec, jack);
+}
+
+static void stac_line_automute(struct hda_codec *codec,
+ struct hda_jack_tbl *jack)
+{
+ snd_hda_gen_line_automute(codec, jack);
+ jack_update_power(codec, jack);
+}
+
+static void stac_vref_event(struct hda_codec *codec, struct hda_jack_tbl *event)
+{
+ unsigned int data;
+
+ data = snd_hda_codec_read(codec, codec->afg, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
+ /* toggle VREF state based on GPIOx status */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
+ !!(data & (1 << event->private_data)));
+}
+
+/* initialize the power map and enable the power event to jacks that
+ * haven't been assigned to automute
+ */
+static void stac_init_power_map(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_pwrs; i++) {
+ hda_nid_t nid = spec->pwr_nids[i];
+ unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ def_conf = get_defcfg_connect(def_conf);
+ if (snd_hda_jack_tbl_get(codec, nid))
+ continue;
+ if (def_conf == AC_JACK_PORT_COMPLEX &&
+ !(spec->vref_mute_led_nid == nid ||
+ is_jack_detectable(codec, nid))) {
+ snd_hda_jack_detect_enable_callback(codec, nid,
+ STAC_PWR_EVENT,
+ jack_update_power);
+ } else {
+ if (def_conf == AC_JACK_PORT_NONE)
+ stac_toggle_power_map(codec, nid, false, false);
+ else
+ stac_toggle_power_map(codec, nid, true, false);
+ }
+ }
+}
+
+/*
+ */
+
+static inline bool get_int_hint(struct hda_codec *codec, const char *key,
+ int *valp)
+{
+ return !snd_hda_get_int_hint(codec, key, valp);
+}
+
+/* override some hints from the hwdep entry */
+static void stac_store_hints(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int val;
+
+ if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
+ spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
+ spec->gpio_mask;
+ }
+ if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
+ spec->gpio_mask &= spec->gpio_mask;
+ if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
+ spec->gpio_dir &= spec->gpio_mask;
+ if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
+ spec->eapd_mask &= spec->gpio_mask;
+ if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
+ spec->gpio_mute &= spec->gpio_mask;
+ val = snd_hda_get_bool_hint(codec, "eapd_switch");
+ if (val >= 0)
+ spec->eapd_switch = val;
+}
+
+/*
+ * loopback controls
+ */
+
+#define stac_aloopback_info snd_ctl_boolean_mono_info
+
+static int stac_aloopback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct sigmatel_spec *spec = codec->spec;
+
+ ucontrol->value.integer.value[0] = !!(spec->aloopback &
+ (spec->aloopback_mask << idx));
+ return 0;
}
-static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int stac_aloopback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
@@ -875,399 +620,466 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct hda_verb stac9200_core_init[] = {
- /* set dac0mux for dac converter */
- { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {}
-};
-
-static const struct hda_verb stac9200_eapd_init[] = {
- /* set dac0mux for dac converter */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
- {}
-};
-
-static const struct hda_verb dell_eq_core_init[] = {
- /* set master volume to max value without distortion
- * and direct control */
- { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
- {}
-};
-
-static const struct hda_verb stac92hd73xx_core_init[] = {
- /* set master volume and direct control */
- { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- {}
-};
-
-static const struct hda_verb stac92hd83xxx_core_init[] = {
- /* power state controls amps */
- { 0x01, AC_VERB_SET_EAPD, 1 << 2},
- {}
-};
-
-static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
- { 0x22, 0x785, 0x43 },
- { 0x22, 0x782, 0xe0 },
- { 0x22, 0x795, 0x00 },
- {}
-};
-
-static const struct hda_verb stac92hd71bxx_core_init[] = {
- /* set master volume and direct control */
- { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- {}
-};
-
-static const struct hda_verb stac92hd71bxx_unmute_core_init[] = {
- /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
- { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {}
-};
-
-static const struct hda_verb stac925x_core_init[] = {
- /* set dac0mux for dac converter */
- { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* mute the master volume */
- { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- {}
-};
-
-static const struct hda_verb stac922x_core_init[] = {
- /* set master volume and direct control */
- { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- {}
-};
-
-static const struct hda_verb d965_core_init[] = {
- /* unmute node 0x1b */
- { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* select node 0x03 as DAC */
- { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
- {}
-};
-
-static const struct hda_verb dell_3st_core_init[] = {
- /* don't set delta bit */
- {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
- /* unmute node 0x1b */
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* select node 0x03 as DAC */
- {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
- {}
-};
-
-static const struct hda_verb stac927x_core_init[] = {
- /* set master volume and direct control */
- { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* enable analog pc beep path */
- { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
- {}
-};
-
-static const struct hda_verb stac927x_volknob_core_init[] = {
- /* don't set delta bit */
- {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
- /* enable analog pc beep path */
- {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
- {}
-};
-
-static const struct hda_verb stac9205_core_init[] = {
- /* set master volume and direct control */
- { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
- /* enable analog pc beep path */
- { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
- {}
-};
-
-#define STAC_MONO_MUX \
- { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = "Mono Mux", \
- .count = 1, \
- .info = stac92xx_mono_mux_enum_info, \
- .get = stac92xx_mono_mux_enum_get, \
- .put = stac92xx_mono_mux_enum_put, \
- }
-
#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = "Analog Loopback", \
.count = cnt, \
- .info = stac92xx_aloopback_info, \
- .get = stac92xx_aloopback_get, \
- .put = stac92xx_aloopback_put, \
+ .info = stac_aloopback_info, \
+ .get = stac_aloopback_get, \
+ .put = stac_aloopback_put, \
.private_value = verb_read | (verb_write << 16), \
}
-#define DC_BIAS(xname, idx, nid) \
- { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = idx, \
- .info = stac92xx_dc_bias_info, \
- .get = stac92xx_dc_bias_get, \
- .put = stac92xx_dc_bias_put, \
- .private_value = nid, \
- }
+/*
+ * Mute LED handling on HP laptops
+ */
-static const struct snd_kcontrol_new stac9200_mixer[] = {
- HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
- { } /* end */
-};
+/* check whether it's a HP laptop with a docking port */
+static bool hp_bnb2011_with_dock(struct hda_codec *codec)
+{
+ if (codec->vendor_id != 0x111d7605 &&
+ codec->vendor_id != 0x111d76d1)
+ return false;
-static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
- {}
-};
+ switch (codec->subsystem_id) {
+ case 0x103c1618:
+ case 0x103c1619:
+ case 0x103c161a:
+ case 0x103c161b:
+ case 0x103c161c:
+ case 0x103c161d:
+ case 0x103c161e:
+ case 0x103c161f:
-static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
- {}
-};
+ case 0x103c162a:
+ case 0x103c162b:
-static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
- {}
-};
+ case 0x103c1630:
+ case 0x103c1631:
+ case 0x103c1633:
+ case 0x103c1634:
+ case 0x103c1635:
-static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
-};
+ case 0x103c3587:
+ case 0x103c3588:
+ case 0x103c3589:
+ case 0x103c358a:
-static const struct snd_kcontrol_new stac925x_mixer[] = {
- HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT),
- { } /* end */
-};
+ case 0x103c3667:
+ case 0x103c3668:
+ case 0x103c3669:
-static const struct snd_kcontrol_new stac9205_loopback[] = {
- STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
- {}
-};
-
-static const struct snd_kcontrol_new stac927x_loopback[] = {
- STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
- {}
-};
-
-static struct snd_kcontrol_new stac_dmux_mixer = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Digital Input Source",
- /* count set later */
- .info = stac92xx_dmux_enum_info,
- .get = stac92xx_dmux_enum_get,
- .put = stac92xx_dmux_enum_put,
-};
+ return true;
+ }
+ return false;
+}
-static struct snd_kcontrol_new stac_smux_mixer = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Playback Source",
- /* count set later */
- .info = stac92xx_smux_enum_info,
- .get = stac92xx_smux_enum_get,
- .put = stac92xx_smux_enum_put,
-};
+static bool hp_blike_system(u32 subsystem_id)
+{
+ switch (subsystem_id) {
+ case 0x103c1520:
+ case 0x103c1521:
+ case 0x103c1523:
+ case 0x103c1524:
+ case 0x103c1525:
+ case 0x103c1722:
+ case 0x103c1723:
+ case 0x103c1724:
+ case 0x103c1725:
+ case 0x103c1726:
+ case 0x103c1727:
+ case 0x103c1728:
+ case 0x103c1729:
+ case 0x103c172a:
+ case 0x103c172b:
+ case 0x103c307e:
+ case 0x103c307f:
+ case 0x103c3080:
+ case 0x103c3081:
+ case 0x103c7007:
+ case 0x103c7008:
+ return true;
+ }
+ return false;
+}
-static const char * const slave_pfxs[] = {
- "Front", "Surround", "Center", "LFE", "Side",
- "Headphone", "Speaker", "Bass Speaker", "IEC958", "PCM",
- NULL
-};
+static void set_hp_led_gpio(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ unsigned int gpio;
-static void stac92xx_update_led_status(struct hda_codec *codec, int enabled);
+ if (spec->gpio_led)
+ return;
-static void stac92xx_vmaster_hook(void *private_data, int val)
-{
- stac92xx_update_led_status(private_data, val);
+ gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+ gpio &= AC_GPIO_IO_COUNT;
+ if (gpio > 3)
+ spec->gpio_led = 0x08; /* GPIO 3 */
+ else
+ spec->gpio_led = 0x01; /* GPIO 0 */
}
-static void stac92xx_free_kctls(struct hda_codec *codec);
-
-static int stac92xx_build_controls(struct hda_codec *codec)
+/*
+ * This method searches for the mute LED GPIO configuration
+ * provided as OEM string in SMBIOS. The format of that string
+ * is HP_Mute_LED_P_G or HP_Mute_LED_P
+ * where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
+ * that corresponds to the NOT muted state of the master volume
+ * and G is the index of the GPIO to use as the mute LED control (0..9)
+ * If _G portion is missing it is assigned based on the codec ID
+ *
+ * So, HP B-series like systems may have HP_Mute_LED_0 (current models)
+ * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
+ *
+ *
+ * The dv-series laptops don't seem to have the HP_Mute_LED* strings in
+ * SMBIOS - at least the ones I have seen do not have them - which include
+ * my own system (HP Pavilion dv6-1110ax) and my cousin's
+ * HP Pavilion dv9500t CTO.
+ * Need more information on whether it is true across the entire series.
+ * -- kunal
+ */
+static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
{
struct sigmatel_spec *spec = codec->spec;
- unsigned int vmaster_tlv[4];
- int err;
- int i;
+ const struct dmi_device *dev = NULL;
- if (spec->mixer) {
- err = snd_hda_add_new_ctls(codec, spec->mixer);
- if (err < 0)
- return err;
+ if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
+ get_int_hint(codec, "gpio_led_polarity",
+ &spec->gpio_led_polarity);
+ return 1;
}
- for (i = 0; i < spec->num_mixers; i++) {
- err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
- if (err < 0)
- return err;
- }
- if (!spec->auto_mic && spec->num_dmuxes > 0 &&
- snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
- stac_dmux_mixer.count = spec->num_dmuxes;
- err = snd_hda_ctl_add(codec, 0,
- snd_ctl_new1(&stac_dmux_mixer, codec));
- if (err < 0)
- return err;
- }
- if (spec->num_smuxes > 0) {
- int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
- struct hda_input_mux *smux = &spec->private_smux;
- /* check for mute support on SPDIF out */
- if (wcaps & AC_WCAP_OUT_AMP) {
- snd_hda_add_imux_item(smux, "Off", 0, NULL);
- spec->spdif_mute = 1;
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+ if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
+ &spec->gpio_led_polarity,
+ &spec->gpio_led) == 2) {
+ unsigned int max_gpio;
+ max_gpio = snd_hda_param_read(codec, codec->afg,
+ AC_PAR_GPIO_CAP);
+ max_gpio &= AC_GPIO_IO_COUNT;
+ if (spec->gpio_led < max_gpio)
+ spec->gpio_led = 1 << spec->gpio_led;
+ else
+ spec->vref_mute_led_nid = spec->gpio_led;
+ return 1;
+ }
+ if (sscanf(dev->name, "HP_Mute_LED_%d",
+ &spec->gpio_led_polarity) == 1) {
+ set_hp_led_gpio(codec);
+ return 1;
+ }
+ /* BIOS bug: unfilled OEM string */
+ if (strstr(dev->name, "HP_Mute_LED_P_G")) {
+ set_hp_led_gpio(codec);
+ if (default_polarity >= 0)
+ spec->gpio_led_polarity = default_polarity;
+ else
+ spec->gpio_led_polarity = 1;
+ return 1;
}
- stac_smux_mixer.count = spec->num_smuxes;
- err = snd_hda_ctl_add(codec, 0,
- snd_ctl_new1(&stac_smux_mixer, codec));
- if (err < 0)
- return err;
}
- if (spec->multiout.dig_out_nid) {
- err = snd_hda_create_dig_out_ctls(codec,
- spec->multiout.dig_out_nid,
- spec->multiout.dig_out_nid,
- spec->autocfg.dig_out_type[0]);
- if (err < 0)
- return err;
- err = snd_hda_create_spdif_share_sw(codec,
- &spec->multiout);
- if (err < 0)
- return err;
- spec->multiout.share_spdif = 1;
- }
- if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
- err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
- if (err < 0)
- return err;
+ /*
+ * Fallback case - if we don't find the DMI strings,
+ * we statically set the GPIO - if not a B-series system
+ * and default polarity is provided
+ */
+ if (!hp_blike_system(codec->subsystem_id) &&
+ (default_polarity == 0 || default_polarity == 1)) {
+ set_hp_led_gpio(codec);
+ spec->gpio_led_polarity = default_polarity;
+ return 1;
}
+ return 0;
+}
- /* if we have no master control, let's create it */
- snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
- HDA_OUTPUT, vmaster_tlv);
- /* correct volume offset */
- vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
- /* minimum value is actually mute */
- vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
- err = snd_hda_add_vmaster(codec, "Master Playback Volume",
- vmaster_tlv, slave_pfxs,
- "Playback Volume");
- if (err < 0)
- return err;
+/*
+ * PC beep controls
+ */
- err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
- NULL, slave_pfxs,
- "Playback Switch", true,
- &spec->vmaster_mute.sw_kctl);
- if (err < 0)
- return err;
+/* create PC beep volume controls */
+static int stac_auto_create_beep_ctls(struct hda_codec *codec,
+ hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+ struct snd_kcontrol_new *knew;
+ static struct snd_kcontrol_new abeep_mute_ctl =
+ HDA_CODEC_MUTE(NULL, 0, 0, 0);
+ static struct snd_kcontrol_new dbeep_mute_ctl =
+ HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0);
+ static struct snd_kcontrol_new beep_vol_ctl =
+ HDA_CODEC_VOLUME(NULL, 0, 0, 0);
- if (spec->gpio_led) {
- spec->vmaster_mute.hook = stac92xx_vmaster_hook;
- err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
- if (err < 0)
- return err;
+ /* check for mute support for the the amp */
+ if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
+ const struct snd_kcontrol_new *temp;
+ if (spec->anabeep_nid == nid)
+ temp = &abeep_mute_ctl;
+ else
+ temp = &dbeep_mute_ctl;
+ knew = snd_hda_gen_add_kctl(&spec->gen,
+ "Beep Playback Switch", temp);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value =
+ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT);
}
- if (spec->aloopback_ctl &&
- snd_hda_get_bool_hint(codec, "loopback") == 1) {
- err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl);
- if (err < 0)
- return err;
+ /* check to see if there is volume support for the amp */
+ if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+ knew = snd_hda_gen_add_kctl(&spec->gen,
+ "Beep Playback Volume",
+ &beep_vol_ctl);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value =
+ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT);
}
+ return 0;
+}
- stac92xx_free_kctls(codec); /* no longer needed */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define stac_dig_beep_switch_info snd_ctl_boolean_mono_info
- err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
+static int stac_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = codec->beep->enabled;
+ return 0;
+}
- return 0;
+static int stac_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
}
-static const struct hda_pintbl ref9200_pin_configs[] = {
- { 0x08, 0x01c47010 },
- { 0x09, 0x01447010 },
- { 0x0d, 0x0221401f },
- { 0x0e, 0x01114010 },
- { 0x0f, 0x02a19020 },
- { 0x10, 0x01a19021 },
- { 0x11, 0x90100140 },
- { 0x12, 0x01813122 },
- {}
+static const struct snd_kcontrol_new stac_dig_beep_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Beep Playback Switch",
+ .info = stac_dig_beep_switch_info,
+ .get = stac_dig_beep_switch_get,
+ .put = stac_dig_beep_switch_put,
};
-static const struct hda_pintbl gateway9200_m4_pin_configs[] = {
- { 0x08, 0x400000fe },
- { 0x09, 0x404500f4 },
- { 0x0d, 0x400100f0 },
- { 0x0e, 0x90110010 },
- { 0x0f, 0x400100f1 },
- { 0x10, 0x02a1902e },
- { 0x11, 0x500000f2 },
- { 0x12, 0x500000f3 },
+static int stac_beep_switch_ctl(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_dig_beep_ctrl))
+ return -ENOMEM;
+ return 0;
+}
+#endif
+
+/*
+ */
+
+static const struct hda_verb stac9200_core_init[] = {
+ /* set dac0mux for dac converter */
+ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
{}
};
-static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = {
- { 0x08, 0x400000fe },
- { 0x09, 0x404500f4 },
- { 0x0d, 0x400100f0 },
- { 0x0e, 0x90110010 },
- { 0x0f, 0x400100f1 },
- { 0x10, 0x02a1902e },
- { 0x11, 0x500000f2 },
- { 0x12, 0x500000f3 },
+static const struct hda_verb stac9200_eapd_init[] = {
+ /* set dac0mux for dac converter */
+ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
{}
};
-/*
- STAC 9200 pin configs for
- 102801A8
- 102801DE
- 102801E8
-*/
-static const struct hda_pintbl dell9200_d21_pin_configs[] = {
- { 0x08, 0x400001f0 },
- { 0x09, 0x400001f1 },
- { 0x0d, 0x02214030 },
- { 0x0e, 0x01014010 },
- { 0x0f, 0x02a19020 },
- { 0x10, 0x01a19021 },
- { 0x11, 0x90100140 },
- { 0x12, 0x01813122 },
+static const struct hda_verb dell_eq_core_init[] = {
+ /* set master volume to max value without distortion
+ * and direct control */
+ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
{}
};
-/*
- STAC 9200 pin configs for
- 102801C0
- 102801C1
-*/
-static const struct hda_pintbl dell9200_d22_pin_configs[] = {
- { 0x08, 0x400001f0 },
- { 0x09, 0x400001f1 },
- { 0x0d, 0x0221401f },
- { 0x0e, 0x01014010 },
- { 0x0f, 0x01813020 },
- { 0x10, 0x02a19021 },
- { 0x11, 0x90100140 },
- { 0x12, 0x400001f2 },
+static const struct hda_verb stac92hd73xx_core_init[] = {
+ /* set master volume and direct control */
+ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
{}
};
-/*
+static const struct hda_verb stac92hd83xxx_core_init[] = {
+ /* power state controls amps */
+ { 0x01, AC_VERB_SET_EAPD, 1 << 2},
+ {}
+};
+
+static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
+ { 0x22, 0x785, 0x43 },
+ { 0x22, 0x782, 0xe0 },
+ { 0x22, 0x795, 0x00 },
+ {}
+};
+
+static const struct hda_verb stac92hd71bxx_core_init[] = {
+ /* set master volume and direct control */
+ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ {}
+};
+
+static const struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+ /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
+ { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {}
+};
+
+static const struct hda_verb stac925x_core_init[] = {
+ /* set dac0mux for dac converter */
+ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* mute the master volume */
+ { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ {}
+};
+
+static const struct hda_verb stac922x_core_init[] = {
+ /* set master volume and direct control */
+ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ {}
+};
+
+static const struct hda_verb d965_core_init[] = {
+ /* unmute node 0x1b */
+ { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ /* select node 0x03 as DAC */
+ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {}
+};
+
+static const struct hda_verb dell_3st_core_init[] = {
+ /* don't set delta bit */
+ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+ /* unmute node 0x1b */
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ /* select node 0x03 as DAC */
+ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {}
+};
+
+static const struct hda_verb stac927x_core_init[] = {
+ /* set master volume and direct control */
+ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ /* enable analog pc beep path */
+ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+ {}
+};
+
+static const struct hda_verb stac927x_volknob_core_init[] = {
+ /* don't set delta bit */
+ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+ /* enable analog pc beep path */
+ {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+ {}
+};
+
+static const struct hda_verb stac9205_core_init[] = {
+ /* set master volume and direct control */
+ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+ /* enable analog pc beep path */
+ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+ {}
+};
+
+static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback =
+ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3);
+
+static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback =
+ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4);
+
+static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback =
+ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5);
+
+static const struct snd_kcontrol_new stac92hd71bxx_loopback =
+ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2);
+
+static const struct snd_kcontrol_new stac9205_loopback =
+ STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1);
+
+static const struct snd_kcontrol_new stac927x_loopback =
+ STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1);
+
+static const struct hda_pintbl ref9200_pin_configs[] = {
+ { 0x08, 0x01c47010 },
+ { 0x09, 0x01447010 },
+ { 0x0d, 0x0221401f },
+ { 0x0e, 0x01114010 },
+ { 0x0f, 0x02a19020 },
+ { 0x10, 0x01a19021 },
+ { 0x11, 0x90100140 },
+ { 0x12, 0x01813122 },
+ {}
+};
+
+static const struct hda_pintbl gateway9200_m4_pin_configs[] = {
+ { 0x08, 0x400000fe },
+ { 0x09, 0x404500f4 },
+ { 0x0d, 0x400100f0 },
+ { 0x0e, 0x90110010 },
+ { 0x0f, 0x400100f1 },
+ { 0x10, 0x02a1902e },
+ { 0x11, 0x500000f2 },
+ { 0x12, 0x500000f3 },
+ {}
+};
+
+static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = {
+ { 0x08, 0x400000fe },
+ { 0x09, 0x404500f4 },
+ { 0x0d, 0x400100f0 },
+ { 0x0e, 0x90110010 },
+ { 0x0f, 0x400100f1 },
+ { 0x10, 0x02a1902e },
+ { 0x11, 0x500000f2 },
+ { 0x12, 0x500000f3 },
+ {}
+};
+
+/*
+ STAC 9200 pin configs for
+ 102801A8
+ 102801DE
+ 102801E8
+*/
+static const struct hda_pintbl dell9200_d21_pin_configs[] = {
+ { 0x08, 0x400001f0 },
+ { 0x09, 0x400001f1 },
+ { 0x0d, 0x02214030 },
+ { 0x0e, 0x01014010 },
+ { 0x0f, 0x02a19020 },
+ { 0x10, 0x01a19021 },
+ { 0x11, 0x90100140 },
+ { 0x12, 0x01813122 },
+ {}
+};
+
+/*
+ STAC 9200 pin configs for
+ 102801C0
+ 102801C1
+*/
+static const struct hda_pintbl dell9200_d22_pin_configs[] = {
+ { 0x08, 0x400001f0 },
+ { 0x09, 0x400001f1 },
+ { 0x0d, 0x0221401f },
+ { 0x0e, 0x01014010 },
+ { 0x0f, 0x01813020 },
+ { 0x10, 0x02a19021 },
+ { 0x11, 0x90100140 },
+ { 0x12, 0x400001f2 },
+ {}
+};
+
+/*
STAC 9200 pin configs for
102801C4 (Dell Dimension E310)
102801C5
@@ -1431,17 +1243,13 @@ static void stac9200_fixup_panasonic(struct hda_codec *codec,
{
struct sigmatel_spec *spec = codec->spec;
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->gpio_mask = spec->gpio_dir = 0x09;
spec->gpio_data = 0x00;
- break;
- case HDA_FIXUP_ACT_PROBE:
/* CF-74 has no headphone detection, and the driver should *NOT*
* do detection and HP/speaker toggle because the hardware does it.
*/
- spec->hp_detect = 0;
- break;
+ spec->gen.suppress_auto_mute = 1;
}
}
@@ -1862,7 +1670,6 @@ static void stac92hd73xx_fixup_dell(struct hda_codec *codec)
struct sigmatel_spec *spec = codec->spec;
snd_hda_apply_pincfgs(codec, dell_m6_pin_configs);
- spec->num_smuxes = 0;
spec->eapd_switch = 0;
}
@@ -1883,43 +1690,34 @@ static void stac92hd73xx_fixup_dell_eq(struct hda_codec *codec,
static void stac92hd73xx_fixup_dell_m6_amic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct sigmatel_spec *spec = codec->spec;
-
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
stac92hd73xx_fixup_dell(codec);
snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
- spec->num_dmics = 0;
}
/* Digital Mics */
static void stac92hd73xx_fixup_dell_m6_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct sigmatel_spec *spec = codec->spec;
-
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
stac92hd73xx_fixup_dell(codec);
snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
- spec->num_dmics = 1;
}
/* Both */
static void stac92hd73xx_fixup_dell_m6_both(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct sigmatel_spec *spec = codec->spec;
-
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
stac92hd73xx_fixup_dell(codec);
snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
- spec->num_dmics = 1;
}
static void stac92hd73xx_fixup_alienware_m17x(struct hda_codec *codec,
@@ -1931,19 +1729,14 @@ static void stac92hd73xx_fixup_alienware_m17x(struct hda_codec *codec,
return;
snd_hda_apply_pincfgs(codec, alienware_m17x_pin_configs);
- spec->num_dmics = STAC92HD73XX_NUM_DMICS;
- spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
spec->eapd_switch = 0;
}
static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct sigmatel_spec *spec = codec->spec;
-
- if (action != HDA_FIXUP_ACT_PROBE)
- return;
- spec->hp_detect = 0;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ codec->no_jack_detect = 1;
}
static const struct hda_fixup stac92hd73xx_fixups[] = {
@@ -2348,6 +2141,54 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
{} /* terminator */
};
+/* HP dv7 bass switch - GPIO5 */
+#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
+static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
+ return 0;
+}
+
+static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ unsigned int gpio_data;
+
+ gpio_data = (spec->gpio_data & ~0x20) |
+ (ucontrol->value.integer.value[0] ? 0x20 : 0);
+ if (gpio_data == spec->gpio_data)
+ return 0;
+ spec->gpio_data = gpio_data;
+ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+ return 1;
+}
+
+static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = stac_hp_bass_gpio_info,
+ .get = stac_hp_bass_gpio_get,
+ .put = stac_hp_bass_gpio_put,
+};
+
+static int stac_add_hp_bass_switch(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (!snd_hda_gen_add_kctl(&spec->gen, "Bass Speaker Playback Switch",
+ &stac_hp_bass_sw_ctrl))
+ return -ENOMEM;
+
+ spec->gpio_mask |= 0x20;
+ spec->gpio_dir |= 0x20;
+ spec->gpio_data |= 0x20;
+ return 0;
+}
+
static const struct hda_pintbl ref92hd71bxx_pin_configs[] = {
{ 0x0a, 0x02214030 },
{ 0x0b, 0x02a19040 },
@@ -2420,66 +2261,29 @@ static void stac92hd71bxx_fixup_ref(struct hda_codec *codec,
spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0;
}
-static void stac92hd71bxx_fixup_no_dmic(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- spec->num_dmics = 0;
- spec->num_smuxes = 0;
- spec->num_dmuxes = 0;
-}
-
-static void stac92hd71bxx_fixup_no_smux(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- spec->num_dmics = 1;
- spec->num_smuxes = 0;
- spec->num_dmuxes = 1;
-}
-
static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct sigmatel_spec *spec = codec->spec;
+ struct hda_jack_tbl *jack;
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
/* Enable VREF power saving on GPIO1 detect */
- stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x02);
snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
- snd_hda_jack_detect_enable(codec, codec->afg, 0);
+ snd_hda_jack_detect_enable_callback(codec, codec->afg,
+ STAC_VREF_EVENT,
+ stac_vref_event);
+ jack = snd_hda_jack_tbl_get(codec, codec->afg);
+ if (jack)
+ jack->private_data = 0x02;
+
spec->gpio_mask |= 0x02;
/* enable internal microphone */
snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
- stac92xx_auto_set_pinctl(codec, 0x0e,
- AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
-
- stac92hd71bxx_fixup_no_dmic(codec, fix, action);
-}
-
-static void stac92hd71bxx_fixup_hp_dv4_1222nr(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (action != HDA_FIXUP_ACT_PRE_PROBE)
- return;
- spec->num_dmics = 1;
- /* I don't know if it needs 1 or 2 smuxes - will wait for
- * bug reports to fix if needed
- */
- spec->num_smuxes = 1;
- spec->num_dmuxes = 1;
}
static void stac92hd71bxx_fixup_hp_dv4(struct hda_codec *codec,
@@ -2495,21 +2299,14 @@ static void stac92hd71bxx_fixup_hp_dv4(struct hda_codec *codec,
static void stac92hd71bxx_fixup_hp_dv5(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct sigmatel_spec *spec = codec->spec;
unsigned int cap;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
- stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
break;
case HDA_FIXUP_ACT_PROBE:
- /* HP dv6 gives the headphone pin as a line-out. Thus we
- * need to set hp_detect flag here to force to enable HP
- * detection.
- */
- spec->hp_detect = 1;
/* enable bass on HP dv7 */
cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
cap &= AC_GPIO_IO_COUNT;
@@ -2527,9 +2324,6 @@ static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec,
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
spec->gpio_led = 0x08;
- spec->num_dmics = 1;
- spec->num_smuxes = 1;
- spec->num_dmuxes = 1;
}
@@ -2559,7 +2353,7 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
}
}
- if (find_mute_led_cfg(codec, spec->default_polarity))
+ if (find_mute_led_cfg(codec, 1))
snd_printd("mute LED gpio %d polarity %d\n",
spec->gpio_led,
spec->gpio_led_polarity);
@@ -2574,20 +2368,14 @@ static const struct hda_fixup stac92hd71bxx_fixups[] = {
[STAC_DELL_M4_1] = {
.type = HDA_FIXUP_PINS,
.v.pins = dell_m4_1_pin_configs,
- .chained = true,
- .chain_id = STAC_92HD71BXX_NO_SMUX,
},
[STAC_DELL_M4_2] = {
.type = HDA_FIXUP_PINS,
.v.pins = dell_m4_2_pin_configs,
- .chained = true,
- .chain_id = STAC_92HD71BXX_NO_DMIC,
},
[STAC_DELL_M4_3] = {
.type = HDA_FIXUP_PINS,
.v.pins = dell_m4_3_pin_configs,
- .chained = true,
- .chain_id = STAC_92HD71BXX_NO_SMUX,
},
[STAC_HP_M4] = {
.type = HDA_FIXUP_FUNC,
@@ -2613,23 +2401,9 @@ static const struct hda_fixup stac92hd71bxx_fixups[] = {
.chained = true,
.chain_id = STAC_92HD71BXX_HP,
},
- [STAC_HP_DV4_1222NR] = {
+ [STAC_92HD71BXX_HP] = {
.type = HDA_FIXUP_FUNC,
- .v.func = stac92hd71bxx_fixup_hp_dv4_1222nr,
- .chained = true,
- .chain_id = STAC_HP_DV4,
- },
- [STAC_92HD71BXX_NO_DMIC] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = stac92hd71bxx_fixup_no_dmic,
- },
- [STAC_92HD71BXX_NO_SMUX] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = stac92hd71bxx_fixup_no_smux,
- },
- [STAC_92HD71BXX_HP] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = stac92hd71bxx_fixup_hp,
+ .v.func = stac92hd71bxx_fixup_hp,
},
};
@@ -2642,7 +2416,7 @@ static const struct hda_model_fixup stac92hd71bxx_models[] = {
{ .id = STAC_HP_DV4, .name = "hp-dv4" },
{ .id = STAC_HP_DV5, .name = "hp-dv5" },
{ .id = STAC_HP_HDX, .name = "hp-hdx" },
- { .id = STAC_HP_DV4_1222NR, .name = "hp-dv4-1222nr" },
+ { .id = STAC_HP_DV4, .name = "hp-dv4-1222nr" },
{}
};
@@ -2652,8 +2426,6 @@ static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = {
"DFI LanParty", STAC_92HD71BXX_REF),
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
"DFI LanParty", STAC_92HD71BXX_REF),
- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
- "HP dv4-1222nr", STAC_HP_DV4_1222NR),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720,
"HP", STAC_HP_DV5),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
@@ -3234,11 +3006,9 @@ static const struct hda_pintbl dell_3st_pin_configs[] = {
static void stac927x_fixup_ref_no_jd(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct sigmatel_spec *spec = codec->spec;
-
/* no jack detecion for ref-no-jd model */
- if (action == HDA_FIXUP_ACT_PROBE)
- spec->hp_detect = 0;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ codec->no_jack_detect = 1;
}
static void stac927x_fixup_ref(struct hda_codec *codec,
@@ -3266,13 +3036,9 @@ static void stac927x_fixup_dell_dmic(struct hda_codec *codec,
spec->eapd_mask = spec->gpio_mask = 0x04;
spec->gpio_dir = spec->gpio_data = 0x04;
}
- spec->dmic_nids = stac927x_dmic_nids;
- spec->num_dmics = STAC927X_NUM_DMICS;
snd_hda_add_verbs(codec, dell_3st_core_init);
spec->volknob_init = 1;
- spec->dmux_nids = stac927x_dmux_nids;
- spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
}
static void stac927x_fixup_volknob(struct hda_codec *codec,
@@ -3511,18 +3277,20 @@ static void stac9205_fixup_dell_m43(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct sigmatel_spec *spec = codec->spec;
- int err;
+ struct hda_jack_tbl *jack;
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
/* Enable unsol response for GPIO4/Dock HP connection */
- err = stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x01);
- if (err < 0)
- return;
snd_hda_codec_write_cache(codec, codec->afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
- snd_hda_jack_detect_enable(codec, codec->afg, 0);
+ snd_hda_jack_detect_enable_callback(codec, codec->afg,
+ STAC_VREF_EVENT,
+ stac_vref_event);
+ jack = snd_hda_jack_tbl_get(codec, codec->afg);
+ if (jack)
+ jack->private_data = 0x01;
spec->gpio_dir = 0x0b;
spec->eapd_mask = 0x01;
@@ -3610,2687 +3378,163 @@ static const struct snd_pci_quirk stac9205_fixup_tbl[] = {
"Dell Precision", STAC_9205_DELL_M43),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
"Dell Precision", STAC_9205_DELL_M43),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
- "Dell Precision", STAC_9205_DELL_M43),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
- "Dell Inspiron", STAC_9205_DELL_M44),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
- "Dell Vostro 1500", STAC_9205_DELL_M42),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0229,
- "Dell Vostro 1700", STAC_9205_DELL_M42),
- /* Gateway */
- SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
- SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
- {} /* terminator */
-};
-
-/*
- * Analog playback callbacks
- */
-static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- if (spec->stream_delay)
- msleep(spec->stream_delay);
- return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
- hinfo);
-}
-
-static int stac92xx_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 sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
-}
-
-static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Digital playback callbacks
- */
-static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int stac92xx_dig_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 sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
- stream_tag, format, substream);
-}
-
-static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-
-/*
- * Analog capture callbacks
- */
-static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = spec->adc_nids[substream->number];
-
- if (spec->powerdown_adcs) {
- msleep(40);
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
- }
- snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
- return 0;
-}
-
-static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = spec->adc_nids[substream->number];
-
- snd_hda_codec_cleanup_stream(codec, nid);
- if (spec->powerdown_adcs)
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
- return 0;
-}
-
-static const struct hda_pcm_stream stac92xx_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in stac92xx_build_pcms */
- .ops = {
- .open = stac92xx_dig_playback_pcm_open,
- .close = stac92xx_dig_playback_pcm_close,
- .prepare = stac92xx_dig_playback_pcm_prepare,
- .cleanup = stac92xx_dig_playback_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream stac92xx_pcm_digital_capture = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in stac92xx_build_pcms */
-};
-
-static const struct hda_pcm_stream stac92xx_pcm_analog_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 8,
- .nid = 0x02, /* NID to query formats and rates */
- .ops = {
- .open = stac92xx_playback_pcm_open,
- .prepare = stac92xx_playback_pcm_prepare,
- .cleanup = stac92xx_playback_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x06, /* NID to query formats and rates */
- .ops = {
- .open = stac92xx_playback_pcm_open,
- .prepare = stac92xx_playback_pcm_prepare,
- .cleanup = stac92xx_playback_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream stac92xx_pcm_analog_capture = {
- .channels_min = 2,
- .channels_max = 2,
- /* NID + .substreams is set in stac92xx_build_pcms */
- .ops = {
- .prepare = stac92xx_capture_pcm_prepare,
- .cleanup = stac92xx_capture_pcm_cleanup
- },
-};
-
-static int stac92xx_build_pcms(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
-
- codec->num_pcms = 1;
- codec->pcm_info = info;
-
- info->name = "STAC92xx Analog";
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
- spec->multiout.dac_nids[0];
- if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
- spec->autocfg.line_outs == 2)
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
- snd_pcm_2_1_chmaps;
-
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
- info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
- info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
-
- if (spec->alt_switch) {
- codec->num_pcms++;
- info++;
- info->name = "STAC92xx Analog Alt";
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
- }
-
- if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
- codec->num_pcms++;
- info++;
- info->name = "STAC92xx Digital";
- info->pcm_type = spec->autocfg.dig_out_type[0];
- if (spec->multiout.dig_out_nid) {
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
- }
- if (spec->dig_in_nid) {
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
- info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
- }
- }
-
- return 0;
-}
-
-static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
-
-{
- snd_hda_set_pin_ctl_cache(codec, nid, pin_type);
-}
-
-#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
-
-static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
-
- ucontrol->value.integer.value[0] = !!spec->hp_switch;
- return 0;
-}
-
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid);
-
-static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- int nid = kcontrol->private_value;
-
- spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
-
- /* check to be sure that the ports are up to date with
- * switch changes
- */
- stac_issue_unsol_event(codec, nid);
-
- return 1;
-}
-
-static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- int i;
- static const char * const texts[] = {
- "Mic In", "Line In", "Line Out"
- };
-
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = kcontrol->private_value;
-
- if (nid == spec->mic_switch || nid == spec->line_switch)
- i = 3;
- else
- i = 2;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = i;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= i)
- uinfo->value.enumerated.item = i-1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
-}
-
-static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value;
- unsigned int vref = stac92xx_vref_get(codec, nid);
-
- if (vref == snd_hda_get_default_vref(codec, nid))
- ucontrol->value.enumerated.item[0] = 0;
- else if (vref == AC_PINCTL_VREF_GRD)
- ucontrol->value.enumerated.item[0] = 1;
- else if (vref == AC_PINCTL_VREF_HIZ)
- ucontrol->value.enumerated.item[0] = 2;
-
- return 0;
-}
-
-static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int new_vref = 0;
- int error;
- hda_nid_t nid = kcontrol->private_value;
-
- if (ucontrol->value.enumerated.item[0] == 0)
- new_vref = snd_hda_get_default_vref(codec, nid);
- else if (ucontrol->value.enumerated.item[0] == 1)
- new_vref = AC_PINCTL_VREF_GRD;
- else if (ucontrol->value.enumerated.item[0] == 2)
- new_vref = AC_PINCTL_VREF_HIZ;
- else
- return 0;
-
- if (new_vref != stac92xx_vref_get(codec, nid)) {
- error = stac92xx_vref_set(codec, nid, new_vref);
- return error;
- }
-
- return 0;
-}
-
-static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- char *texts[2];
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
-
- if (kcontrol->private_value == spec->line_switch)
- texts[0] = "Line In";
- else
- texts[0] = "Mic In";
- texts[1] = "Line Out";
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = 2;
- uinfo->count = 1;
-
- if (uinfo->value.enumerated.item >= 2)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
-}
-
-static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = kcontrol->private_value;
- int io_idx = (nid == spec->mic_switch) ? 1 : 0;
-
- ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
- return 0;
-}
-
-static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = kcontrol->private_value;
- int io_idx = (nid == spec->mic_switch) ? 1 : 0;
- unsigned short val = !!ucontrol->value.enumerated.item[0];
-
- spec->io_switch[io_idx] = val;
-
- if (val)
- stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
- else {
- unsigned int pinctl = AC_PINCTL_IN_EN;
- if (io_idx) /* set VREF for mic */
- pinctl |= snd_hda_get_default_vref(codec, nid);
- stac92xx_auto_set_pinctl(codec, nid, pinctl);
- }
-
- /* check the auto-mute again: we need to mute/unmute the speaker
- * appropriately according to the pin direction
- */
- if (spec->hp_detect)
- stac_issue_unsol_event(codec, nid);
-
- return 1;
-}
-
-#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
-
-static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
-
- ucontrol->value.integer.value[0] = spec->clfe_swap;
- return 0;
-}
-
-static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid = kcontrol->private_value & 0xff;
- unsigned int val = !!ucontrol->value.integer.value[0];
-
- if (spec->clfe_swap == val)
- return 0;
-
- spec->clfe_swap = val;
-
- snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
- spec->clfe_swap ? 0x4 : 0x0);
-
- return 1;
-}
-
-#define STAC_CODEC_HP_SWITCH(xname) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = 0, \
- .info = stac92xx_hp_switch_info, \
- .get = stac92xx_hp_switch_get, \
- .put = stac92xx_hp_switch_put, \
- }
-
-#define STAC_CODEC_IO_SWITCH(xname, xpval) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = 0, \
- .info = stac92xx_io_switch_info, \
- .get = stac92xx_io_switch_get, \
- .put = stac92xx_io_switch_put, \
- .private_value = xpval, \
- }
-
-#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = 0, \
- .info = stac92xx_clfe_switch_info, \
- .get = stac92xx_clfe_switch_get, \
- .put = stac92xx_clfe_switch_put, \
- .private_value = xpval, \
- }
-
-enum {
- STAC_CTL_WIDGET_VOL,
- STAC_CTL_WIDGET_MUTE,
- STAC_CTL_WIDGET_MUTE_BEEP,
- STAC_CTL_WIDGET_MONO_MUX,
- STAC_CTL_WIDGET_HP_SWITCH,
- STAC_CTL_WIDGET_IO_SWITCH,
- STAC_CTL_WIDGET_CLFE_SWITCH,
- STAC_CTL_WIDGET_DC_BIAS
-};
-
-static const struct snd_kcontrol_new stac92xx_control_templates[] = {
- HDA_CODEC_VOLUME(NULL, 0, 0, 0),
- HDA_CODEC_MUTE(NULL, 0, 0, 0),
- HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
- STAC_MONO_MUX,
- STAC_CODEC_HP_SWITCH(NULL),
- STAC_CODEC_IO_SWITCH(NULL, 0),
- STAC_CODEC_CLFE_SWITCH(NULL, 0),
- DC_BIAS(NULL, 0, 0),
-};
-
-/* add dynamic controls */
-static struct snd_kcontrol_new *
-stac_control_new(struct sigmatel_spec *spec,
- const struct snd_kcontrol_new *ktemp,
- const char *name,
- unsigned int subdev)
-{
- struct snd_kcontrol_new *knew;
-
- knew = snd_array_new(&spec->kctls);
- if (!knew)
- return NULL;
- *knew = *ktemp;
- knew->name = kstrdup(name, GFP_KERNEL);
- if (!knew->name) {
- /* roolback */
- memset(knew, 0, sizeof(*knew));
- spec->kctls.alloced--;
- return NULL;
- }
- knew->subdevice = subdev;
- return knew;
-}
-
-static struct snd_kcontrol_new *
-add_control_temp(struct sigmatel_spec *spec,
- const struct snd_kcontrol_new *ktemp,
- int idx, const char *name,
- unsigned long val)
-{
- struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
- HDA_SUBDEV_AMP_FLAG);
- if (!knew)
- return NULL;
- knew->index = idx;
- knew->private_value = val;
- return knew;
-}
-
-static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
- const struct snd_kcontrol_new *ktemp,
- int idx, const char *name,
- unsigned long val)
-{
- return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;
-}
-
-static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
- int type, int idx, const char *name,
- unsigned long val)
-{
- return stac92xx_add_control_temp(spec,
- &stac92xx_control_templates[type],
- idx, name, val);
-}
-
-
-/* add dynamic controls */
-static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
- const char *name, unsigned long val)
-{
- return stac92xx_add_control_idx(spec, type, 0, name, val);
-}
-
-static const struct snd_kcontrol_new stac_input_src_temp = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Input Source",
- .info = stac92xx_mux_enum_info,
- .get = stac92xx_mux_enum_get,
- .put = stac92xx_mux_enum_put,
-};
-
-static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
- hda_nid_t nid, int idx)
-{
- int def_conf = snd_hda_codec_get_pincfg(codec, nid);
- int control = 0;
- struct sigmatel_spec *spec = codec->spec;
- char name[22];
-
- if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
- if (spec->headset_jack && snd_hda_get_input_pin_attr(def_conf)
- != INPUT_PIN_ATTR_DOCK)
- return 0;
- if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
- && nid == spec->line_switch)
- control = STAC_CTL_WIDGET_IO_SWITCH;
- else if (snd_hda_query_pin_caps(codec, nid)
- & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
- control = STAC_CTL_WIDGET_DC_BIAS;
- else if (nid == spec->mic_switch)
- control = STAC_CTL_WIDGET_IO_SWITCH;
- }
-
- if (control) {
- snd_hda_get_pin_label(codec, nid, &spec->autocfg,
- name, sizeof(name), NULL);
- return stac92xx_add_control(codec->spec, control,
- strcat(name, " Jack Mode"), nid);
- }
-
- return 0;
-}
-
-static int stac92xx_add_input_source(struct sigmatel_spec *spec)
-{
- struct snd_kcontrol_new *knew;
- struct hda_input_mux *imux = &spec->private_imux;
-
- if (spec->auto_mic)
- return 0; /* no need for input source */
- if (!spec->num_adcs || imux->num_items <= 1)
- return 0; /* no need for input source control */
- knew = stac_control_new(spec, &stac_input_src_temp,
- stac_input_src_temp.name, 0);
- if (!knew)
- return -ENOMEM;
- knew->count = spec->num_adcs;
- return 0;
-}
-
-/* check whether the line-input can be used as line-out */
-static hda_nid_t check_line_out_switch(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- hda_nid_t nid;
- unsigned int pincap;
- int i;
-
- if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
- return 0;
- for (i = 0; i < cfg->num_inputs; i++) {
- if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
- nid = cfg->inputs[i].pin;
- pincap = snd_hda_query_pin_caps(codec, nid);
- if (pincap & AC_PINCAP_OUT)
- return nid;
- }
- }
- return 0;
-}
-
-static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
-
-/* check whether the mic-input can be used as line-out */
-static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- unsigned int def_conf, pincap;
- int i;
-
- *dac = 0;
- if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
- return 0;
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- if (cfg->inputs[i].type != AUTO_PIN_MIC)
- continue;
- def_conf = snd_hda_codec_get_pincfg(codec, nid);
- /* some laptops have an internal analog microphone
- * which can't be used as a output */
- if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
- pincap = snd_hda_query_pin_caps(codec, nid);
- if (pincap & AC_PINCAP_OUT) {
- *dac = get_unassigned_dac(codec, nid);
- if (*dac)
- return nid;
- }
- }
- }
- return 0;
-}
-
-static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
-{
- int i;
-
- for (i = 0; i < spec->multiout.num_dacs; i++) {
- if (spec->multiout.dac_nids[i] == nid)
- return 1;
- }
-
- return 0;
-}
-
-static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
-{
- int i;
- if (is_in_dac_nids(spec, nid))
- return 1;
- for (i = 0; i < spec->autocfg.hp_outs; i++)
- if (spec->hp_dacs[i] == nid)
- return 1;
- for (i = 0; i < spec->autocfg.speaker_outs; i++)
- if (spec->speaker_dacs[i] == nid)
- return 1;
- return 0;
-}
-
-static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int j, conn_len;
- hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac;
- unsigned int wcaps, wtype;
-
- conn_len = snd_hda_get_connections(codec, nid, conn,
- HDA_MAX_CONNECTIONS);
- /* 92HD88: trace back up the link of nids to find the DAC */
- while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0]))
- != AC_WID_AUD_OUT)) {
- nid = conn[0];
- conn_len = snd_hda_get_connections(codec, nid, conn,
- HDA_MAX_CONNECTIONS);
- }
- for (j = 0; j < conn_len; j++) {
- wcaps = get_wcaps(codec, conn[j]);
- wtype = get_wcaps_type(wcaps);
- /* we check only analog outputs */
- if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
- continue;
- /* if this route has a free DAC, assign it */
- if (!check_all_dac_nids(spec, conn[j])) {
- if (conn_len > 1) {
- /* select this DAC in the pin's input mux */
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, j);
- }
- return conn[j];
- }
- }
-
- /* if all DACs are already assigned, connect to the primary DAC,
- unless we're assigning a secondary headphone */
- fallback_dac = spec->multiout.dac_nids[0];
- if (spec->multiout.hp_nid) {
- for (j = 0; j < cfg->hp_outs; j++)
- if (cfg->hp_pins[j] == nid) {
- fallback_dac = spec->multiout.hp_nid;
- break;
- }
- }
-
- if (conn_len > 1) {
- for (j = 0; j < conn_len; j++) {
- if (conn[j] == fallback_dac) {
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, j);
- break;
- }
- }
- }
- return 0;
-}
-
-static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
-static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
-
-/*
- * Fill in the dac_nids table from the parsed pin configuration
- * This function only works when every pin in line_out_pins[]
- * contains atleast one DAC in its connection list. Some 92xx
- * codecs are not connected directly to a DAC, such as the 9200
- * and 9202/925x. For those, dac_nids[] must be hard-coded.
- */
-static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
- hda_nid_t nid, dac;
-
- for (i = 0; i < cfg->line_outs; i++) {
- nid = cfg->line_out_pins[i];
- dac = get_unassigned_dac(codec, nid);
- if (!dac) {
- if (spec->multiout.num_dacs > 0) {
- /* we have already working output pins,
- * so let's drop the broken ones again
- */
- cfg->line_outs = spec->multiout.num_dacs;
- break;
- }
- /* error out, no available DAC found */
- snd_printk(KERN_ERR
- "%s: No available DAC for pin 0x%x\n",
- __func__, nid);
- return -ENODEV;
- }
- add_spec_dacs(spec, dac);
- }
-
- for (i = 0; i < cfg->hp_outs; i++) {
- nid = cfg->hp_pins[i];
- dac = get_unassigned_dac(codec, nid);
- if (dac) {
- if (!spec->multiout.hp_nid)
- spec->multiout.hp_nid = dac;
- else
- add_spec_extra_dacs(spec, dac);
- }
- spec->hp_dacs[i] = dac;
- }
-
- for (i = 0; i < cfg->speaker_outs; i++) {
- nid = cfg->speaker_pins[i];
- dac = get_unassigned_dac(codec, nid);
- if (dac)
- add_spec_extra_dacs(spec, dac);
- spec->speaker_dacs[i] = dac;
- }
-
- /* add line-in as output */
- nid = check_line_out_switch(codec);
- if (nid) {
- dac = get_unassigned_dac(codec, nid);
- if (dac) {
- snd_printdd("STAC: Add line-in 0x%x as output %d\n",
- nid, cfg->line_outs);
- cfg->line_out_pins[cfg->line_outs] = nid;
- cfg->line_outs++;
- spec->line_switch = nid;
- add_spec_dacs(spec, dac);
- }
- }
- /* add mic as output */
- nid = check_mic_out_switch(codec, &dac);
- if (nid && dac) {
- snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
- nid, cfg->line_outs);
- cfg->line_out_pins[cfg->line_outs] = nid;
- cfg->line_outs++;
- spec->mic_switch = nid;
- add_spec_dacs(spec, dac);
- }
-
- snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
- spec->multiout.num_dacs,
- spec->multiout.dac_nids[0],
- spec->multiout.dac_nids[1],
- spec->multiout.dac_nids[2],
- spec->multiout.dac_nids[3],
- spec->multiout.dac_nids[4]);
-
- return 0;
-}
-
-/* create volume control/switch for the given prefx type */
-static int create_controls_idx(struct hda_codec *codec, const char *pfx,
- int idx, hda_nid_t nid, int chs)
-{
- struct sigmatel_spec *spec = codec->spec;
- char name[32];
- int err;
-
- if (!spec->check_volume_offset) {
- unsigned int caps, step, nums, db_scale;
- caps = query_amp_caps(codec, nid, HDA_OUTPUT);
- step = (caps & AC_AMPCAP_STEP_SIZE) >>
- AC_AMPCAP_STEP_SIZE_SHIFT;
- step = (step + 1) * 25; /* in .01dB unit */
- nums = (caps & AC_AMPCAP_NUM_STEPS) >>
- AC_AMPCAP_NUM_STEPS_SHIFT;
- db_scale = nums * step;
- /* if dB scale is over -64dB, and finer enough,
- * let's reduce it to half
- */
- if (db_scale > 6400 && nums >= 0x1f)
- spec->volume_offset = nums / 2;
- spec->check_volume_offset = 1;
- }
-
- sprintf(name, "%s Playback Volume", pfx);
- err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name,
- HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
- spec->volume_offset));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", pfx);
- err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name,
- HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- return 0;
-}
-
-#define create_controls(codec, pfx, nid, chs) \
- create_controls_idx(codec, pfx, 0, nid, chs)
-
-static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
-{
- if (spec->multiout.num_dacs > 4) {
- printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
- return 1;
- } else {
- snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids);
- spec->dac_nids[spec->multiout.num_dacs] = nid;
- spec->multiout.num_dacs++;
- }
- return 0;
-}
-
-static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
- if (!spec->multiout.extra_out_nid[i]) {
- spec->multiout.extra_out_nid[i] = nid;
- return 0;
- }
- }
- printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
- return 1;
-}
-
-/* Create output controls
- * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT)
- */
-static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
- const hda_nid_t *pins,
- const hda_nid_t *dac_nids,
- int type)
-{
- struct sigmatel_spec *spec = codec->spec;
- static const char * const chname[4] = {
- "Front", "Surround", NULL /*CLFE*/, "Side"
- };
- hda_nid_t nid;
- int i, err;
- unsigned int wid_caps;
-
- for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
- if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
- if (is_jack_detectable(codec, pins[i]))
- spec->hp_detect = 1;
- }
- nid = dac_nids[i];
- if (!nid)
- continue;
- if (type != AUTO_PIN_HP_OUT && i == 2) {
- /* Center/LFE */
- err = create_controls(codec, "Center", nid, 1);
- if (err < 0)
- return err;
- err = create_controls(codec, "LFE", nid, 2);
- if (err < 0)
- return err;
-
- wid_caps = get_wcaps(codec, nid);
-
- if (wid_caps & AC_WCAP_LR_SWAP) {
- err = stac92xx_add_control(spec,
- STAC_CTL_WIDGET_CLFE_SWITCH,
- "Swap Center/LFE Playback Switch", nid);
-
- if (err < 0)
- return err;
- }
-
- } else {
- const char *name;
- int idx;
- switch (type) {
- case AUTO_PIN_HP_OUT:
- name = "Headphone";
- idx = i;
- break;
- case AUTO_PIN_SPEAKER_OUT:
- if (num_outs <= 2) {
- name = i ? "Bass Speaker" : "Speaker";
- idx = 0;
- break;
- }
- /* Fall through in case of multi speaker outs */
- default:
- name = chname[i];
- idx = 0;
- break;
- }
- err = create_controls_idx(codec, name, idx, nid, 3);
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
- unsigned int dir_mask, unsigned int data);
-
-/* hook for controlling mic-mute LED GPIO */
-static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- int err;
- bool mute;
-
- err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
- if (err <= 0)
- return err;
- mute = !(ucontrol->value.integer.value[0] &&
- ucontrol->value.integer.value[1]);
- if (spec->mic_mute_led_on != mute) {
- spec->mic_mute_led_on = mute;
- if (mute)
- spec->gpio_data |= spec->mic_mute_led_gpio;
- else
- spec->gpio_data &= ~spec->mic_mute_led_gpio;
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data);
- }
- return err;
-}
-
-static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
- unsigned long sw, int idx)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct snd_kcontrol_new *knew;
- int err;
-
- err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
- "Capture Volume", vol);
- if (err < 0)
- return err;
-
- knew = add_control_temp(spec,
- &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE],
- idx, "Capture Switch", sw);
- if (!knew)
- return -ENOMEM;
- /* add a LED hook for some HP laptops */
- if (spec->mic_mute_led_gpio)
- knew->put = stac92xx_capture_sw_put_led;
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t nid;
- int err;
- int idx;
-
- err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
- spec->multiout.dac_nids,
- cfg->line_out_type);
- if (err < 0)
- return err;
-
- if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
- err = stac92xx_add_control(spec,
- STAC_CTL_WIDGET_HP_SWITCH,
- "Headphone as Line Out Switch",
- cfg->hp_pins[cfg->hp_outs - 1]);
- if (err < 0)
- return err;
- }
-
- for (idx = 0; idx < cfg->num_inputs; idx++) {
- if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
- break;
- nid = cfg->inputs[idx].pin;
- err = stac92xx_add_jack_mode_control(codec, nid, idx);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-/* add playback controls for Speaker and HP outputs */
-static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
- struct auto_pin_cfg *cfg)
-{
- struct sigmatel_spec *spec = codec->spec;
- int err;
-
- err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins,
- spec->hp_dacs, AUTO_PIN_HP_OUT);
- if (err < 0)
- return err;
-
- err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins,
- spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-/* labels for mono mux outputs */
-static const char * const stac92xx_mono_labels[4] = {
- "DAC0", "DAC1", "Mixer", "DAC2"
-};
-
-/* create mono mux for mono out on capable codecs */
-static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct hda_input_mux *mono_mux = &spec->private_mono_mux;
- int i, num_cons;
- hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
-
- num_cons = snd_hda_get_connections(codec,
- spec->mono_nid,
- con_lst,
- HDA_MAX_NUM_INPUTS);
- if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
- return -EINVAL;
-
- for (i = 0; i < num_cons; i++)
- snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
- NULL);
-
- return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
- "Mono Mux", spec->mono_nid);
-}
-
-/* create PC beep volume controls */
-static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
- hda_nid_t nid)
-{
- struct sigmatel_spec *spec = codec->spec;
- u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
- int err, type = STAC_CTL_WIDGET_MUTE_BEEP;
-
- if (spec->anabeep_nid == nid)
- type = STAC_CTL_WIDGET_MUTE;
-
- /* check for mute support for the the amp */
- if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
- err = stac92xx_add_control(spec, type,
- "Beep Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- }
-
- /* check to see if there is volume support for the amp */
- if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
- "Beep Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
-
-static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = codec->beep->enabled;
- return 0;
-}
-
-static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
-}
-
-static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = stac92xx_dig_beep_switch_info,
- .get = stac92xx_dig_beep_switch_get,
- .put = stac92xx_dig_beep_switch_put,
-};
-
-static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
-{
- return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
- 0, "Beep Playback Switch", 0);
-}
-#endif
-
-static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int i, j, err = 0;
-
- for (i = 0; i < spec->num_muxes; i++) {
- hda_nid_t nid;
- unsigned int wcaps;
- unsigned long val;
-
- nid = spec->mux_nids[i];
- wcaps = get_wcaps(codec, nid);
- if (!(wcaps & AC_WCAP_OUT_AMP))
- continue;
-
- /* check whether already the same control was created as
- * normal Capture Volume.
- */
- val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- for (j = 0; j < spec->num_caps; j++) {
- if (spec->capvols[j] == val)
- break;
- }
- if (j < spec->num_caps)
- continue;
-
- err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i,
- "Mux Capture Volume", val);
- if (err < 0)
- return err;
- }
- return 0;
-};
-
-static const char * const stac92xx_spdif_labels[3] = {
- "Digital Playback", "Analog Mux 1", "Analog Mux 2",
-};
-
-static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct hda_input_mux *spdif_mux = &spec->private_smux;
- const char * const *labels = spec->spdif_labels;
- int i, num_cons;
- hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
-
- num_cons = snd_hda_get_connections(codec,
- spec->smux_nids[0],
- con_lst,
- HDA_MAX_NUM_INPUTS);
- if (num_cons <= 0)
- return -EINVAL;
-
- if (!labels)
- labels = stac92xx_spdif_labels;
-
- for (i = 0; i < num_cons; i++)
- snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
-
- return 0;
-}
-
-/* labels for dmic mux inputs */
-static const char * const stac92xx_dmic_labels[5] = {
- "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
- "Digital Mic 3", "Digital Mic 4"
-};
-
-static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
- int idx)
-{
- hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int nums;
- nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
- if (idx >= 0 && idx < nums)
- return conn[idx];
- return 0;
-}
-
-/* look for NID recursively */
-#define get_connection_index(codec, mux, nid) \
- snd_hda_get_conn_index(codec, mux, nid, 1)
-
-/* create a volume assigned to the given pin (only if supported) */
-/* return 1 if the volume control is created */
-static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
- const char *label, int idx, int direction)
-{
- unsigned int caps, nums;
- char name[32];
- int err;
-
- if (direction == HDA_OUTPUT)
- caps = AC_WCAP_OUT_AMP;
- else
- caps = AC_WCAP_IN_AMP;
- if (!(get_wcaps(codec, nid) & caps))
- return 0;
- caps = query_amp_caps(codec, nid, direction);
- nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
- if (!nums)
- return 0;
- snprintf(name, sizeof(name), "%s Capture Volume", label);
- err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
- if (err < 0)
- return err;
- return 1;
-}
-
-/* create playback/capture controls for input pins on dmic capable codecs */
-static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct hda_input_mux *imux = &spec->private_imux;
- struct hda_input_mux *dimux = &spec->private_dimux;
- int err, i;
- unsigned int def_conf;
-
- snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
-
- for (i = 0; i < spec->num_dmics; i++) {
- hda_nid_t nid;
- int index, type_idx;
- char label[32];
-
- nid = spec->dmic_nids[i];
- if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
- continue;
- def_conf = snd_hda_codec_get_pincfg(codec, nid);
- if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
- continue;
-
- index = get_connection_index(codec, spec->dmux_nids[0], nid);
- if (index < 0)
- continue;
-
- snd_hda_get_pin_label(codec, nid, &spec->autocfg,
- label, sizeof(label), NULL);
- snd_hda_add_imux_item(dimux, label, index, &type_idx);
- if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
- snd_hda_add_imux_item(imux, label, index, &type_idx);
-
- err = create_elem_capture_vol(codec, nid, label, type_idx,
- HDA_INPUT);
- if (err < 0)
- return err;
- if (!err) {
- err = create_elem_capture_vol(codec, nid, label,
- type_idx, HDA_OUTPUT);
- if (err < 0)
- return err;
- if (!err) {
- nid = get_connected_node(codec,
- spec->dmux_nids[0], index);
- if (nid)
- err = create_elem_capture_vol(codec,
- nid, label,
- type_idx, HDA_INPUT);
- if (err < 0)
- return err;
- }
- }
- }
-
- return 0;
-}
-
-static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
-{
- unsigned int cfg;
- unsigned int type;
-
- if (!nid)
- return 0;
- cfg = snd_hda_codec_get_pincfg(codec, nid);
- type = get_defcfg_device(cfg);
- switch (snd_hda_get_input_pin_attr(cfg)) {
- case INPUT_PIN_ATTR_INT:
- if (*fixed)
- return 1; /* already occupied */
- if (type != AC_JACK_MIC_IN)
- return 1; /* invalid type */
- *fixed = nid;
- break;
- case INPUT_PIN_ATTR_UNUSED:
- break;
- case INPUT_PIN_ATTR_DOCK:
- if (*dock)
- return 1; /* already occupied */
- if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN)
- return 1; /* invalid type */
- *dock = nid;
- break;
- default:
- if (*ext)
- return 1; /* already occupied */
- if (type != AC_JACK_MIC_IN)
- return 1; /* invalid type */
- *ext = nid;
- break;
- }
- return 0;
-}
-
-static int set_mic_route(struct hda_codec *codec,
- struct sigmatel_mic_route *mic,
- hda_nid_t pin)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
-
- mic->pin = pin;
- if (pin == 0)
- return 0;
- for (i = 0; i < cfg->num_inputs; i++) {
- if (pin == cfg->inputs[i].pin)
- break;
- }
- if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
- /* analog pin */
- i = get_connection_index(codec, spec->mux_nids[0], pin);
- if (i < 0)
- return -1;
- mic->mux_idx = i;
- mic->dmux_idx = -1;
- if (spec->dmux_nids)
- mic->dmux_idx = get_connection_index(codec,
- spec->dmux_nids[0],
- spec->mux_nids[0]);
- } else if (spec->dmux_nids) {
- /* digital pin */
- i = get_connection_index(codec, spec->dmux_nids[0], pin);
- if (i < 0)
- return -1;
- mic->dmux_idx = i;
- mic->mux_idx = -1;
- if (spec->mux_nids)
- mic->mux_idx = get_connection_index(codec,
- spec->mux_nids[0],
- spec->dmux_nids[0]);
- }
- return 0;
-}
-
-/* return non-zero if the device is for automatic mic switch */
-static int stac_check_auto_mic(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- hda_nid_t fixed, ext, dock;
- int i;
-
- fixed = ext = dock = 0;
- for (i = 0; i < cfg->num_inputs; i++)
- if (check_mic_pin(codec, cfg->inputs[i].pin,
- &fixed, &ext, &dock))
- return 0;
- for (i = 0; i < spec->num_dmics; i++)
- if (check_mic_pin(codec, spec->dmic_nids[i],
- &fixed, &ext, &dock))
- return 0;
- if (!fixed || (!ext && !dock))
- return 0; /* no input to switch */
- if (!is_jack_detectable(codec, ext))
- return 0; /* no unsol support */
- if (set_mic_route(codec, &spec->ext_mic, ext) ||
- set_mic_route(codec, &spec->int_mic, fixed) ||
- set_mic_route(codec, &spec->dock_mic, dock))
- return 0; /* something is wrong */
- return 1;
-}
-
-/* create playback/capture controls for input pins */
-static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct hda_input_mux *imux = &spec->private_imux;
- int i, j;
- const char *label;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- int index, err, type_idx;
-
- index = -1;
- for (j = 0; j < spec->num_muxes; j++) {
- index = get_connection_index(codec, spec->mux_nids[j],
- nid);
- if (index >= 0)
- break;
- }
- if (index < 0)
- continue;
-
- label = hda_get_autocfg_input_label(codec, cfg, i);
- snd_hda_add_imux_item(imux, label, index, &type_idx);
-
- err = create_elem_capture_vol(codec, nid,
- label, type_idx,
- HDA_INPUT);
- if (err < 0)
- return err;
- }
- spec->num_analog_muxes = imux->num_items;
-
- if (imux->num_items) {
- /*
- * Set the current input for the muxes.
- * The STAC9221 has two input muxes with identical source
- * NID lists. Hopefully this won't get confused.
- */
- for (i = 0; i < spec->num_muxes; i++) {
- snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
- AC_VERB_SET_CONNECT_SEL,
- imux->items[0].index);
- }
- }
-
- return 0;
-}
-
-static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->autocfg.line_outs; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
- }
-}
-
-static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->autocfg.hp_outs; i++) {
- hda_nid_t pin;
- pin = spec->autocfg.hp_pins[i];
- if (pin) /* connect to front */
- stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
- }
- for (i = 0; i < spec->autocfg.speaker_outs; i++) {
- hda_nid_t pin;
- pin = spec->autocfg.speaker_pins[i];
- if (pin) /* connect to front */
- stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
- }
-}
-
-static int is_dual_headphones(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int i, valid_hps;
-
- if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT ||
- spec->autocfg.hp_outs <= 1)
- return 0;
- valid_hps = 0;
- for (i = 0; i < spec->autocfg.hp_outs; i++) {
- hda_nid_t nid = spec->autocfg.hp_pins[i];
- unsigned int cfg = snd_hda_codec_get_pincfg(codec, nid);
- if (get_defcfg_location(cfg) & AC_JACK_LOC_SEPARATE)
- continue;
- valid_hps++;
- }
- return (valid_hps > 1);
-}
-
-
-static int stac92xx_parse_auto_config(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t dig_out = 0, dig_in = 0;
- int hp_swap = 0;
- int i, err;
-
- if ((err = snd_hda_parse_pin_def_config(codec,
- &spec->autocfg,
- spec->dmic_nids)) < 0)
- return err;
- if (! spec->autocfg.line_outs)
- return -EINVAL; /* can't find valid pin config */
-
- /* If we have no real line-out pin and multiple hp-outs, HPs should
- * be set up as multi-channel outputs.
- */
- if (is_dual_headphones(codec)) {
- /* Copy hp_outs to line_outs, backup line_outs in
- * speaker_outs so that the following routines can handle
- * HP pins as primary outputs.
- */
- snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
- memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
- sizeof(spec->autocfg.line_out_pins));
- spec->autocfg.speaker_outs = spec->autocfg.line_outs;
- memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
- sizeof(spec->autocfg.hp_pins));
- spec->autocfg.line_outs = spec->autocfg.hp_outs;
- spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
- spec->autocfg.hp_outs = 0;
- hp_swap = 1;
- }
- if (spec->autocfg.mono_out_pin) {
- int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
- (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
- u32 caps = query_amp_caps(codec,
- spec->autocfg.mono_out_pin, dir);
- hda_nid_t conn_list[1];
-
- /* get the mixer node and then the mono mux if it exists */
- if (snd_hda_get_connections(codec,
- spec->autocfg.mono_out_pin, conn_list, 1) &&
- snd_hda_get_connections(codec, conn_list[0],
- conn_list, 1) > 0) {
-
- int wcaps = get_wcaps(codec, conn_list[0]);
- int wid_type = get_wcaps_type(wcaps);
- /* LR swap check, some stac925x have a mux that
- * changes the DACs output path instead of the
- * mono-mux path.
- */
- if (wid_type == AC_WID_AUD_SEL &&
- !(wcaps & AC_WCAP_LR_SWAP))
- spec->mono_nid = conn_list[0];
- }
- if (dir) {
- hda_nid_t nid = spec->autocfg.mono_out_pin;
-
- /* most mono outs have a least a mute/unmute switch */
- dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
- "Mono Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
- if (err < 0)
- return err;
- /* check for volume support for the amp */
- if ((caps & AC_AMPCAP_NUM_STEPS)
- >> AC_AMPCAP_NUM_STEPS_SHIFT) {
- err = stac92xx_add_control(spec,
- STAC_CTL_WIDGET_VOL,
- "Mono Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
- if (err < 0)
- return err;
- }
- }
-
- stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
- AC_PINCTL_OUT_EN);
- }
-
- if (!spec->multiout.num_dacs) {
- err = stac92xx_auto_fill_dac_nids(codec);
- if (err < 0)
- return err;
- err = stac92xx_auto_create_multi_out_ctls(codec,
- &spec->autocfg);
- if (err < 0)
- return err;
- }
-
- /* setup analog beep controls */
- if (spec->anabeep_nid > 0) {
- err = stac92xx_auto_create_beep_ctls(codec,
- spec->anabeep_nid);
- if (err < 0)
- return err;
- }
-
- /* setup digital beep controls and input device */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
- if (spec->digbeep_nid > 0) {
- hda_nid_t nid = spec->digbeep_nid;
- unsigned int caps;
-
- err = stac92xx_auto_create_beep_ctls(codec, nid);
- if (err < 0)
- return err;
- err = snd_hda_attach_beep_device(codec, nid);
- if (err < 0)
- return err;
- if (codec->beep) {
- /* IDT/STAC codecs have linear beep tone parameter */
- codec->beep->linear_tone = spec->linear_tone_beep;
- /* if no beep switch is available, make its own one */
- caps = query_amp_caps(codec, nid, HDA_OUTPUT);
- if (!(caps & AC_AMPCAP_MUTE)) {
- err = stac92xx_beep_switch_ctl(codec);
- if (err < 0)
- return err;
- }
- }
- }
-#endif
-
- err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- /* All output parsing done, now restore the swapped hp pins */
- if (hp_swap) {
- memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
- sizeof(spec->autocfg.hp_pins));
- spec->autocfg.hp_outs = spec->autocfg.line_outs;
- spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
- spec->autocfg.line_outs = 0;
- }
-
- if (stac_check_auto_mic(codec)) {
- spec->auto_mic = 1;
- /* only one capture for auto-mic */
- spec->num_adcs = 1;
- spec->num_caps = 1;
- spec->num_muxes = 1;
- }
-
- for (i = 0; i < spec->num_caps; i++) {
- err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
- spec->capsws[i], i);
- if (err < 0)
- return err;
- }
-
- err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- if (spec->mono_nid > 0) {
- err = stac92xx_auto_create_mono_output_ctls(codec);
- if (err < 0)
- return err;
- }
- if (spec->num_dmics > 0 && !spec->dinput_mux)
- if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
- &spec->autocfg)) < 0)
- return err;
- if (spec->num_muxes > 0) {
- err = stac92xx_auto_create_mux_input_ctls(codec);
- if (err < 0)
- return err;
- }
- if (spec->num_smuxes > 0) {
- err = stac92xx_auto_create_spdif_mux_ctls(codec);
- if (err < 0)
- return err;
- }
-
- err = stac92xx_add_input_source(spec);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->multiout.max_channels > 2)
- spec->surr_switch = 1;
-
- /* find digital out and in converters */
- for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) {
- unsigned int wid_caps = get_wcaps(codec, i);
- if (wid_caps & AC_WCAP_DIGITAL) {
- switch (get_wcaps_type(wid_caps)) {
- case AC_WID_AUD_OUT:
- if (!dig_out)
- dig_out = i;
- break;
- case AC_WID_AUD_IN:
- if (!dig_in)
- dig_in = i;
- break;
- }
- }
- }
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = dig_out;
- if (dig_in && spec->autocfg.dig_in_pin)
- spec->dig_in_nid = dig_in;
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux;
- if (!spec->dinput_mux)
- spec->dinput_mux = &spec->private_dimux;
- spec->sinput_mux = &spec->private_smux;
- spec->mono_mux = &spec->private_mono_mux;
- return 0;
-}
-
-/* add playback controls for HP output */
-static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
- struct auto_pin_cfg *cfg)
-{
- struct sigmatel_spec *spec = codec->spec;
- hda_nid_t pin = cfg->hp_pins[0];
-
- if (! pin)
- return 0;
-
- if (is_jack_detectable(codec, pin))
- spec->hp_detect = 1;
-
- return 0;
-}
-
-/* add playback controls for LFE output */
-static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
- struct auto_pin_cfg *cfg)
-{
- struct sigmatel_spec *spec = codec->spec;
- int err;
- hda_nid_t lfe_pin = 0x0;
- int i;
-
- /*
- * search speaker outs and line outs for a mono speaker pin
- * with an amp. If one is found, add LFE controls
- * for it.
- */
- for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
- hda_nid_t pin = spec->autocfg.speaker_pins[i];
- unsigned int wcaps = get_wcaps(codec, pin);
- wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
- if (wcaps == AC_WCAP_OUT_AMP)
- /* found a mono speaker with an amp, must be lfe */
- lfe_pin = pin;
- }
-
- /* if speaker_outs is 0, then speakers may be in line_outs */
- if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
- for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
- hda_nid_t pin = spec->autocfg.line_out_pins[i];
- unsigned int defcfg;
- defcfg = snd_hda_codec_get_pincfg(codec, pin);
- if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
- unsigned int wcaps = get_wcaps(codec, pin);
- wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
- if (wcaps == AC_WCAP_OUT_AMP)
- /* found a mono speaker with an amp,
- must be lfe */
- lfe_pin = pin;
- }
- }
- }
-
- if (lfe_pin) {
- err = create_controls(codec, "LFE", lfe_pin, 1);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static int stac9200_parse_auto_config(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int err;
-
- if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
- return err;
-
- if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
- return err;
-
- if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
- return err;
-
- if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
- return err;
-
- if (spec->num_muxes > 0) {
- err = stac92xx_auto_create_mux_input_ctls(codec);
- if (err < 0)
- return err;
- }
-
- err = stac92xx_add_input_source(spec);
- if (err < 0)
- return err;
-
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = 0x05;
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = 0x04;
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux;
- spec->dinput_mux = &spec->private_dimux;
-
- return 0;
-}
-
-/*
- * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
- * funky external mute control using GPIO pins.
- */
-
-static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
- unsigned int dir_mask, unsigned int data)
-{
- unsigned int gpiostate, gpiomask, gpiodir;
-
- snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
-
- gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DATA, 0);
- gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
-
- gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_MASK, 0);
- gpiomask |= mask;
-
- gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DIRECTION, 0);
- gpiodir |= dir_mask;
-
- /* Configure GPIOx as CMOS */
- snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
-
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_MASK, gpiomask);
- snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
-
- msleep(1);
-
- snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
-}
-
-static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
- unsigned char type, int data)
-{
- struct hda_jack_tbl *event;
-
- event = snd_hda_jack_tbl_new(codec, nid);
- if (!event)
- return -ENOMEM;
- event->action = type;
- event->private_data = data;
-
- return 0;
-}
-
-static void handle_unsol_event(struct hda_codec *codec,
- struct hda_jack_tbl *event);
-
-/* check if given nid is a valid pin and no other events are assigned
- * to it. If OK, assign the event, set the unsol flag, and returns 1.
- * Otherwise, returns zero.
- */
-static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
- unsigned int type)
-{
- struct hda_jack_tbl *event;
-
- if (!is_jack_detectable(codec, nid))
- return 0;
- event = snd_hda_jack_tbl_new(codec, nid);
- if (!event)
- return -ENOMEM;
- if (event->action && event->action != type)
- return 0;
- event->action = type;
- event->callback = handle_unsol_event;
- snd_hda_jack_detect_enable(codec, nid, 0);
- return 1;
-}
-
-static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
-{
- int i;
- for (i = 0; i < cfg->hp_outs; i++)
- if (cfg->hp_pins[i] == nid)
- return 1; /* nid is a HP-Out */
- for (i = 0; i < cfg->line_outs; i++)
- if (cfg->line_out_pins[i] == nid)
- return 1; /* nid is a line-Out */
- return 0; /* nid is not a HP-Out */
-};
-
-static void stac92xx_power_down(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- /* power down inactive DACs */
- const hda_nid_t *dac;
- for (dac = spec->dac_list; *dac; dac++)
- if (!check_all_dac_nids(spec, *dac))
- snd_hda_codec_write(codec, *dac, 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-}
-
-static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
- int enable);
-
-static inline bool get_int_hint(struct hda_codec *codec, const char *key,
- int *valp)
-{
- return !snd_hda_get_int_hint(codec, key, valp);
-}
-
-/* override some hints from the hwdep entry */
-static void stac_store_hints(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int val;
-
- val = snd_hda_get_bool_hint(codec, "hp_detect");
- if (val >= 0)
- spec->hp_detect = val;
- if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
- spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
- spec->gpio_mask;
- }
- if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
- spec->gpio_mask &= spec->gpio_mask;
- if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
- spec->gpio_dir &= spec->gpio_mask;
- if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
- spec->eapd_mask &= spec->gpio_mask;
- if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
- spec->gpio_mute &= spec->gpio_mask;
- val = snd_hda_get_bool_hint(codec, "eapd_switch");
- if (val >= 0)
- spec->eapd_switch = val;
-}
-
-static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
- const hda_nid_t *pins)
-{
- while (num_pins--)
- stac_issue_unsol_event(codec, *pins++);
-}
-
-/* fake event to set up pins */
-static void stac_fake_hp_events(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (spec->autocfg.hp_outs)
- stac_issue_unsol_events(codec, spec->autocfg.hp_outs,
- spec->autocfg.hp_pins);
- if (spec->autocfg.line_outs &&
- spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0])
- stac_issue_unsol_events(codec, spec->autocfg.line_outs,
- spec->autocfg.line_out_pins);
-}
-
-static int stac92xx_init(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- unsigned int gpio;
- int i;
-
- if (spec->init)
- snd_hda_sequence_write(codec, spec->init);
-
- snd_hda_apply_verbs(codec);
-
- /* power down adcs initially */
- if (spec->powerdown_adcs)
- for (i = 0; i < spec->num_adcs; i++)
- snd_hda_codec_write(codec,
- spec->adc_nids[i], 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-
- /* override some hints */
- stac_store_hints(codec);
-
- /* set up GPIO */
- gpio = spec->gpio_data;
- /* turn on EAPD statically when spec->eapd_switch isn't set.
- * otherwise, unsol event will turn it on/off dynamically
- */
- if (!spec->eapd_switch)
- gpio |= spec->eapd_mask;
- stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
-
- /* set up pins */
- if (spec->hp_detect) {
- /* Enable unsolicited responses on the HP widget */
- for (i = 0; i < cfg->hp_outs; i++) {
- hda_nid_t nid = cfg->hp_pins[i];
- enable_pin_detect(codec, nid, STAC_HP_EVENT);
- }
- if (cfg->line_out_type == AUTO_PIN_LINE_OUT &&
- cfg->speaker_outs > 0) {
- /* enable pin-detect for line-outs as well */
- for (i = 0; i < cfg->line_outs; i++) {
- hda_nid_t nid = cfg->line_out_pins[i];
- enable_pin_detect(codec, nid, STAC_LO_EVENT);
- }
- }
-
- /* force to enable the first line-out; the others are set up
- * in unsol_event
- */
- stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
- AC_PINCTL_OUT_EN);
- /* fake event to set up pins */
- stac_fake_hp_events(codec);
- } else {
- stac92xx_auto_init_multi_out(codec);
- stac92xx_auto_init_hp_out(codec);
- for (i = 0; i < cfg->hp_outs; i++)
- stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
- }
- if (spec->auto_mic) {
- /* initialize connection to analog input */
- if (spec->dmux_nids)
- snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
- AC_VERB_SET_CONNECT_SEL, 0);
- if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
- stac_issue_unsol_event(codec, spec->ext_mic.pin);
- if (enable_pin_detect(codec, spec->dock_mic.pin,
- STAC_MIC_EVENT))
- stac_issue_unsol_event(codec, spec->dock_mic.pin);
- }
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- int type = cfg->inputs[i].type;
- unsigned int pinctl, conf;
- if (type == AUTO_PIN_MIC) {
- /* for mic pins, force to initialize */
- pinctl = snd_hda_get_default_vref(codec, nid);
- pinctl |= AC_PINCTL_IN_EN;
- stac92xx_auto_set_pinctl(codec, nid, pinctl);
- } else {
- pinctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- /* if PINCTL already set then skip */
- /* Also, if both INPUT and OUTPUT are set,
- * it must be a BIOS bug; need to override, too
- */
- if (!(pinctl & AC_PINCTL_IN_EN) ||
- (pinctl & AC_PINCTL_OUT_EN)) {
- pinctl &= ~AC_PINCTL_OUT_EN;
- pinctl |= AC_PINCTL_IN_EN;
- stac92xx_auto_set_pinctl(codec, nid, pinctl);
- }
- }
- conf = snd_hda_codec_get_pincfg(codec, nid);
- if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
- if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
- stac_issue_unsol_event(codec, nid);
- }
- }
- for (i = 0; i < spec->num_dmics; i++)
- stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
- AC_PINCTL_IN_EN);
- if (cfg->dig_out_pins[0])
- stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0],
- AC_PINCTL_OUT_EN);
- if (cfg->dig_in_pin)
- stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
- AC_PINCTL_IN_EN);
- for (i = 0; i < spec->num_pwrs; i++) {
- hda_nid_t nid = spec->pwr_nids[i];
- unsigned int pinctl, def_conf;
-
- def_conf = snd_hda_codec_get_pincfg(codec, nid);
- def_conf = get_defcfg_connect(def_conf);
- if (def_conf == AC_JACK_PORT_NONE) {
- /* power off unused ports */
- stac_toggle_power_map(codec, nid, 0);
- continue;
- }
- if (def_conf == AC_JACK_PORT_FIXED) {
- /* no need for jack detection for fixed pins */
- stac_toggle_power_map(codec, nid, 1);
- continue;
- }
- /* power on when no jack detection is available */
- /* or when the VREF is used for controlling LED */
- if (!spec->hp_detect ||
- spec->vref_mute_led_nid == nid ||
- !is_jack_detectable(codec, nid)) {
- stac_toggle_power_map(codec, nid, 1);
- continue;
- }
-
- if (is_nid_out_jack_pin(cfg, nid))
- continue; /* already has an unsol event */
-
- pinctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- /* outputs are only ports capable of power management
- * any attempts on powering down a input port cause the
- * referenced VREF to act quirky.
- */
- if (pinctl & AC_PINCTL_IN_EN) {
- stac_toggle_power_map(codec, nid, 1);
- continue;
- }
- if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
- stac_issue_unsol_event(codec, nid);
- continue;
- }
- /* none of the above, turn the port OFF */
- stac_toggle_power_map(codec, nid, 0);
- }
-
- /* sync mute LED */
- if (spec->gpio_led) {
- if (spec->vmaster_mute.hook)
- snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
- else /* the very first init call doesn't have vmaster yet */
- stac92xx_update_led_status(codec, false);
- }
-
- /* sync the power-map */
- if (spec->num_pwrs)
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_IDT_SET_POWER_MAP,
- spec->power_map_bits);
- if (spec->dac_list)
- stac92xx_power_down(codec);
- return 0;
-}
-
-static void stac92xx_free_kctls(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (spec->kctls.list) {
- struct snd_kcontrol_new *kctl = spec->kctls.list;
- int i;
- for (i = 0; i < spec->kctls.used; i++)
- kfree(kctl[i].name);
- }
- snd_array_free(&spec->kctls);
-}
-
-static void stac92xx_shutup_pins(struct hda_codec *codec)
-{
- unsigned int i, def_conf;
-
- if (codec->bus->shutdown)
- return;
- for (i = 0; i < codec->init_pins.used; i++) {
- struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
- def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
- if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
- snd_hda_set_pin_ctl(codec, pin->nid, 0);
- }
-}
-
-static void stac92xx_shutup(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- stac92xx_shutup_pins(codec);
-
- if (spec->eapd_mask)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data &
- ~spec->eapd_mask);
-}
-
-static void stac92xx_free(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (! spec)
- return;
-
- kfree(spec);
- snd_hda_detach_beep_device(codec);
-}
-
-static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
- unsigned int flag)
-{
- unsigned int old_ctl, pin_ctl;
-
- pin_ctl = snd_hda_codec_read(codec, nid,
- 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
-
- if (pin_ctl & AC_PINCTL_IN_EN) {
- /*
- * we need to check the current set-up direction of
- * shared input pins since they can be switched via
- * "xxx as Output" mixer switch
- */
- struct sigmatel_spec *spec = codec->spec;
- if (nid == spec->line_switch || nid == spec->mic_switch)
- return;
- }
-
- old_ctl = pin_ctl;
- /* if setting pin direction bits, clear the current
- direction bits first */
- if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
- pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
-
- pin_ctl |= flag;
- if (old_ctl != pin_ctl)
- snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl);
-}
-
-static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
- unsigned int flag)
-{
- unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
- 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
- if (pin_ctl & flag)
- snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag);
-}
-
-static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
-{
- if (!nid)
- return 0;
- return snd_hda_jack_detect(codec, nid);
-}
-
-static void stac92xx_line_out_detect(struct hda_codec *codec,
- int presence)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
-
- if (cfg->speaker_outs == 0)
- return;
-
- for (i = 0; i < cfg->line_outs; i++) {
- if (presence)
- break;
- presence = get_pin_presence(codec, cfg->line_out_pins[i]);
- if (presence) {
- unsigned int pinctl;
- pinctl = snd_hda_codec_read(codec,
- cfg->line_out_pins[i], 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- if (pinctl & AC_PINCTL_IN_EN)
- presence = 0; /* mic- or line-input */
- }
- }
-
- if (presence) {
- /* disable speakers */
- for (i = 0; i < cfg->speaker_outs; i++)
- stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
- AC_PINCTL_OUT_EN);
- if (spec->eapd_mask && spec->eapd_switch)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data &
- ~spec->eapd_mask);
- } else {
- /* enable speakers */
- for (i = 0; i < cfg->speaker_outs; i++)
- stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
- AC_PINCTL_OUT_EN);
- if (spec->eapd_mask && spec->eapd_switch)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data |
- spec->eapd_mask);
- }
-}
-
-/* return non-zero if the hp-pin of the given array index isn't
- * a jack-detection target
- */
-static int no_hp_sensing(struct sigmatel_spec *spec, int i)
-{
- struct auto_pin_cfg *cfg = &spec->autocfg;
-
- /* ignore sensing of shared line and mic jacks */
- if (cfg->hp_pins[i] == spec->line_switch)
- return 1;
- if (cfg->hp_pins[i] == spec->mic_switch)
- return 1;
- /* ignore if the pin is set as line-out */
- if (cfg->hp_pins[i] == spec->hp_switch)
- return 1;
- return 0;
-}
-
-static void stac92xx_hp_detect(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i, presence;
-
- presence = 0;
- if (spec->gpio_mute)
- presence = !(snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
-
- for (i = 0; i < cfg->hp_outs; i++) {
- if (presence)
- break;
- if (no_hp_sensing(spec, i))
- continue;
- presence = get_pin_presence(codec, cfg->hp_pins[i]);
- if (presence) {
- unsigned int pinctl;
- pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- if (pinctl & AC_PINCTL_IN_EN)
- presence = 0; /* mic- or line-input */
- }
- }
-
- if (presence) {
- /* disable lineouts */
- if (spec->hp_switch)
- stac92xx_reset_pinctl(codec, spec->hp_switch,
- AC_PINCTL_OUT_EN);
- for (i = 0; i < cfg->line_outs; i++)
- stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
- AC_PINCTL_OUT_EN);
- } else {
- /* enable lineouts */
- if (spec->hp_switch)
- stac92xx_set_pinctl(codec, spec->hp_switch,
- AC_PINCTL_OUT_EN);
- for (i = 0; i < cfg->line_outs; i++)
- stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
- AC_PINCTL_OUT_EN);
- }
- stac92xx_line_out_detect(codec, presence);
- /* toggle hp outs */
- for (i = 0; i < cfg->hp_outs; i++) {
- unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
- if (no_hp_sensing(spec, i))
- continue;
- if (1 /*presence*/)
- stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
-#if 0 /* FIXME */
-/* Resetting the pinctl like below may lead to (a sort of) regressions
- * on some devices since they use the HP pin actually for line/speaker
- * outs although the default pin config shows a different pin (that is
- * wrong and useless).
- *
- * So, it's basically a problem of default pin configs, likely a BIOS issue.
- * But, disabling the code below just works around it, and I'm too tired of
- * bug reports with such devices...
- */
- else
- stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
-#endif /* FIXME */
- }
-}
-
-static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
- int enable)
-{
- struct sigmatel_spec *spec = codec->spec;
- unsigned int idx, val;
-
- for (idx = 0; idx < spec->num_pwrs; idx++) {
- if (spec->pwr_nids[idx] == nid)
- break;
- }
- if (idx >= spec->num_pwrs)
- return;
-
- idx = 1 << idx;
-
- val = spec->power_map_bits;
- if (enable)
- val &= ~idx;
- else
- val |= idx;
-
- /* power down unused output ports */
- if (val != spec->power_map_bits) {
- spec->power_map_bits = val;
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_IDT_SET_POWER_MAP, val);
- }
-}
-
-static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
-{
- stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
-}
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
+ "Dell Inspiron", STAC_9205_DELL_M44),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
+ "Dell Vostro 1500", STAC_9205_DELL_M42),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0229,
+ "Dell Vostro 1700", STAC_9205_DELL_M42),
+ /* Gateway */
+ SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
+ SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
+ {} /* terminator */
+};
-/* get the pin connection (fixed, none, etc) */
-static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+static int stac_parse_auto_config(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- unsigned int cfg;
+ int err;
- cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
- return get_defcfg_connect(cfg);
-}
+ err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+ if (err < 0)
+ return err;
-static int stac92xx_connected_ports(struct hda_codec *codec,
- const hda_nid_t *nids, int num_nids)
-{
- struct sigmatel_spec *spec = codec->spec;
- int idx, num;
- unsigned int def_conf;
-
- for (num = 0; num < num_nids; num++) {
- for (idx = 0; idx < spec->num_pins; idx++)
- if (spec->pin_nids[idx] == nids[num])
- break;
- if (idx >= spec->num_pins)
- break;
- def_conf = stac_get_defcfg_connect(codec, idx);
- if (def_conf == AC_JACK_PORT_NONE)
- break;
- }
- return num;
-}
+ /* add hooks */
+ spec->gen.pcm_playback_hook = stac_playback_pcm_hook;
+ spec->gen.pcm_capture_hook = stac_capture_pcm_hook;
-static void stac92xx_mic_detect(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct sigmatel_mic_route *mic;
+ spec->gen.automute_hook = stac_update_outputs;
+ spec->gen.hp_automute_hook = stac_hp_automute;
+ spec->gen.line_automute_hook = stac_line_automute;
- if (get_pin_presence(codec, spec->ext_mic.pin))
- mic = &spec->ext_mic;
- else if (get_pin_presence(codec, spec->dock_mic.pin))
- mic = &spec->dock_mic;
- else
- mic = &spec->int_mic;
- if (mic->dmux_idx >= 0)
- snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
- AC_VERB_SET_CONNECT_SEL,
- mic->dmux_idx);
- if (mic->mux_idx >= 0)
- snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
- AC_VERB_SET_CONNECT_SEL,
- mic->mux_idx);
-}
+ err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+ if (err < 0)
+ return err;
-static void handle_unsol_event(struct hda_codec *codec,
- struct hda_jack_tbl *event)
-{
- struct sigmatel_spec *spec = codec->spec;
- int data;
+ /* minimum value is actually mute */
+ spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
- switch (event->action) {
- case STAC_HP_EVENT:
- case STAC_LO_EVENT:
- stac92xx_hp_detect(codec);
- break;
- case STAC_MIC_EVENT:
- stac92xx_mic_detect(codec);
- break;
+ /* setup analog beep controls */
+ if (spec->anabeep_nid > 0) {
+ err = stac_auto_create_beep_ctls(codec,
+ spec->anabeep_nid);
+ if (err < 0)
+ return err;
}
- switch (event->action) {
- case STAC_HP_EVENT:
- case STAC_LO_EVENT:
- case STAC_MIC_EVENT:
- case STAC_INSERT_EVENT:
- case STAC_PWR_EVENT:
- if (spec->num_pwrs > 0)
- stac92xx_pin_sense(codec, event->nid);
-
- switch (codec->subsystem_id) {
- case 0x103c308f:
- if (event->nid == 0xb) {
- int pin = AC_PINCTL_IN_EN;
-
- if (get_pin_presence(codec, 0xa)
- && get_pin_presence(codec, 0xb))
- pin |= AC_PINCTL_VREF_80;
- if (!get_pin_presence(codec, 0xb))
- pin |= AC_PINCTL_VREF_80;
-
- /* toggle VREF state based on mic + hp pin
- * status
- */
- stac92xx_auto_set_pinctl(codec, 0x0a, pin);
+ /* setup digital beep controls and input device */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+ if (spec->digbeep_nid > 0) {
+ hda_nid_t nid = spec->digbeep_nid;
+ unsigned int caps;
+
+ err = stac_auto_create_beep_ctls(codec, nid);
+ if (err < 0)
+ return err;
+ err = snd_hda_attach_beep_device(codec, nid);
+ if (err < 0)
+ return err;
+ if (codec->beep) {
+ /* IDT/STAC codecs have linear beep tone parameter */
+ codec->beep->linear_tone = spec->linear_tone_beep;
+ /* if no beep switch is available, make its own one */
+ caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+ if (!(caps & AC_AMPCAP_MUTE)) {
+ err = stac_beep_switch_ctl(codec);
+ if (err < 0)
+ return err;
}
}
- break;
- case STAC_VREF_EVENT:
- data = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DATA, 0);
- /* toggle VREF state based on GPIOx status */
- snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
- !!(data & (1 << event->private_data)));
- break;
}
-}
+#endif
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
-{
- struct hda_jack_tbl *event = snd_hda_jack_tbl_get(codec, nid);
- if (!event)
- return;
- handle_unsol_event(codec, event);
+ if (spec->gpio_led)
+ spec->gen.vmaster_mute.hook = stac_vmaster_hook;
+
+ if (spec->aloopback_ctl &&
+ snd_hda_get_bool_hint(codec, "loopback") == 1) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, spec->aloopback_ctl))
+ return -ENOMEM;
+ }
+
+ stac_init_power_map(codec);
+
+ return 0;
}
-static void set_hp_led_gpio(struct hda_codec *codec)
+
+static int stac_init(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
unsigned int gpio;
+ int i;
- if (spec->gpio_led)
- return;
+ /* override some hints */
+ stac_store_hints(codec);
- gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
- gpio &= AC_GPIO_IO_COUNT;
- if (gpio > 3)
- spec->gpio_led = 0x08; /* GPIO 3 */
- else
- spec->gpio_led = 0x01; /* GPIO 0 */
-}
+ /* set up GPIO */
+ gpio = spec->gpio_data;
+ /* turn on EAPD statically when spec->eapd_switch isn't set.
+ * otherwise, unsol event will turn it on/off dynamically
+ */
+ if (!spec->eapd_switch)
+ gpio |= spec->eapd_mask;
+ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
-/*
- * This method searches for the mute LED GPIO configuration
- * provided as OEM string in SMBIOS. The format of that string
- * is HP_Mute_LED_P_G or HP_Mute_LED_P
- * where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
- * that corresponds to the NOT muted state of the master volume
- * and G is the index of the GPIO to use as the mute LED control (0..9)
- * If _G portion is missing it is assigned based on the codec ID
- *
- * So, HP B-series like systems may have HP_Mute_LED_0 (current models)
- * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
- *
- *
- * The dv-series laptops don't seem to have the HP_Mute_LED* strings in
- * SMBIOS - at least the ones I have seen do not have them - which include
- * my own system (HP Pavilion dv6-1110ax) and my cousin's
- * HP Pavilion dv9500t CTO.
- * Need more information on whether it is true across the entire series.
- * -- kunal
- */
-static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
-{
- struct sigmatel_spec *spec = codec->spec;
- const struct dmi_device *dev = NULL;
+ snd_hda_gen_init(codec);
- if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
- get_int_hint(codec, "gpio_led_polarity",
- &spec->gpio_led_polarity);
- return 1;
- }
+ /* sync the power-map */
+ if (spec->num_pwrs)
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_IDT_SET_POWER_MAP,
+ spec->power_map_bits);
- while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
- if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
- &spec->gpio_led_polarity,
- &spec->gpio_led) == 2) {
- unsigned int max_gpio;
- max_gpio = snd_hda_param_read(codec, codec->afg,
- AC_PAR_GPIO_CAP);
- max_gpio &= AC_GPIO_IO_COUNT;
- if (spec->gpio_led < max_gpio)
- spec->gpio_led = 1 << spec->gpio_led;
- else
- spec->vref_mute_led_nid = spec->gpio_led;
- return 1;
- }
- if (sscanf(dev->name, "HP_Mute_LED_%d",
- &spec->gpio_led_polarity) == 1) {
- set_hp_led_gpio(codec);
- return 1;
- }
- /* BIOS bug: unfilled OEM string */
- if (strstr(dev->name, "HP_Mute_LED_P_G")) {
- set_hp_led_gpio(codec);
- if (default_polarity >= 0)
- spec->gpio_led_polarity = default_polarity;
- else
- spec->gpio_led_polarity = 1;
- return 1;
+ /* power down inactive ADCs */
+ if (spec->powerdown_adcs) {
+ for (i = 0; i < spec->gen.num_all_adcs; i++) {
+ if (spec->active_adcs & (1 << i))
+ continue;
+ snd_hda_codec_write(codec, spec->gen.all_adcs[i], 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
}
}
- /*
- * Fallback case - if we don't find the DMI strings,
- * we statically set the GPIO - if not a B-series system
- * and default polarity is provided
- */
- if (!hp_blike_system(codec->subsystem_id) &&
- (default_polarity == 0 || default_polarity == 1)) {
- set_hp_led_gpio(codec);
- spec->gpio_led_polarity = default_polarity;
- return 1;
+ /* power down unused DACs */
+ for (i = 0; i < spec->gen.num_all_dacs; i++) {
+ if (!snd_hda_get_nid_path(codec, spec->gen.all_dacs[i], 0))
+ snd_hda_codec_write(codec, spec->gen.all_dacs[i], 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
}
+
return 0;
}
-static int hp_blike_system(u32 subsystem_id)
+static void stac_shutup(struct hda_codec *codec)
{
- switch (subsystem_id) {
- case 0x103c1520:
- case 0x103c1521:
- case 0x103c1523:
- case 0x103c1524:
- case 0x103c1525:
- case 0x103c1722:
- case 0x103c1723:
- case 0x103c1724:
- case 0x103c1725:
- case 0x103c1726:
- case 0x103c1727:
- case 0x103c1728:
- case 0x103c1729:
- case 0x103c172a:
- case 0x103c172b:
- case 0x103c307e:
- case 0x103c307f:
- case 0x103c3080:
- case 0x103c3081:
- case 0x103c7007:
- case 0x103c7008:
- return 1;
- }
- return 0;
+ struct sigmatel_spec *spec = codec->spec;
+
+ snd_hda_shutup_pins(codec);
+
+ if (spec->eapd_mask)
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data &
+ ~spec->eapd_mask);
+}
+
+static void stac_free(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (!spec)
+ return;
+
+ snd_hda_gen_spec_free(&spec->gen);
+ kfree(spec);
+ snd_hda_detach_beep_device(codec);
}
#ifdef CONFIG_PROC_FS
@@ -6341,101 +3585,69 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
#endif
#ifdef CONFIG_PM
-static int stac92xx_resume(struct hda_codec *codec)
+static int stac_resume(struct hda_codec *codec)
{
- stac92xx_init(codec);
+ codec->patch_ops.init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
- /* fake event to set up pins again to override cached values */
- stac_fake_hp_events(codec);
return 0;
}
-static int stac92xx_suspend(struct hda_codec *codec)
-{
- stac92xx_shutup(codec);
- return 0;
-}
-
-static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state)
-{
- unsigned int afg_power_state = power_state;
- struct sigmatel_spec *spec = codec->spec;
-
- if (power_state == AC_PWRST_D3) {
- if (spec->vref_mute_led_nid) {
- /* with vref-out pin used for mute led control
- * codec AFG is prevented from D3 state
- */
- afg_power_state = AC_PWRST_D1;
- }
- /* this delay seems necessary to avoid click noise at power-down */
- msleep(100);
- }
- snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
- afg_power_state);
- snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
-}
-#else
-#define stac92xx_suspend NULL
-#define stac92xx_resume NULL
-#define stac92xx_set_power_state NULL
-#endif /* CONFIG_PM */
-
-/* update mute-LED accoring to the master switch */
-static void stac92xx_update_led_status(struct hda_codec *codec, int enabled)
-{
- struct sigmatel_spec *spec = codec->spec;
- int muted = !enabled;
-
- if (!spec->gpio_led)
- return;
-
- /* LED state is inverted on these systems */
- if (spec->gpio_led_polarity)
- muted = !muted;
-
- if (!spec->vref_mute_led_nid) {
- if (muted)
- spec->gpio_data |= spec->gpio_led;
- else
- spec->gpio_data &= ~spec->gpio_led;
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data);
- } else {
- spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
- stac_vrefout_set(codec, spec->vref_mute_led_nid,
- spec->vref_led);
+static int stac_suspend(struct hda_codec *codec)
+{
+ stac_shutup(codec);
+ return 0;
+}
+
+static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state)
+{
+ unsigned int afg_power_state = power_state;
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (power_state == AC_PWRST_D3) {
+ if (spec->vref_mute_led_nid) {
+ /* with vref-out pin used for mute led control
+ * codec AFG is prevented from D3 state
+ */
+ afg_power_state = AC_PWRST_D1;
+ }
+ /* this delay seems necessary to avoid click noise at power-down */
+ msleep(100);
}
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+ afg_power_state);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
}
+#else
+#define stac_suspend NULL
+#define stac_resume NULL
+#define stac_set_power_state NULL
+#endif /* CONFIG_PM */
-static const struct hda_codec_ops stac92xx_patch_ops = {
- .build_controls = stac92xx_build_controls,
- .build_pcms = stac92xx_build_pcms,
- .init = stac92xx_init,
- .free = stac92xx_free,
+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,
#ifdef CONFIG_PM
- .suspend = stac92xx_suspend,
- .resume = stac92xx_resume,
+ .suspend = stac_suspend,
+ .resume = stac_resume,
#endif
- .reboot_notify = stac92xx_shutup,
+ .reboot_notify = stac_shutup,
};
-static int alloc_stac_spec(struct hda_codec *codec, int num_pins,
- const hda_nid_t *pin_nids)
+static int alloc_stac_spec(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
+ snd_hda_gen_spec_init(&spec->gen);
codec->spec = spec;
codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
- spec->num_pins = num_pins;
- spec->pin_nids = pin_nids;
- snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
return 0;
}
@@ -6444,40 +3656,28 @@ static int patch_stac9200(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac9200_pin_nids),
- stac9200_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 1;
+ spec->gen.own_eapd_ctl = 1;
- snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl,
- stac9200_fixups);
+ codec->patch_ops = stac_patch_ops;
- spec->multiout.max_channels = 2;
- spec->multiout.num_dacs = 1;
- spec->multiout.dac_nids = stac9200_dac_nids;
- spec->adc_nids = stac9200_adc_nids;
- spec->mux_nids = stac9200_mux_nids;
- spec->num_muxes = 1;
- spec->num_dmics = 0;
- spec->num_adcs = 1;
- spec->num_pwrs = 0;
snd_hda_add_verbs(codec, stac9200_eapd_init);
- spec->mixer = stac9200_mixer;
-
+ snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl,
+ stac9200_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = stac9200_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
- codec->patch_ops = stac92xx_patch_ops;
-
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
@@ -6488,56 +3688,28 @@ static int patch_stac925x(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac925x_pin_nids),
- stac925x_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 1;
+ spec->gen.own_eapd_ctl = 1;
- snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl,
- stac925x_fixups);
-
- spec->multiout.max_channels = 2;
- spec->multiout.num_dacs = 1;
- spec->multiout.dac_nids = stac925x_dac_nids;
- spec->adc_nids = stac925x_adc_nids;
- spec->mux_nids = stac925x_mux_nids;
- spec->num_muxes = 1;
- spec->num_adcs = 1;
- spec->num_pwrs = 0;
- switch (codec->vendor_id) {
- case 0x83847632: /* STAC9202 */
- case 0x83847633: /* STAC9202D */
- case 0x83847636: /* STAC9251 */
- case 0x83847637: /* STAC9251D */
- spec->num_dmics = STAC925X_NUM_DMICS;
- spec->dmic_nids = stac925x_dmic_nids;
- spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
- spec->dmux_nids = stac925x_dmux_nids;
- break;
- default:
- spec->num_dmics = 0;
- break;
- }
+ codec->patch_ops = stac_patch_ops;
snd_hda_add_verbs(codec, stac925x_core_init);
- spec->mixer = stac925x_mixer;
- spec->num_caps = 1;
- spec->capvols = stac925x_capvols;
- spec->capsws = stac925x_capsws;
+ snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl,
+ stac925x_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
- codec->patch_ops = stac92xx_patch_ops;
-
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
@@ -6546,86 +3718,66 @@ static int patch_stac925x(struct hda_codec *codec)
static int patch_stac92hd73xx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
- hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
int err;
int num_dacs;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac92hd73xx_pin_nids),
- stac92hd73xx_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 0;
- codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
-
- snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl,
- stac92hd73xx_fixups);
-
- num_dacs = snd_hda_get_connections(codec, 0x0a,
- conn, STAC92HD73_DAC_COUNT + 2) - 1;
+ num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1;
if (num_dacs < 3 || num_dacs > 5) {
printk(KERN_WARNING "hda_codec: Could not determine "
"number of channels defaulting to DAC count\n");
- num_dacs = STAC92HD73_DAC_COUNT;
+ num_dacs = 5;
}
switch (num_dacs) {
case 0x3: /* 6 Channel */
- spec->aloopback_ctl = stac92hd73xx_6ch_loopback;
+ spec->aloopback_ctl = &stac92hd73xx_6ch_loopback;
break;
case 0x4: /* 8 Channel */
- spec->aloopback_ctl = stac92hd73xx_8ch_loopback;
+ spec->aloopback_ctl = &stac92hd73xx_8ch_loopback;
break;
case 0x5: /* 10 Channel */
- spec->aloopback_ctl = stac92hd73xx_10ch_loopback;
+ spec->aloopback_ctl = &stac92hd73xx_10ch_loopback;
break;
}
- spec->multiout.dac_nids = spec->dac_nids;
spec->aloopback_mask = 0x01;
spec->aloopback_shift = 8;
spec->digbeep_nid = 0x1c;
- spec->mux_nids = stac92hd73xx_mux_nids;
- spec->adc_nids = stac92hd73xx_adc_nids;
- spec->dmic_nids = stac92hd73xx_dmic_nids;
- spec->dmux_nids = stac92hd73xx_dmux_nids;
- spec->smux_nids = stac92hd73xx_smux_nids;
-
- spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
- spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
- spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
-
- spec->num_caps = STAC92HD73XX_NUM_CAPS;
- spec->capvols = stac92hd73xx_capvols;
- spec->capsws = stac92hd73xx_capsws;
/* GPIO0 High = Enable EAPD */
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
spec->gpio_data = 0x01;
- spec->num_dmics = STAC92HD73XX_NUM_DMICS;
- spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
spec->eapd_switch = 1;
spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
spec->pwr_nids = stac92hd73xx_pwr_nids;
+ spec->gen.own_eapd_ctl = 1;
+
+ codec->patch_ops = stac_patch_ops;
+
+ snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl,
+ stac92hd73xx_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
if (!spec->volknob_init)
snd_hda_add_verbs(codec, stac92hd73xx_core_init);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
- codec->patch_ops = stac92xx_patch_ops;
-
codec->proc_widget_hook = stac92hd7x_proc_hook;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -6633,145 +3785,6 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
return 0;
}
-static int hp_bnb2011_with_dock(struct hda_codec *codec)
-{
- if (codec->vendor_id != 0x111d7605 &&
- codec->vendor_id != 0x111d76d1)
- return 0;
-
- switch (codec->subsystem_id) {
- case 0x103c1618:
- case 0x103c1619:
- case 0x103c161a:
- case 0x103c161b:
- case 0x103c161c:
- case 0x103c161d:
- case 0x103c161e:
- case 0x103c161f:
-
- case 0x103c162a:
- case 0x103c162b:
-
- case 0x103c1630:
- case 0x103c1631:
-
- case 0x103c1633:
- case 0x103c1634:
- case 0x103c1635:
-
- case 0x103c3587:
- case 0x103c3588:
- case 0x103c3589:
- case 0x103c358a:
-
- case 0x103c3667:
- case 0x103c3668:
- case 0x103c3669:
-
- return 1;
- }
- return 0;
-}
-
-static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid)
-{
- struct sigmatel_spec *spec = codec->spec;
- unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
- int i;
-
- spec->auto_pin_nids[spec->auto_pin_cnt] = nid;
- spec->auto_pin_cnt++;
-
- if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
- get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) {
- for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) {
- if (nid == stac92hd83xxx_dmic_nids[i]) {
- spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid;
- spec->auto_dmic_cnt++;
- }
- }
- }
-}
-
-static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- spec->auto_adc_nids[spec->auto_adc_cnt] = nid;
- spec->auto_adc_cnt++;
-}
-
-static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid)
-{
- int i, j;
- struct sigmatel_spec *spec = codec->spec;
-
- for (i = 0; i < spec->auto_adc_cnt; i++) {
- if (get_connection_index(codec,
- spec->auto_adc_nids[i], nid) >= 0) {
- /* mux and volume for adc_nids[i] */
- if (!spec->auto_mux_nids[i]) {
- spec->auto_mux_nids[i] = nid;
- /* 92hd codecs capture volume is in mux */
- spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid,
- 3, 0, HDA_OUTPUT);
- }
- for (j = 0; j < spec->auto_dmic_cnt; j++) {
- if (get_connection_index(codec, nid,
- spec->auto_dmic_nids[j]) >= 0) {
- /* dmux for adc_nids[i] */
- if (!spec->auto_dmux_nids[i])
- spec->auto_dmux_nids[i] = nid;
- break;
- }
- }
- break;
- }
- }
-}
-
-static void stac92hd8x_fill_auto_spec(struct hda_codec *codec)
-{
- hda_nid_t nid, end_nid;
- unsigned int wid_caps, wid_type;
- struct sigmatel_spec *spec = codec->spec;
-
- end_nid = codec->start_nid + codec->num_nodes;
-
- for (nid = codec->start_nid; nid < end_nid; nid++) {
- wid_caps = get_wcaps(codec, nid);
- wid_type = get_wcaps_type(wid_caps);
-
- if (wid_type == AC_WID_PIN)
- stac92hd8x_add_pin(codec, nid);
-
- if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL))
- stac92hd8x_add_adc(codec, nid);
- }
-
- for (nid = codec->start_nid; nid < end_nid; nid++) {
- wid_caps = get_wcaps(codec, nid);
- wid_type = get_wcaps_type(wid_caps);
-
- if (wid_type == AC_WID_AUD_SEL)
- stac92hd8x_add_mux(codec, nid);
- }
-
- spec->pin_nids = spec->auto_pin_nids;
- spec->num_pins = spec->auto_pin_cnt;
- spec->adc_nids = spec->auto_adc_nids;
- spec->num_adcs = spec->auto_adc_cnt;
- spec->capvols = spec->auto_capvols;
- spec->capsws = spec->auto_capvols;
- spec->num_caps = spec->auto_adc_cnt;
- spec->mux_nids = spec->auto_mux_nids;
- spec->num_muxes = spec->auto_adc_cnt;
- spec->dmux_nids = spec->auto_dmux_nids;
- spec->num_dmuxes = spec->auto_adc_cnt;
- spec->dmic_nids = spec->auto_dmic_nids;
- spec->num_dmics = spec->auto_dmic_cnt;
-}
-
static void stac_setup_gpio(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -6783,7 +3796,7 @@ static void stac_setup_gpio(struct hda_codec *codec)
spec->gpio_data |= spec->gpio_led;
} else {
codec->patch_ops.set_power_state =
- stac92xx_set_power_state;
+ stac_set_power_state;
}
}
@@ -6792,6 +3805,8 @@ static void stac_setup_gpio(struct hda_codec *codec)
spec->gpio_dir |= spec->mic_mute_led_gpio;
spec->mic_mute_led_on = true;
spec->gpio_data |= spec->mic_mute_led_gpio;
+
+ spec->gen.capture_switch_hook = stac_capture_led_hook;
}
}
@@ -6800,36 +3815,34 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, 0, NULL); /* pins filled later */
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
codec->epss = 0; /* longer delay needed for D3 */
- stac92hd8x_fill_auto_spec(codec);
spec = codec->spec;
spec->linear_tone_beep = 0;
- codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
+ spec->gen.own_eapd_ctl = 1;
+
spec->digbeep_nid = 0x21;
spec->pwr_nids = stac92hd83xxx_pwr_nids;
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
- spec->multiout.dac_nids = spec->dac_nids;
+ spec->default_polarity = -1; /* no default cfg */
- snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl,
- stac92hd83xxx_fixups);
+ codec->patch_ops = stac_patch_ops;
snd_hda_add_verbs(codec, stac92hd83xxx_core_init);
- spec->default_polarity = -1; /* no default cfg */
-
- codec->patch_ops = stac92xx_patch_ops;
+ snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl,
+ stac92hd83xxx_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
stac_setup_gpio(codec);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
@@ -6840,133 +3853,31 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
return 0;
}
-static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
- hda_nid_t dig0pin)
-{
- struct sigmatel_spec *spec = codec->spec;
- int idx;
-
- for (idx = 0; idx < spec->num_pins; idx++)
- if (spec->pin_nids[idx] == dig0pin)
- break;
- if ((idx + 2) >= spec->num_pins)
- return 0;
-
- /* dig1pin case */
- if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE)
- return 2;
-
- /* dig0pin + dig2pin case */
- if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE)
- return 2;
- if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE)
- return 1;
- else
- return 0;
-}
-
-/* HP dv7 bass switch - GPIO5 */
-#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
-static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
- return 0;
-}
-
-static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct sigmatel_spec *spec = codec->spec;
- unsigned int gpio_data;
-
- gpio_data = (spec->gpio_data & ~0x20) |
- (ucontrol->value.integer.value[0] ? 0x20 : 0);
- if (gpio_data == spec->gpio_data)
- return 0;
- spec->gpio_data = gpio_data;
- stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
- return 1;
-}
-
-static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .info = stac_hp_bass_gpio_info,
- .get = stac_hp_bass_gpio_get,
- .put = stac_hp_bass_gpio_put,
-};
-
-static int stac_add_hp_bass_switch(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl,
- "Bass Speaker Playback Switch", 0))
- return -ENOMEM;
-
- spec->gpio_mask |= 0x20;
- spec->gpio_dir |= 0x20;
- spec->gpio_data |= 0x20;
- return 0;
-}
-
static int patch_stac92hd71bxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
int err;
- err = alloc_stac_spec(codec, STAC92HD71BXX_NUM_PINS,
- stac92hd71bxx_pin_nids_4port);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 0;
- codec->patch_ops = stac92xx_patch_ops;
- switch (codec->vendor_id) {
- case 0x111d76b6:
- case 0x111d76b7:
- break;
- case 0x111d7603:
- case 0x111d7608:
- /* On 92HD75Bx 0x27 isn't a pin nid */
- spec->num_pins--;
- /* fallthrough */
- default:
- spec->pin_nids = stac92hd71bxx_pin_nids_6port;
- }
- spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
+ spec->gen.own_eapd_ctl = 1;
- snd_hda_pick_fixup(codec, stac92hd71bxx_models, stac92hd71bxx_fixup_tbl,
- stac92hd71bxx_fixups);
+ codec->patch_ops = stac_patch_ops;
/* GPIO0 = EAPD */
spec->gpio_mask = 0x01;
spec->gpio_dir = 0x01;
spec->gpio_data = 0x01;
- spec->dmic_nids = stac92hd71bxx_dmic_nids;
- spec->dmux_nids = stac92hd71bxx_dmux_nids;
-
- spec->num_caps = STAC92HD71BXX_NUM_CAPS;
- spec->capvols = stac92hd71bxx_capvols;
- spec->capsws = stac92hd71bxx_capsws;
-
switch (codec->vendor_id) {
case 0x111d76b6: /* 4 Port without Analog Mixer */
case 0x111d76b7:
unmute_init++;
- /* fallthru */
- case 0x111d76b4: /* 6 Port without Analog Mixer */
- case 0x111d76b5:
- codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
- spec->num_dmics = stac92xx_connected_ports(codec,
- stac92hd71bxx_dmic_nids,
- STAC92HD71BXX_NUM_DMICS);
break;
case 0x111d7608: /* 5 Port with Analog Mixer */
if ((codec->revision_id & 0xf) == 0 ||
@@ -6977,21 +3888,11 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
unmute_init++;
snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
- spec->dmic_nids = stac92hd71bxx_dmic_5port_nids;
- spec->num_dmics = stac92xx_connected_ports(codec,
- stac92hd71bxx_dmic_5port_nids,
- STAC92HD71BXX_NUM_DMICS - 1);
break;
case 0x111d7603: /* 6 Port with Analog Mixer */
if ((codec->revision_id & 0xf) == 1)
spec->stream_delay = 40; /* 40 milliseconds */
- /* fallthru */
- default:
- codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
- spec->num_dmics = stac92xx_connected_ports(codec,
- stac92hd71bxx_dmic_nids,
- STAC92HD71BXX_NUM_DMICS);
break;
}
@@ -7001,32 +3902,24 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
snd_hda_sequence_write_cache(codec, unmute_init);
- spec->aloopback_ctl = stac92hd71bxx_loopback;
+ spec->aloopback_ctl = &stac92hd71bxx_loopback;
spec->aloopback_mask = 0x50;
spec->aloopback_shift = 0;
spec->powerdown_adcs = 1;
spec->digbeep_nid = 0x26;
- spec->mux_nids = stac92hd71bxx_mux_nids;
- spec->adc_nids = stac92hd71bxx_adc_nids;
- spec->smux_nids = stac92hd71bxx_smux_nids;
+ spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
spec->pwr_nids = stac92hd71bxx_pwr_nids;
- spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
- spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
- spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
- spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
-
- spec->multiout.dac_nids = spec->dac_nids;
- spec->default_polarity = 1;
-
+ snd_hda_pick_fixup(codec, stac92hd71bxx_models, stac92hd71bxx_fixup_tbl,
+ stac92hd71bxx_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
stac_setup_gpio(codec);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
@@ -7042,42 +3935,18 @@ static int patch_stac922x(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac922x_pin_nids),
- stac922x_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 1;
+ spec->gen.own_eapd_ctl = 1;
- snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl,
- stac922x_fixups);
-
- spec->adc_nids = stac922x_adc_nids;
- spec->mux_nids = stac922x_mux_nids;
- spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
- spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
- spec->num_dmics = 0;
- spec->num_pwrs = 0;
+ codec->patch_ops = stac_patch_ops;
- spec->num_caps = STAC922X_NUM_CAPS;
- spec->capvols = stac922x_capvols;
- spec->capsws = stac922x_capsws;
-
- spec->multiout.dac_nids = spec->dac_nids;
-
snd_hda_add_verbs(codec, stac922x_core_init);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- err = stac92xx_parse_auto_config(codec);
- if (err < 0) {
- stac92xx_free(codec);
- return err;
- }
-
- codec->patch_ops = stac92xx_patch_ops;
-
/* Fix Mux capture level; max to 2 */
snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
(0 << AC_AMPCAP_OFFSET_SHIFT) |
@@ -7085,6 +3954,16 @@ static int patch_stac922x(struct hda_codec *codec)
(0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(0 << AC_AMPCAP_MUTE_SHIFT));
+ snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl,
+ stac922x_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ err = stac_parse_auto_config(codec);
+ if (err < 0) {
+ stac_free(codec);
+ return err;
+ }
+
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return 0;
@@ -7095,58 +3974,40 @@ static int patch_stac927x(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac927x_pin_nids),
- stac927x_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 1;
- codec->slave_dig_outs = stac927x_slave_dig_outs;
-
- snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl,
- stac927x_fixups);
+ spec->gen.own_eapd_ctl = 1;
spec->digbeep_nid = 0x23;
- spec->adc_nids = stac927x_adc_nids;
- spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
- spec->mux_nids = stac927x_mux_nids;
- spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
- spec->smux_nids = stac927x_smux_nids;
- spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
- spec->spdif_labels = stac927x_spdif_labels;
- spec->dac_list = stac927x_dac_nids;
- spec->multiout.dac_nids = spec->dac_nids;
/* GPIO0 High = Enable EAPD */
spec->eapd_mask = spec->gpio_mask = 0x01;
spec->gpio_dir = spec->gpio_data = 0x01;
- spec->num_dmics = 0;
-
- spec->num_caps = STAC927X_NUM_CAPS;
- spec->capvols = stac927x_capvols;
- spec->capsws = stac927x_capsws;
-
- spec->num_pwrs = 0;
- spec->aloopback_ctl = stac927x_loopback;
+ spec->aloopback_ctl = &stac927x_loopback;
spec->aloopback_mask = 0x40;
spec->aloopback_shift = 0;
spec->eapd_switch = 1;
+ codec->patch_ops = stac_patch_ops;
+
+ snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl,
+ stac927x_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
if (!spec->volknob_init)
snd_hda_add_verbs(codec, stac927x_core_init);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
- codec->patch_ops = stac92xx_patch_ops;
-
codec->proc_widget_hook = stac927x_proc_hook;
/*
@@ -7171,40 +4032,21 @@ static int patch_stac9205(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac9205_pin_nids),
- stac9205_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 1;
-
- snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl,
- stac9205_fixups);
+ spec->gen.own_eapd_ctl = 1;
spec->digbeep_nid = 0x23;
- spec->adc_nids = stac9205_adc_nids;
- spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
- spec->mux_nids = stac9205_mux_nids;
- spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
- spec->smux_nids = stac9205_smux_nids;
- spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
- spec->dmic_nids = stac9205_dmic_nids;
- spec->num_dmics = STAC9205_NUM_DMICS;
- spec->dmux_nids = stac9205_dmux_nids;
- spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
- spec->num_pwrs = 0;
snd_hda_add_verbs(codec, stac9205_core_init);
- spec->aloopback_ctl = stac9205_loopback;
-
- spec->num_caps = STAC9205_NUM_CAPS;
- spec->capvols = stac9205_capvols;
- spec->capsws = stac9205_capsws;
+ spec->aloopback_ctl = &stac9205_loopback;
spec->aloopback_mask = 0x40;
spec->aloopback_shift = 0;
- spec->multiout.dac_nids = spec->dac_nids;
/* GPIO0 High = EAPD */
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
@@ -7213,16 +4055,18 @@ static int patch_stac9205(struct hda_codec *codec)
/* Turn on/off EAPD per HP plugging */
spec->eapd_switch = 1;
+ codec->patch_ops = stac_patch_ops;
+
+ snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl,
+ stac9205_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return err;
}
- codec->patch_ops = stac92xx_patch_ops;
-
codec->proc_widget_hook = stac9205_proc_hook;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7240,24 +4084,6 @@ static const struct hda_verb stac9872_core_init[] = {
{}
};
-static const hda_nid_t stac9872_pin_nids[] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x11, 0x13, 0x14,
-};
-
-static const hda_nid_t stac9872_adc_nids[] = {
- 0x8 /*,0x6*/
-};
-
-static const hda_nid_t stac9872_mux_nids[] = {
- 0x15
-};
-
-static const unsigned long stac9872_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-};
-#define stac9872_capsws stac9872_capvols
-
static const struct hda_pintbl stac9872_vaio_pin_configs[] = {
{ 0x0a, 0x03211020 },
{ 0x0b, 0x411111f0 },
@@ -7294,36 +4120,27 @@ static int patch_stac9872(struct hda_codec *codec)
struct sigmatel_spec *spec;
int err;
- err = alloc_stac_spec(codec, ARRAY_SIZE(stac9872_pin_nids),
- stac9872_pin_nids);
+ err = alloc_stac_spec(codec);
if (err < 0)
return err;
spec = codec->spec;
spec->linear_tone_beep = 1;
+ spec->gen.own_eapd_ctl = 1;
- snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl,
- stac9872_fixups);
+ codec->patch_ops = stac_patch_ops;
- spec->multiout.dac_nids = spec->dac_nids;
- spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
- spec->adc_nids = stac9872_adc_nids;
- spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
- spec->mux_nids = stac9872_mux_nids;
- spec->num_caps = 1;
- spec->capvols = stac9872_capvols;
- spec->capsws = stac9872_capsws;
snd_hda_add_verbs(codec, stac9872_core_init);
+ snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl,
+ stac9872_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = stac92xx_parse_auto_config(codec);
+ err = stac_parse_auto_config(codec);
if (err < 0) {
- stac92xx_free(codec);
+ stac_free(codec);
return -EINVAL;
}
- spec->input_mux = &spec->private_imux;
- codec->patch_ops = stac92xx_patch_ops;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
--
1.8.1
1
0
17 Jan '13
Hi,
this is the final bits for improving / fixing the HD-audio generic
parser for migrating patch_sigmatel.c. After these, patch_sigmatel.c
is converted to use the generic parser, and all done!
As usual, the patches are found in sound-unstable git tree
test/hda-gen-parser branch (it's already merged into master and
test/hda-migrate branch, too).
Takashi
1
9
17 Jan '13
Signed-off-by: Yoichi Yuasa <yuasa(a)linux-mips.org>
---
sound/soc/codecs/Kconfig | 6 ++++++
sound/soc/codecs/Makefile | 1 +
sound/soc/codecs/ymu831/Makefile | 3 +++
3 files changed, 10 insertions(+)
create mode 100644 sound/soc/codecs/ymu831/Makefile
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3a84782..bb405b87 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -122,6 +122,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
select SND_SOC_WM9713 if SND_SOC_AC97_BUS
+ select SND_SOC_YMU831 if SPI_MASTER
help
Normally ASoC codec drivers are only built if a machine driver which
uses them is also built since they are only usable with a machine
@@ -494,6 +495,11 @@ config SND_SOC_WM9712
config SND_SOC_WM9713
tristate
+config SND_SOC_YMU831
+ tristate
+ select SND_HWDEP
+
+
# Amp
config SND_SOC_LM4857
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f6e8e36..1d31783 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -236,6 +236,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_YMU831) += ymu831/
# Amp
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
diff --git a/sound/soc/codecs/ymu831/Makefile b/sound/soc/codecs/ymu831/Makefile
new file mode 100644
index 0000000..5b3f66d
--- /dev/null
+++ b/sound/soc/codecs/ymu831/Makefile
@@ -0,0 +1,3 @@
+snd-soc-ymu831-objs := \
+
+obj-$(CONFIG_SND_SOC_YMU831) += snd-soc-ymu831.o
--
1.7.9.5
3
41
v2 of the Tegra AC97 series. Unmerged ASoC related patches only.
The machine driver now instantiates the codec driver by itself,
without usage of DT. Other fixups for review feedback also included.
I'll post a patch for the AC97 clock once Prashant patches land
in a branch.
Lucas Stach (3):
ASoC: tegra: add ac97 host driver
ASoC: tegra: add ac97 host controller to device tree
ASoC: tegra: add tegra machine driver using wm9712 codec
.../bindings/sound/nvidia,tegra-audio-wm9712.txt | 51 +++
.../bindings/sound/nvidia,tegra20-ac97.txt | 22 +
arch/arm/boot/dts/tegra20.dtsi | 9 +
sound/soc/tegra/Kconfig | 19 +
sound/soc/tegra/Makefile | 4 +
sound/soc/tegra/tegra20_ac97.c | 480 +++++++++++++++++++++
sound/soc/tegra/tegra20_ac97.h | 95 ++++
sound/soc/tegra/tegra_wm9712.c | 179 ++++++++
8 files changed, 859 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt
create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt
create mode 100644 sound/soc/tegra/tegra20_ac97.c
create mode 100644 sound/soc/tegra/tegra20_ac97.h
create mode 100644 sound/soc/tegra/tegra_wm9712.c
--
1.8.0.1
3
13
[alsa-devel] [PATCH alsa-utils] speaker-test: increase the maximum supported rate to 384000
by Antonio Ospite 17 Jan '13
by Antonio Ospite 17 Jan '13
17 Jan '13
There are some devices around supporting this sample rate so let's make
speaker-test capable to deal with them.
Signed-off-by: Antonio Ospite <ao2(a)amarulasolutions.com>
---
speaker-test/speaker-test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
index 3c89c38..de42a0c 100644
--- a/speaker-test/speaker-test.c
+++ b/speaker-test/speaker-test.c
@@ -999,7 +999,7 @@ int main(int argc, char *argv[]) {
case 'r':
rate = atoi(optarg);
rate = rate < 4000 ? 4000 : rate;
- rate = rate > 196000 ? 196000 : rate;
+ rate = rate > 384000 ? 384000 : rate;
break;
case 'c':
channels = atoi(optarg);
--
1.7.10.4
2
1
[alsa-devel] [PATCH] ASoC: arizona: Use actual rather than desired BCLK when calculating LRCLK
by Mark Brown 17 Jan '13
by Mark Brown 17 Jan '13
17 Jan '13
Otherwise we'll get the wrong LRCLK if we need to pick a higher BCLK than
is required.
Signed-off-by: Mark Brown <broonie(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/arizona.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index c3592db..ef62c43 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -685,7 +685,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
}
sr_val = i;
- lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
+ lrclk = rates[bclk] / params_rate(params);
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
rates[bclk], rates[bclk] / lrclk);
--
1.7.10.4
1
0
[alsa-devel] [PATCH v3 1/1] ALSA: hda - bug fix for invalid connection list of Haswell HDMI codec pins
by mengdong.lin@intel.com 17 Jan '13
by mengdong.lin@intel.com 17 Jan '13
17 Jan '13
From: Mengdong Lin <mengdong.lin(a)intel.com>
Haswell HDMI codec pins may report invalid connection list entries, which
will cause failure to play audio via HDMI or Display Port.
So this patch adds fixup for Haswell to workaround this hardware issue:
enable DP1.2 mode and override the pins' connection list entries with proper
value.
Signed-off-by: Mengdong Lin <mengdong.lin(a)intel.com>
Signed-off-by: Xingchao Wang <xingchao.wang(a)intel.com>
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 71555cc..59abe73 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1687,6 +1687,30 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
.unsol_event = hdmi_unsol_event,
};
+static void intel_haswell_fixup_connect_list(struct hda_codec *codec)
+{
+ unsigned int vendor_param;
+ hda_nid_t list[3] = {0x2, 0x3, 0x4};
+
+ vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
+ if (vendor_param == -1 || vendor_param & 0x02)
+ return;
+
+ /* enable DP1.2 mode */
+ vendor_param |= 0x02;
+ snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param);
+
+ vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
+ if (vendor_param == -1 || !(vendor_param & 0x02))
+ return;
+
+ /* override 3 pins connection list */
+ snd_hda_override_conn_list(codec, 0x05, 3, list);
+ snd_hda_override_conn_list(codec, 0x06, 3, list);
+ snd_hda_override_conn_list(codec, 0x07, 3, list);
+}
+
+
static int patch_generic_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
@@ -1696,6 +1720,10 @@ static int patch_generic_hdmi(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
+
+ if (codec->vendor_id == 0x80862807)
+ intel_haswell_fixup_connect_list(codec);
+
if (hdmi_parse_codec(codec) < 0) {
codec->spec = NULL;
kfree(spec);
--
1.7.9.5
4
5