Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: hdac_hdmi: Add jack reporting

Jack is created based on pcm devices enumerated, so we will
create Jack as "HDMI/DP, pcm=x Jack". This style is expected by
current usermode like PulseAudio and CRAS.

This patch exports an API which can be used to register Jack
based on PCM. This API also establishes the map between PCM and
cvt. Further cvt to pin mapping is established with the help of
usermode selection based on the board topology.

During device probe as the PCMs may not be registered, initial
pin sense don't report jack events. So, first time jack reporting
is done during user selection of mux control.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Jeeja KP and committed by
Mark Brown
4a3478de 79f4e922

+163 -3
+157 -3
sound/soc/codecs/hdac_hdmi.c
··· 24 24 #include <linux/hdmi.h> 25 25 #include <drm/drm_edid.h> 26 26 #include <sound/pcm_params.h> 27 + #include <sound/jack.h> 27 28 #include <sound/soc.h> 28 29 #include <sound/hdaudio_ext.h> 29 30 #include <sound/hda_i915.h> 30 31 #include <sound/pcm_drm_eld.h> 31 32 #include "../../hda/local.h" 33 + #include "hdac_hdmi.h" 32 34 33 35 #define NAME_SIZE 32 34 36 ··· 54 52 struct hdac_hdmi_cvt { 55 53 struct list_head head; 56 54 hda_nid_t nid; 55 + const char *name; 57 56 struct hdac_hdmi_cvt_params params; 58 57 }; 59 58 ··· 76 73 struct delayed_work work; 77 74 }; 78 75 76 + struct hdac_hdmi_pcm { 77 + struct list_head head; 78 + int pcm_id; 79 + struct hdac_hdmi_pin *pin; 80 + struct hdac_hdmi_cvt *cvt; 81 + struct snd_jack *jack; 82 + }; 83 + 79 84 struct hdac_hdmi_dai_pin_map { 80 85 int dai_id; 81 86 struct hdac_hdmi_pin *pin; ··· 94 83 struct hdac_hdmi_dai_pin_map dai_map[3]; 95 84 struct list_head pin_list; 96 85 struct list_head cvt_list; 86 + struct list_head pcm_list; 97 87 int num_pin; 98 88 int num_cvt; 89 + struct mutex pin_mutex; 99 90 }; 100 91 101 92 static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) ··· 491 478 route->connected = handler; 492 479 } 493 480 481 + static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, 482 + struct hdac_hdmi_pin *pin) 483 + { 484 + struct hdac_hdmi_priv *hdmi = edev->private_data; 485 + struct hdac_hdmi_pcm *pcm = NULL; 486 + 487 + list_for_each_entry(pcm, &hdmi->pcm_list, head) { 488 + if (pcm->pin == pin) 489 + return pcm; 490 + } 491 + 492 + return NULL; 493 + } 494 + 495 + /* 496 + * Based on user selection, map the PINs with the PCMs. 497 + */ 498 + static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, 499 + struct snd_ctl_elem_value *ucontrol) 500 + { 501 + int ret; 502 + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 503 + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 504 + struct snd_soc_dapm_context *dapm = w->dapm; 505 + struct hdac_hdmi_pin *pin = w->priv; 506 + struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 507 + struct hdac_hdmi_priv *hdmi = edev->private_data; 508 + struct hdac_hdmi_pcm *pcm = NULL; 509 + const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; 510 + 511 + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); 512 + if (ret < 0) 513 + return ret; 514 + 515 + mutex_lock(&hdmi->pin_mutex); 516 + list_for_each_entry(pcm, &hdmi->pcm_list, head) { 517 + if (pcm->pin == pin) 518 + pcm->pin = NULL; 519 + 520 + /* 521 + * Jack status is not reported during device probe as the 522 + * PCMs are not registered by then. So report it here. 523 + */ 524 + if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { 525 + pcm->pin = pin; 526 + if (pin->eld.monitor_present && pin->eld.eld_valid) { 527 + dev_dbg(&edev->hdac.dev, 528 + "jack report for pcm=%d\n", 529 + pcm->pcm_id); 530 + 531 + snd_jack_report(pcm->jack, SND_JACK_AVOUT); 532 + } 533 + mutex_unlock(&hdmi->pin_mutex); 534 + return ret; 535 + } 536 + } 537 + mutex_unlock(&hdmi->pin_mutex); 538 + 539 + return ret; 540 + } 541 + 494 542 /* 495 543 * Ideally the Mux inputs should be based on the num_muxs enumerated, but 496 544 * the display driver seem to be programming the connection list for the pin ··· 594 520 kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 595 521 kc->access = 0; 596 522 kc->info = snd_soc_info_enum_double; 597 - kc->put = snd_soc_dapm_put_enum_double; 523 + kc->put = hdac_hdmi_set_pin_mux; 598 524 kc->get = snd_soc_dapm_get_enum_double; 599 525 600 526 se->reg = SND_SOC_NOPM; ··· 622 548 return -ENOMEM; 623 549 624 550 return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, 625 - snd_soc_dapm_mux, &pin->nid, widget_name, 626 - NULL, kc, 1); 551 + snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1); 627 552 } 628 553 629 554 /* Add cvt <- input <- mux route map */ ··· 801 728 { 802 729 struct hdac_hdmi_priv *hdmi = edev->private_data; 803 730 struct hdac_hdmi_cvt *cvt; 731 + char name[NAME_SIZE]; 804 732 805 733 cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); 806 734 if (!cvt) 807 735 return -ENOMEM; 808 736 809 737 cvt->nid = nid; 738 + sprintf(name, "cvt %d", cvt->nid); 739 + cvt->name = kstrdup(name, GFP_KERNEL); 810 740 811 741 list_add_tail(&cvt->head, &hdmi->cvt_list); 812 742 hdmi->num_cvt++; ··· 820 744 static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) 821 745 { 822 746 struct hdac_ext_device *edev = pin->edev; 747 + struct hdac_hdmi_priv *hdmi = edev->private_data; 748 + struct hdac_hdmi_pcm *pcm; 823 749 int val; 824 750 825 751 if (!edev) ··· 836 758 dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", 837 759 val, pin->nid); 838 760 761 + 762 + mutex_lock(&hdmi->pin_mutex); 839 763 pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); 840 764 pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); 765 + 766 + pcm = hdac_hdmi_get_pcm(edev, pin); 841 767 842 768 if (!pin->eld.monitor_present || !pin->eld.eld_valid) { 843 769 844 770 dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", 845 771 __func__, pin->nid); 772 + 773 + /* 774 + * PCMs are not registered during device probe, so don't 775 + * report jack here. It will be done in usermode mux 776 + * control select. 777 + */ 778 + if (pcm) { 779 + dev_dbg(&edev->hdac.dev, 780 + "jack report for pcm=%d\n", pcm->pcm_id); 781 + 782 + snd_jack_report(pcm->jack, 0); 783 + } 784 + 785 + mutex_unlock(&hdmi->pin_mutex); 846 786 goto put_hdac_device; 847 787 } 848 788 ··· 870 774 pin->eld.eld_buffer, 871 775 &pin->eld.eld_size) == 0) { 872 776 777 + if (pcm) { 778 + dev_dbg(&edev->hdac.dev, 779 + "jack report for pcm=%d\n", 780 + pcm->pcm_id); 781 + 782 + snd_jack_report(pcm->jack, SND_JACK_AVOUT); 783 + } 784 + 873 785 print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, 874 786 pin->eld.eld_buffer, pin->eld.eld_size); 875 787 } else { 876 788 pin->eld.monitor_present = false; 877 789 pin->eld.eld_valid = false; 790 + 791 + if (pcm) { 792 + dev_dbg(&edev->hdac.dev, 793 + "jack report for pcm=%d\n", 794 + pcm->pcm_id); 795 + 796 + snd_jack_report(pcm->jack, 0); 797 + } 878 798 } 879 799 } 800 + 801 + mutex_unlock(&hdmi->pin_mutex); 880 802 881 803 /* 882 804 * Sometimes the pin_sense may present invalid monitor ··· 1153 1039 .pin_eld_notify = hdac_hdmi_eld_notify_cb, 1154 1040 }; 1155 1041 1042 + int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) 1043 + { 1044 + char jack_name[NAME_SIZE]; 1045 + struct snd_soc_codec *codec = dai->codec; 1046 + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 1047 + struct snd_soc_dapm_context *dapm = 1048 + snd_soc_component_get_dapm(&codec->component); 1049 + struct hdac_hdmi_priv *hdmi = edev->private_data; 1050 + struct hdac_hdmi_pcm *pcm; 1051 + 1052 + /* 1053 + * this is a new PCM device, create new pcm and 1054 + * add to the pcm list 1055 + */ 1056 + pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); 1057 + if (!pcm) 1058 + return -ENOMEM; 1059 + pcm->pcm_id = device; 1060 + pcm->cvt = hdmi->dai_map[dai->id].cvt; 1061 + 1062 + list_add_tail(&pcm->head, &hdmi->pcm_list); 1063 + 1064 + sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); 1065 + 1066 + return snd_jack_new(dapm->card->snd_card, jack_name, 1067 + SND_JACK_AVOUT, &pcm->jack, true, false); 1068 + } 1069 + EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); 1070 + 1156 1071 static int hdmi_codec_probe(struct snd_soc_codec *codec) 1157 1072 { 1158 1073 struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); ··· 1254 1111 1255 1112 INIT_LIST_HEAD(&hdmi_priv->pin_list); 1256 1113 INIT_LIST_HEAD(&hdmi_priv->cvt_list); 1114 + INIT_LIST_HEAD(&hdmi_priv->pcm_list); 1115 + mutex_init(&hdmi_priv->pin_mutex); 1257 1116 1258 1117 ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); 1259 1118 if (ret < 0) { ··· 1274 1129 struct hdac_hdmi_priv *hdmi = edev->private_data; 1275 1130 struct hdac_hdmi_pin *pin, *pin_next; 1276 1131 struct hdac_hdmi_cvt *cvt, *cvt_next; 1132 + struct hdac_hdmi_pcm *pcm, *pcm_next; 1277 1133 1278 1134 snd_soc_unregister_codec(&edev->hdac.dev); 1279 1135 1136 + list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { 1137 + pcm->cvt = NULL; 1138 + pcm->pin = NULL; 1139 + list_del(&pcm->head); 1140 + kfree(pcm); 1141 + } 1142 + 1280 1143 list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { 1281 1144 list_del(&cvt->head); 1145 + kfree(cvt->name); 1282 1146 kfree(cvt); 1283 1147 } 1284 1148
+6
sound/soc/codecs/hdac_hdmi.h
··· 1 + #ifndef __HDAC_HDMI_H__ 2 + #define __HDAC_HDMI_H__ 3 + 4 + int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm); 5 + 6 + #endif /* __HDAC_HDMI_H__ */