aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c83
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
1212static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
1213 hda_nid_t fg, unsigned int power_state);
1214
1212static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 1215static 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}
1387EXPORT_SYMBOL_HDA(snd_hda_codec_configure); 1394EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
1388 1395
1396/* update the stream-id if changed */
1397static 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 */
1416static 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 }