[ALSA] hda-codec - Fix connection list parsing
Modules: HDA Codec driver,HDA generic driver - Fix connection list parsing (with ranged flag). - Increase the max number of connections - Introduce widget capabilities cache - Power up/down widgets at init, suspend and resume Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
1b98ea4791
commit
54d1740315
|
@ -155,8 +155,9 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||||
hda_nid_t *conn_list, int max_conns)
|
hda_nid_t *conn_list, int max_conns)
|
||||||
{
|
{
|
||||||
unsigned int parm;
|
unsigned int parm;
|
||||||
int i, j, conn_len, num_tupples, conns;
|
int i, conn_len, conns;
|
||||||
unsigned int shift, num_elems, mask;
|
unsigned int shift, num_elems, mask;
|
||||||
|
hda_nid_t prev_nid;
|
||||||
|
|
||||||
snd_assert(conn_list && max_conns > 0, return -EINVAL);
|
snd_assert(conn_list && max_conns > 0, return -EINVAL);
|
||||||
|
|
||||||
|
@ -171,7 +172,6 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||||
num_elems = 4;
|
num_elems = 4;
|
||||||
}
|
}
|
||||||
conn_len = parm & AC_CLIST_LENGTH;
|
conn_len = parm & AC_CLIST_LENGTH;
|
||||||
num_tupples = num_elems / 2;
|
|
||||||
mask = (1 << (shift-1)) - 1;
|
mask = (1 << (shift-1)) - 1;
|
||||||
|
|
||||||
if (! conn_len)
|
if (! conn_len)
|
||||||
|
@ -186,40 +186,38 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
|
||||||
/* multi connection */
|
/* multi connection */
|
||||||
conns = 0;
|
conns = 0;
|
||||||
for (i = 0; i < conn_len; i += num_elems) {
|
prev_nid = 0;
|
||||||
parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, i);
|
for (i = 0; i < conn_len; i++) {
|
||||||
for (j = 0; j < num_tupples; j++) {
|
int range_val;
|
||||||
int range_val;
|
hda_nid_t val, n;
|
||||||
hda_nid_t val1, val2, n;
|
|
||||||
range_val = parm & (1 << (shift-1)); /* ranges */
|
if (i % num_elems == 0)
|
||||||
val1 = parm & mask;
|
parm = snd_hda_codec_read(codec, nid, 0,
|
||||||
parm >>= shift;
|
AC_VERB_GET_CONNECT_LIST, i);
|
||||||
val2 = parm & mask;
|
range_val = !! (parm & (1 << (shift-1))); /* ranges */
|
||||||
parm >>= shift;
|
val = parm & mask;
|
||||||
if (range_val) {
|
parm >>= shift;
|
||||||
/* ranges between val1 and val2 */
|
if (range_val) {
|
||||||
if (val1 > val2) {
|
/* ranges between the previous and this one */
|
||||||
snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", val1, val2);
|
if (! prev_nid || prev_nid >= val) {
|
||||||
continue;
|
snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", prev_nid, val);
|
||||||
}
|
continue;
|
||||||
for (n = val1; n <= val2; n++) {
|
|
||||||
if (conns >= max_conns)
|
|
||||||
return -EINVAL;
|
|
||||||
conn_list[conns++] = n;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (! val1)
|
|
||||||
break;
|
|
||||||
if (conns >= max_conns)
|
|
||||||
return -EINVAL;
|
|
||||||
conn_list[conns++] = val1;
|
|
||||||
if (! val2)
|
|
||||||
break;
|
|
||||||
if (conns >= max_conns)
|
|
||||||
return -EINVAL;
|
|
||||||
conn_list[conns++] = val2;
|
|
||||||
}
|
}
|
||||||
|
for (n = prev_nid + 1; n <= val; n++) {
|
||||||
|
if (conns >= max_conns) {
|
||||||
|
snd_printk(KERN_ERR "Too many connections\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
conn_list[conns++] = n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (conns >= max_conns) {
|
||||||
|
snd_printk(KERN_ERR "Too many connections\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
conn_list[conns++] = val;
|
||||||
}
|
}
|
||||||
|
prev_nid = val;
|
||||||
}
|
}
|
||||||
return conns;
|
return conns;
|
||||||
}
|
}
|
||||||
|
@ -455,6 +453,27 @@ static void setup_fg_nodes(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read widget caps for each widget and store in cache
|
||||||
|
*/
|
||||||
|
static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
hda_nid_t nid;
|
||||||
|
|
||||||
|
codec->num_nodes = snd_hda_get_sub_nodes(codec, fg_node,
|
||||||
|
&codec->start_nid);
|
||||||
|
codec->wcaps = kmalloc(codec->num_nodes * 4, GFP_KERNEL);
|
||||||
|
if (! codec->wcaps)
|
||||||
|
return -ENOMEM;
|
||||||
|
nid = codec->start_nid;
|
||||||
|
for (i = 0; i < codec->num_nodes; i++, nid++)
|
||||||
|
codec->wcaps[i] = snd_hda_param_read(codec, nid,
|
||||||
|
AC_PAR_AUDIO_WIDGET_CAP);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* codec destructor
|
* codec destructor
|
||||||
*/
|
*/
|
||||||
|
@ -467,6 +486,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||||
if (codec->patch_ops.free)
|
if (codec->patch_ops.free)
|
||||||
codec->patch_ops.free(codec);
|
codec->patch_ops.free(codec);
|
||||||
kfree(codec->amp_info);
|
kfree(codec->amp_info);
|
||||||
|
kfree(codec->wcaps);
|
||||||
kfree(codec);
|
kfree(codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +540,12 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) {
|
||||||
|
snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
|
||||||
|
snd_hda_codec_free(codec);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
if (! codec->subsystem_id) {
|
if (! codec->subsystem_id) {
|
||||||
hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
|
hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
|
||||||
codec->subsystem_id = snd_hda_codec_read(codec, nid, 0,
|
codec->subsystem_id = snd_hda_codec_read(codec, nid, 0,
|
||||||
|
@ -647,7 +673,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
|
||||||
if (! info)
|
if (! info)
|
||||||
return 0;
|
return 0;
|
||||||
if (! (info->status & INFO_AMP_CAPS)) {
|
if (! (info->status & INFO_AMP_CAPS)) {
|
||||||
if (!(snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_AMP_OVRD))
|
if (! (get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
|
||||||
nid = codec->afg;
|
nid = codec->afg;
|
||||||
info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ?
|
info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ?
|
||||||
AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
|
AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
|
||||||
|
@ -1195,6 +1221,31 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set power state of the codec
|
||||||
|
*/
|
||||||
|
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||||
|
unsigned int power_state)
|
||||||
|
{
|
||||||
|
hda_nid_t nid, nid_start;
|
||||||
|
int nodes;
|
||||||
|
|
||||||
|
snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
|
||||||
|
power_state);
|
||||||
|
|
||||||
|
nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start);
|
||||||
|
for (nid = nid_start; nid < nodes + nid_start; nid++) {
|
||||||
|
if (get_wcaps(codec, nid) & AC_WCAP_POWER)
|
||||||
|
snd_hda_codec_write(codec, nid, 0,
|
||||||
|
AC_VERB_SET_POWER_STATE,
|
||||||
|
power_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (power_state == AC_PWRST_D0)
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_hda_build_controls - build mixer controls
|
* snd_hda_build_controls - build mixer controls
|
||||||
* @bus: the BUS
|
* @bus: the BUS
|
||||||
|
@ -1222,6 +1273,9 @@ int snd_hda_build_controls(struct hda_bus *bus)
|
||||||
list_for_each(p, &bus->codec_list) {
|
list_for_each(p, &bus->codec_list) {
|
||||||
struct hda_codec *codec = list_entry(p, struct hda_codec, list);
|
struct hda_codec *codec = list_entry(p, struct hda_codec, list);
|
||||||
int err;
|
int err;
|
||||||
|
hda_set_power_state(codec,
|
||||||
|
codec->afg ? codec->afg : codec->mfg,
|
||||||
|
AC_PWRST_D0);
|
||||||
if (! codec->patch_ops.init)
|
if (! codec->patch_ops.init)
|
||||||
continue;
|
continue;
|
||||||
err = codec->patch_ops.init(codec);
|
err = codec->patch_ops.init(codec);
|
||||||
|
@ -1340,7 +1394,7 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
|
||||||
val = 0;
|
val = 0;
|
||||||
if (nid != codec->afg &&
|
if (nid != codec->afg &&
|
||||||
snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
|
(get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
|
||||||
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
||||||
if (val == -1)
|
if (val == -1)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -1362,7 +1416,7 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||||
unsigned int bps;
|
unsigned int bps;
|
||||||
unsigned int wcaps;
|
unsigned int wcaps;
|
||||||
|
|
||||||
wcaps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
|
wcaps = get_wcaps(codec, nid);
|
||||||
streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
|
streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
|
||||||
if (streams == -1)
|
if (streams == -1)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -1432,7 +1486,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
|
||||||
unsigned int val = 0, rate, stream;
|
unsigned int val = 0, rate, stream;
|
||||||
|
|
||||||
if (nid != codec->afg &&
|
if (nid != codec->afg &&
|
||||||
snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
|
(get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
|
||||||
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
||||||
if (val == -1)
|
if (val == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1658,9 +1712,21 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (; knew->name; knew++) {
|
for (; knew->name; knew++) {
|
||||||
err = snd_ctl_add(codec->bus->card, snd_ctl_new1(knew, codec));
|
struct snd_kcontrol *kctl;
|
||||||
if (err < 0)
|
kctl = snd_ctl_new1(knew, codec);
|
||||||
return err;
|
if (! kctl)
|
||||||
|
return -ENOMEM;
|
||||||
|
err = snd_ctl_add(codec->bus->card, kctl);
|
||||||
|
if (err < 0) {
|
||||||
|
if (! codec->addr)
|
||||||
|
return err;
|
||||||
|
kctl = snd_ctl_new1(knew, codec);
|
||||||
|
if (! kctl)
|
||||||
|
return -ENOMEM;
|
||||||
|
kctl->id.device = codec->addr;
|
||||||
|
if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1874,8 +1940,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
|
|
||||||
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
|
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
|
||||||
for (nid = nid_start; nid < nodes + nid_start; nid++) {
|
for (nid = nid_start; nid < nodes + nid_start; nid++) {
|
||||||
unsigned int wid_caps = snd_hda_param_read(codec, nid,
|
unsigned int wid_caps = get_wcaps(codec, nid);
|
||||||
AC_PAR_AUDIO_WIDGET_CAP);
|
|
||||||
unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
||||||
unsigned int def_conf;
|
unsigned int def_conf;
|
||||||
short assoc, loc;
|
short assoc, loc;
|
||||||
|
@ -1993,6 +2058,9 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
|
||||||
struct hda_codec *codec = list_entry(p, struct hda_codec, list);
|
struct hda_codec *codec = list_entry(p, struct hda_codec, list);
|
||||||
if (codec->patch_ops.suspend)
|
if (codec->patch_ops.suspend)
|
||||||
codec->patch_ops.suspend(codec, state);
|
codec->patch_ops.suspend(codec, state);
|
||||||
|
hda_set_power_state(codec,
|
||||||
|
codec->afg ? codec->afg : codec->mfg,
|
||||||
|
AC_PWRST_D3);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2010,6 +2078,9 @@ int snd_hda_resume(struct hda_bus *bus)
|
||||||
|
|
||||||
list_for_each(p, &bus->codec_list) {
|
list_for_each(p, &bus->codec_list) {
|
||||||
struct hda_codec *codec = list_entry(p, struct hda_codec, list);
|
struct hda_codec *codec = list_entry(p, struct hda_codec, list);
|
||||||
|
hda_set_power_state(codec,
|
||||||
|
codec->afg ? codec->afg : codec->mfg,
|
||||||
|
AC_PWRST_D0);
|
||||||
if (codec->patch_ops.resume)
|
if (codec->patch_ops.resume)
|
||||||
codec->patch_ops.resume(codec);
|
codec->patch_ops.resume(codec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,12 @@ enum {
|
||||||
#define AC_PWRST_D2SUP (1<<2)
|
#define AC_PWRST_D2SUP (1<<2)
|
||||||
#define AC_PWRST_D3SUP (1<<3)
|
#define AC_PWRST_D3SUP (1<<3)
|
||||||
|
|
||||||
|
/* Power state values */
|
||||||
|
#define AC_PWRST_D0 0x00
|
||||||
|
#define AC_PWRST_D1 0x01
|
||||||
|
#define AC_PWRST_D2 0x02
|
||||||
|
#define AC_PWRST_D3 0x03
|
||||||
|
|
||||||
/* Processing capabilies */
|
/* Processing capabilies */
|
||||||
#define AC_PCAP_BENIGN (1<<0)
|
#define AC_PCAP_BENIGN (1<<0)
|
||||||
#define AC_PCAP_NUM_COEF (0xff<<8)
|
#define AC_PCAP_NUM_COEF (0xff<<8)
|
||||||
|
@ -376,7 +382,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* max. connections to a widget */
|
/* max. connections to a widget */
|
||||||
#define HDA_MAX_CONNECTIONS 16
|
#define HDA_MAX_CONNECTIONS 32
|
||||||
|
|
||||||
/* max. codec address */
|
/* max. codec address */
|
||||||
#define HDA_MAX_CODEC_ADDRESS 0x0f
|
#define HDA_MAX_CODEC_ADDRESS 0x0f
|
||||||
|
@ -542,6 +548,11 @@ struct hda_codec {
|
||||||
/* codec specific info */
|
/* codec specific info */
|
||||||
void *spec;
|
void *spec;
|
||||||
|
|
||||||
|
/* widget capabilities cache */
|
||||||
|
unsigned int num_nodes;
|
||||||
|
hda_nid_t start_nid;
|
||||||
|
u32 *wcaps;
|
||||||
|
|
||||||
/* hash for amp access */
|
/* hash for amp access */
|
||||||
u16 amp_hash[32];
|
u16 amp_hash[32];
|
||||||
int num_amp_entries;
|
int num_amp_entries;
|
||||||
|
|
|
@ -87,7 +87,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
|
||||||
/*
|
/*
|
||||||
* input MUX helper
|
* input MUX helper
|
||||||
*/
|
*/
|
||||||
#define HDA_MAX_NUM_INPUTS 8
|
#define HDA_MAX_NUM_INPUTS 16
|
||||||
struct hda_input_mux_item {
|
struct hda_input_mux_item {
|
||||||
const char *label;
|
const char *label;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
@ -243,4 +243,16 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
|
||||||
#define PIN_HP 0xc0
|
#define PIN_HP 0xc0
|
||||||
#define PIN_HP_AMP 0x80
|
#define PIN_HP_AMP 0x80
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get widget capabilities
|
||||||
|
*/
|
||||||
|
static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
if (nid < codec->start_nid ||
|
||||||
|
nid >= codec->start_nid + codec->num_nodes)
|
||||||
|
return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
|
||||||
|
return codec->wcaps[nid - codec->start_nid];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* __SOUND_HDA_LOCAL_H */
|
#endif /* __SOUND_HDA_LOCAL_H */
|
||||||
|
|
|
@ -2091,8 +2091,7 @@ static int patch_alc880(struct hda_codec *codec)
|
||||||
|
|
||||||
if (! spec->adc_nids && spec->input_mux) {
|
if (! spec->adc_nids && spec->input_mux) {
|
||||||
/* check whether NID 0x07 is valid */
|
/* check whether NID 0x07 is valid */
|
||||||
unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0],
|
unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
|
||||||
AC_PAR_AUDIO_WIDGET_CAP);
|
|
||||||
wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
|
wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
|
||||||
if (wcap != AC_WID_AUD_IN) {
|
if (wcap != AC_WID_AUD_IN) {
|
||||||
spec->adc_nids = alc880_adc_nids_alt;
|
spec->adc_nids = alc880_adc_nids_alt;
|
||||||
|
|
|
@ -624,7 +624,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
|
||||||
if (! pin)
|
if (! pin)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP);
|
wid_caps = get_wcaps(codec, pin);
|
||||||
if (wid_caps & AC_WCAP_UNSOL_CAP)
|
if (wid_caps & AC_WCAP_UNSOL_CAP)
|
||||||
/* Enable unsolicited responses on the HP widget */
|
/* Enable unsolicited responses on the HP widget */
|
||||||
snd_hda_codec_write(codec, pin, 0,
|
snd_hda_codec_write(codec, pin, 0,
|
||||||
|
@ -786,33 +786,10 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stac92xx_init_pstate(struct hda_codec *codec)
|
|
||||||
{
|
|
||||||
hda_nid_t nid, nid_start;
|
|
||||||
int nodes;
|
|
||||||
|
|
||||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_POWER_STATE, 0x00);
|
|
||||||
|
|
||||||
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
|
|
||||||
for (nid = nid_start; nid < nodes + nid_start; nid++) {
|
|
||||||
unsigned int wid_caps = snd_hda_param_read(codec, nid,
|
|
||||||
AC_PAR_AUDIO_WIDGET_CAP);
|
|
||||||
if (wid_caps & AC_WCAP_POWER)
|
|
||||||
snd_hda_codec_write(codec, nid, 0,
|
|
||||||
AC_VERB_SET_POWER_STATE, 0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
mdelay(100);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stac92xx_init(struct hda_codec *codec)
|
static int stac92xx_init(struct hda_codec *codec)
|
||||||
{
|
{
|
||||||
struct sigmatel_spec *spec = codec->spec;
|
struct sigmatel_spec *spec = codec->spec;
|
||||||
|
|
||||||
stac92xx_init_pstate(codec);
|
|
||||||
|
|
||||||
snd_hda_sequence_write(codec, spec->init);
|
snd_hda_sequence_write(codec, spec->init);
|
||||||
|
|
||||||
stac92xx_auto_init_multi_out(codec);
|
stac92xx_auto_init_multi_out(codec);
|
||||||
|
|
Loading…
Reference in New Issue