aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubhransu S. Prusty <subhransu.s.prusty@intel.com>2016-02-11 21:16:07 -0500
committerMark Brown <broonie@kernel.org>2016-02-15 15:55:57 -0500
commit148569fddbc6d3ce97236c4344068b1293e51838 (patch)
tree684c73bbbef1eff6e99a2af984500f105e94492d
parent9f2f232e2e5394be04b6a636898c64509bc8d5c1 (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.c174
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
93struct hdac_hdmi_priv { 95struct 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
389static 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
418static 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 */
449static 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
387static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, 479static 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
427static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, 521static 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
442static int 538static int
@@ -759,40 +855,34 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
759static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) 855static 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}