diff options
author | Subhransu S. Prusty <subhransu.s.prusty@intel.com> | 2016-02-11 21:16:07 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-02-15 15:55:57 -0500 |
commit | 148569fddbc6d3ce97236c4344068b1293e51838 (patch) | |
tree | 684c73bbbef1eff6e99a2af984500f105e94492d | |
parent | 9f2f232e2e5394be04b6a636898c64509bc8d5c1 (diff) |
ASoC: hdac_hdmi: Enable playback on all enumerated ports
Last patch added infrastructure to render over all the ports,
PCM<->cvt<- pin mapping and user selection of controls. But we
still have restriction of playback on the default port alone, so
remove that.
This patch removes the hardcoding of cvt<->pin map from the dai.
Cvt and pin for a dai are now derived from the already stored pcm
list of device opened. We query connection list of a pin from
codec to validate the cvt<->pin map.
If connection list returns zero, then monitor is not connected so
fail playback.
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/hdac_hdmi.c | 174 |
1 files changed, 132 insertions, 42 deletions
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 839148688744..dcd1cb643145 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c | |||
@@ -40,6 +40,8 @@ | |||
40 | 40 | ||
41 | #define HDA_MAX_CONNECTIONS 32 | 41 | #define HDA_MAX_CONNECTIONS 32 |
42 | 42 | ||
43 | #define HDA_MAX_CVTS 3 | ||
44 | |||
43 | #define ELD_MAX_SIZE 256 | 45 | #define ELD_MAX_SIZE 256 |
44 | #define ELD_FIXED_BYTES 20 | 46 | #define ELD_FIXED_BYTES 20 |
45 | 47 | ||
@@ -91,7 +93,7 @@ struct hdac_hdmi_dai_pin_map { | |||
91 | }; | 93 | }; |
92 | 94 | ||
93 | struct hdac_hdmi_priv { | 95 | struct hdac_hdmi_priv { |
94 | struct hdac_hdmi_dai_pin_map dai_map[3]; | 96 | struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; |
95 | struct list_head pin_list; | 97 | struct list_head pin_list; |
96 | struct list_head cvt_list; | 98 | struct list_head cvt_list; |
97 | struct list_head pcm_list; | 99 | struct list_head pcm_list; |
@@ -384,44 +386,136 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, | |||
384 | return 0; | 386 | return 0; |
385 | } | 387 | } |
386 | 388 | ||
389 | static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, | ||
390 | struct hdac_hdmi_dai_pin_map *dai_map) | ||
391 | { | ||
392 | int mux_idx; | ||
393 | struct hdac_hdmi_pin *pin = dai_map->pin; | ||
394 | |||
395 | for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) { | ||
396 | if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) { | ||
397 | snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, | ||
398 | AC_VERB_SET_CONNECT_SEL, mux_idx); | ||
399 | break; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | if (mux_idx == pin->num_mux_nids) | ||
404 | return -EIO; | ||
405 | |||
406 | /* Enable out path for this pin widget */ | ||
407 | snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, | ||
408 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
409 | |||
410 | hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); | ||
411 | |||
412 | snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, | ||
413 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, | ||
419 | struct hdac_hdmi_pin *pin) | ||
420 | { | ||
421 | if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { | ||
422 | dev_warn(&hdac->hdac.dev, | ||
423 | "HDMI: pin %d wcaps %#x does not support connection list\n", | ||
424 | pin->nid, get_wcaps(&hdac->hdac, pin->nid)); | ||
425 | return -EINVAL; | ||
426 | } | ||
427 | |||
428 | pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, | ||
429 | pin->mux_nids, HDA_MAX_CONNECTIONS); | ||
430 | if (pin->num_mux_nids == 0) | ||
431 | dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", | ||
432 | pin->nid); | ||
433 | |||
434 | dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", | ||
435 | pin->num_mux_nids, pin->nid); | ||
436 | |||
437 | return pin->num_mux_nids; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * Query pcm list and return pin widget to which stream is routed. | ||
442 | * | ||
443 | * Also query connection list of the pin, to validate the cvt to pin map. | ||
444 | * | ||
445 | * Same stream rendering to multiple pins simultaneously can be done | ||
446 | * possibly, but not supported for now in driver. So return the first pin | ||
447 | * connected. | ||
448 | */ | ||
449 | static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( | ||
450 | struct hdac_ext_device *edev, | ||
451 | struct hdac_hdmi_priv *hdmi, | ||
452 | struct hdac_hdmi_cvt *cvt) | ||
453 | { | ||
454 | struct hdac_hdmi_pcm *pcm; | ||
455 | struct hdac_hdmi_pin *pin = NULL; | ||
456 | int ret, i; | ||
457 | |||
458 | list_for_each_entry(pcm, &hdmi->pcm_list, head) { | ||
459 | if (pcm->cvt == cvt) { | ||
460 | pin = pcm->pin; | ||
461 | break; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | if (pin) { | ||
466 | ret = hdac_hdmi_query_pin_connlist(edev, pin); | ||
467 | if (ret < 0) | ||
468 | return NULL; | ||
469 | |||
470 | for (i = 0; i < pin->num_mux_nids; i++) { | ||
471 | if (pin->mux_nids[i] == cvt->nid) | ||
472 | return pin; | ||
473 | } | ||
474 | } | ||
475 | |||
476 | return NULL; | ||
477 | } | ||
478 | |||
387 | static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, | 479 | static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, |
388 | struct snd_soc_dai *dai) | 480 | struct snd_soc_dai *dai) |
389 | { | 481 | { |
390 | struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); | 482 | struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); |
391 | struct hdac_hdmi_priv *hdmi = hdac->private_data; | 483 | struct hdac_hdmi_priv *hdmi = hdac->private_data; |
392 | struct hdac_hdmi_dai_pin_map *dai_map; | 484 | struct hdac_hdmi_dai_pin_map *dai_map; |
485 | struct hdac_hdmi_cvt *cvt; | ||
486 | struct hdac_hdmi_pin *pin; | ||
393 | int ret; | 487 | int ret; |
394 | 488 | ||
395 | if (dai->id > 0) { | ||
396 | dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); | ||
397 | return -ENODEV; | ||
398 | } | ||
399 | |||
400 | dai_map = &hdmi->dai_map[dai->id]; | 489 | dai_map = &hdmi->dai_map[dai->id]; |
401 | 490 | ||
402 | if ((!dai_map->pin->eld.monitor_present) || | 491 | cvt = dai_map->cvt; |
403 | (!dai_map->pin->eld.eld_valid)) { | 492 | pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); |
493 | if (!pin) | ||
494 | return -EIO; | ||
495 | |||
496 | if ((!pin->eld.monitor_present) || | ||
497 | (!pin->eld.eld_valid)) { | ||
404 | 498 | ||
405 | dev_err(&hdac->hdac.dev, | 499 | dev_err(&hdac->hdac.dev, |
406 | "Failed: montior present? %d ELD valid?: %d\n", | 500 | "Failed: montior present? %d ELD valid?: %d for pin: %d\n", |
407 | dai_map->pin->eld.monitor_present, | 501 | pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); |
408 | dai_map->pin->eld.eld_valid); | ||
409 | 502 | ||
410 | return -ENODEV; | 503 | return -ENODEV; |
411 | } | 504 | } |
412 | 505 | ||
413 | hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); | 506 | dai_map->pin = pin; |
414 | 507 | ||
415 | snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, | 508 | ret = hdac_hdmi_enable_pin(hdac, dai_map); |
416 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | 509 | if (ret < 0) |
510 | return ret; | ||
417 | 511 | ||
418 | ret = hdac_hdmi_eld_limit_formats(substream->runtime, | 512 | ret = hdac_hdmi_eld_limit_formats(substream->runtime, |
419 | dai_map->pin->eld.eld_buffer); | 513 | pin->eld.eld_buffer); |
420 | if (ret < 0) | 514 | if (ret < 0) |
421 | return ret; | 515 | return ret; |
422 | 516 | ||
423 | return snd_pcm_hw_constraint_eld(substream->runtime, | 517 | return snd_pcm_hw_constraint_eld(substream->runtime, |
424 | dai_map->pin->eld.eld_buffer); | 518 | pin->eld.eld_buffer); |
425 | } | 519 | } |
426 | 520 | ||
427 | static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, | 521 | static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, |
@@ -437,6 +531,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, | |||
437 | 531 | ||
438 | snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, | 532 | snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, |
439 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | 533 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); |
534 | |||
535 | dai_map->pin = NULL; | ||
440 | } | 536 | } |
441 | 537 | ||
442 | static int | 538 | static int |
@@ -759,40 +855,34 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) | |||
759 | static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) | 855 | static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) |
760 | { | 856 | { |
761 | struct hdac_hdmi_priv *hdmi = edev->private_data; | 857 | struct hdac_hdmi_priv *hdmi = edev->private_data; |
762 | struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0]; | 858 | struct hdac_hdmi_dai_pin_map *dai_map; |
763 | struct hdac_hdmi_cvt *cvt; | 859 | struct hdac_hdmi_cvt *cvt; |
764 | struct hdac_hdmi_pin *pin; | 860 | int dai_id = 0; |
765 | 861 | ||
766 | if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) | 862 | if (list_empty(&hdmi->cvt_list)) |
767 | return -EINVAL; | 863 | return -EINVAL; |
768 | 864 | ||
769 | /* | 865 | list_for_each_entry(cvt, &hdmi->cvt_list, head) { |
770 | * Currently on board only 1 pin and 1 converter is enabled for | 866 | dai_map = &hdmi->dai_map[dai_id]; |
771 | * simplification, more will be added eventually | 867 | dai_map->dai_id = dai_id; |
772 | * So using fixed map for dai_id:pin:cvt | 868 | dai_map->cvt = cvt; |
773 | */ | ||
774 | cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head); | ||
775 | pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head); | ||
776 | |||
777 | dai_map->dai_id = 0; | ||
778 | dai_map->pin = pin; | ||
779 | 869 | ||
780 | dai_map->cvt = cvt; | 870 | /* Enable transmission */ |
871 | snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, | ||
872 | AC_VERB_SET_DIGI_CONVERT_1, 1); | ||
781 | 873 | ||
782 | /* Enable out path for this pin widget */ | 874 | /* Category Code (CC) to zero */ |
783 | snd_hdac_codec_write(&edev->hdac, pin->nid, 0, | 875 | snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, |
784 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | 876 | AC_VERB_SET_DIGI_CONVERT_2, 0); |
785 | 877 | ||
786 | /* Enable transmission */ | 878 | dai_id++; |
787 | snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, | ||
788 | AC_VERB_SET_DIGI_CONVERT_1, 1); | ||
789 | 879 | ||
790 | /* Category Code (CC) to zero */ | 880 | if (dai_id == HDA_MAX_CVTS) { |
791 | snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, | 881 | dev_warn(&edev->hdac.dev, |
792 | AC_VERB_SET_DIGI_CONVERT_2, 0); | 882 | "Max dais supported: %d\n", dai_id); |
793 | 883 | break; | |
794 | snd_hdac_codec_write(&edev->hdac, pin->nid, 0, | 884 | } |
795 | AC_VERB_SET_CONNECT_SEL, 0); | 885 | } |
796 | 886 | ||
797 | return 0; | 887 | return 0; |
798 | } | 888 | } |