diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 83 |
1 files changed, 56 insertions, 27 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 88a9c20eb7a2..f25c24c743f9 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1209,6 +1209,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
1209 | kfree(codec); | 1209 | kfree(codec); |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, | ||
1213 | hda_nid_t fg, unsigned int power_state); | ||
1214 | |||
1212 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | 1215 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, |
1213 | unsigned int power_state); | 1216 | unsigned int power_state); |
1214 | 1217 | ||
@@ -1317,6 +1320,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, | |||
1317 | AC_VERB_GET_SUBSYSTEM_ID, 0); | 1320 | AC_VERB_GET_SUBSYSTEM_ID, 0); |
1318 | } | 1321 | } |
1319 | 1322 | ||
1323 | codec->epss = snd_hda_codec_get_supported_ps(codec, | ||
1324 | codec->afg ? codec->afg : codec->mfg, | ||
1325 | AC_PWRST_EPSS); | ||
1326 | |||
1320 | /* power-up all before initialization */ | 1327 | /* power-up all before initialization */ |
1321 | hda_set_power_state(codec, | 1328 | hda_set_power_state(codec, |
1322 | codec->afg ? codec->afg : codec->mfg, | 1329 | codec->afg ? codec->afg : codec->mfg, |
@@ -1386,6 +1393,44 @@ int snd_hda_codec_configure(struct hda_codec *codec) | |||
1386 | } | 1393 | } |
1387 | EXPORT_SYMBOL_HDA(snd_hda_codec_configure); | 1394 | EXPORT_SYMBOL_HDA(snd_hda_codec_configure); |
1388 | 1395 | ||
1396 | /* update the stream-id if changed */ | ||
1397 | static void update_pcm_stream_id(struct hda_codec *codec, | ||
1398 | struct hda_cvt_setup *p, hda_nid_t nid, | ||
1399 | u32 stream_tag, int channel_id) | ||
1400 | { | ||
1401 | unsigned int oldval, newval; | ||
1402 | |||
1403 | if (p->stream_tag != stream_tag || p->channel_id != channel_id) { | ||
1404 | oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
1405 | newval = (stream_tag << 4) | channel_id; | ||
1406 | if (oldval != newval) | ||
1407 | snd_hda_codec_write(codec, nid, 0, | ||
1408 | AC_VERB_SET_CHANNEL_STREAMID, | ||
1409 | newval); | ||
1410 | p->stream_tag = stream_tag; | ||
1411 | p->channel_id = channel_id; | ||
1412 | } | ||
1413 | } | ||
1414 | |||
1415 | /* update the format-id if changed */ | ||
1416 | static void update_pcm_format(struct hda_codec *codec, struct hda_cvt_setup *p, | ||
1417 | hda_nid_t nid, int format) | ||
1418 | { | ||
1419 | unsigned int oldval; | ||
1420 | |||
1421 | if (p->format_id != format) { | ||
1422 | oldval = snd_hda_codec_read(codec, nid, 0, | ||
1423 | AC_VERB_GET_STREAM_FORMAT, 0); | ||
1424 | if (oldval != format) { | ||
1425 | msleep(1); | ||
1426 | snd_hda_codec_write(codec, nid, 0, | ||
1427 | AC_VERB_SET_STREAM_FORMAT, | ||
1428 | format); | ||
1429 | } | ||
1430 | p->format_id = format; | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1389 | /** | 1434 | /** |
1390 | * snd_hda_codec_setup_stream - set up the codec for streaming | 1435 | * snd_hda_codec_setup_stream - set up the codec for streaming |
1391 | * @codec: the CODEC to set up | 1436 | * @codec: the CODEC to set up |
@@ -1400,7 +1445,6 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | |||
1400 | { | 1445 | { |
1401 | struct hda_codec *c; | 1446 | struct hda_codec *c; |
1402 | struct hda_cvt_setup *p; | 1447 | struct hda_cvt_setup *p; |
1403 | unsigned int oldval, newval; | ||
1404 | int type; | 1448 | int type; |
1405 | int i; | 1449 | int i; |
1406 | 1450 | ||
@@ -1413,29 +1457,13 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | |||
1413 | p = get_hda_cvt_setup(codec, nid); | 1457 | p = get_hda_cvt_setup(codec, nid); |
1414 | if (!p) | 1458 | if (!p) |
1415 | return; | 1459 | return; |
1416 | /* update the stream-id if changed */ | 1460 | |
1417 | if (p->stream_tag != stream_tag || p->channel_id != channel_id) { | 1461 | if (codec->pcm_format_first) |
1418 | oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | 1462 | update_pcm_format(codec, p, nid, format); |
1419 | newval = (stream_tag << 4) | channel_id; | 1463 | update_pcm_stream_id(codec, p, nid, stream_tag, channel_id); |
1420 | if (oldval != newval) | 1464 | if (!codec->pcm_format_first) |
1421 | snd_hda_codec_write(codec, nid, 0, | 1465 | update_pcm_format(codec, p, nid, format); |
1422 | AC_VERB_SET_CHANNEL_STREAMID, | 1466 | |
1423 | newval); | ||
1424 | p->stream_tag = stream_tag; | ||
1425 | p->channel_id = channel_id; | ||
1426 | } | ||
1427 | /* update the format-id if changed */ | ||
1428 | if (p->format_id != format) { | ||
1429 | oldval = snd_hda_codec_read(codec, nid, 0, | ||
1430 | AC_VERB_GET_STREAM_FORMAT, 0); | ||
1431 | if (oldval != format) { | ||
1432 | msleep(1); | ||
1433 | snd_hda_codec_write(codec, nid, 0, | ||
1434 | AC_VERB_SET_STREAM_FORMAT, | ||
1435 | format); | ||
1436 | } | ||
1437 | p->format_id = format; | ||
1438 | } | ||
1439 | p->active = 1; | 1467 | p->active = 1; |
1440 | p->dirty = 0; | 1468 | p->dirty = 0; |
1441 | 1469 | ||
@@ -3497,7 +3525,7 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg | |||
3497 | { | 3525 | { |
3498 | int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE); | 3526 | int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE); |
3499 | 3527 | ||
3500 | if (sup < 0) | 3528 | if (sup == -1) |
3501 | return false; | 3529 | return false; |
3502 | if (sup & power_state) | 3530 | if (sup & power_state) |
3503 | return true; | 3531 | return true; |
@@ -3522,8 +3550,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
3522 | /* this delay seems necessary to avoid click noise at power-down */ | 3550 | /* this delay seems necessary to avoid click noise at power-down */ |
3523 | if (power_state == AC_PWRST_D3) { | 3551 | if (power_state == AC_PWRST_D3) { |
3524 | /* transition time less than 10ms for power down */ | 3552 | /* transition time less than 10ms for power down */ |
3525 | bool epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); | 3553 | msleep(codec->epss ? 10 : 100); |
3526 | msleep(epss ? 10 : 100); | ||
3527 | } | 3554 | } |
3528 | 3555 | ||
3529 | /* repeat power states setting at most 10 times*/ | 3556 | /* repeat power states setting at most 10 times*/ |
@@ -4433,6 +4460,8 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) | |||
4433 | * then there is no need to go through power up here. | 4460 | * then there is no need to go through power up here. |
4434 | */ | 4461 | */ |
4435 | if (codec->power_on) { | 4462 | if (codec->power_on) { |
4463 | if (codec->power_transition < 0) | ||
4464 | codec->power_transition = 0; | ||
4436 | spin_unlock(&codec->power_lock); | 4465 | spin_unlock(&codec->power_lock); |
4437 | return; | 4466 | return; |
4438 | } | 4467 | } |