aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeeja KP <jeeja.kp@intel.com>2017-02-07 08:39:48 -0500
committerMark Brown <broonie@kernel.org>2017-02-16 13:55:40 -0500
commite0e5d3e5a53b3bc354c18030b78b7ebcb33e004b (patch)
tree613359fe84984c564bc8820e7ccbf00c4ffbf244
parent1b46ebd136b3ad334762d6e66b0b96b432680e50 (diff)
ASoC: hdac_hdmi: Add support for multiple ports to a PCM
Since we have the MST feature enabled and Pin-Port mux for user to select the converter routing, multiple port mapping to same converter needs to be supported. To support multiple port mapped to same converter following changes are done for this:. o Add port list to pcm, so that multiple ports can be mapped to a PCM. o Jack reporting in case where multiple port are attached to same PCM. o Change hdac_hdmi_get_port_from_cvt(), channel_map, remove functions to parse through all ports mapped to same the PCM. Signed-off-by: Jeeja KP <jeeja.kp@intel.com> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/hdac_hdmi.c168
1 files changed, 113 insertions, 55 deletions
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 6cf86a0a118c..f8b6e9f1c6f6 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -89,6 +89,7 @@ struct hdac_hdmi_pin {
89}; 89};
90 90
91struct hdac_hdmi_port { 91struct hdac_hdmi_port {
92 struct list_head head;
92 int id; 93 int id;
93 struct hdac_hdmi_pin *pin; 94 struct hdac_hdmi_pin *pin;
94 int num_mux_nids; 95 int num_mux_nids;
@@ -99,7 +100,7 @@ struct hdac_hdmi_port {
99struct hdac_hdmi_pcm { 100struct hdac_hdmi_pcm {
100 struct list_head head; 101 struct list_head head;
101 int pcm_id; 102 int pcm_id;
102 struct hdac_hdmi_port *port; 103 struct list_head port_list;
103 struct hdac_hdmi_cvt *cvt; 104 struct hdac_hdmi_cvt *cvt;
104 struct snd_jack *jack; 105 struct snd_jack *jack;
105 int stream_tag; 106 int stream_tag;
@@ -108,6 +109,7 @@ struct hdac_hdmi_pcm {
108 bool chmap_set; 109 bool chmap_set;
109 unsigned char chmap[8]; /* ALSA API channel-map */ 110 unsigned char chmap[8]; /* ALSA API channel-map */
110 struct mutex lock; 111 struct mutex lock;
112 int jack_event;
111}; 113};
112 114
113struct hdac_hdmi_dai_port_map { 115struct hdac_hdmi_dai_port_map {
@@ -142,6 +144,37 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
142 return pcm; 144 return pcm;
143} 145}
144 146
147static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
148 struct hdac_hdmi_port *port, bool is_connect)
149{
150 struct hdac_ext_device *edev = port->pin->edev;
151
152 if (is_connect) {
153 /*
154 * Report Jack connect event when a device is connected
155 * for the first time where same PCM is attached to multiple
156 * ports.
157 */
158 if (pcm->jack_event == 0) {
159 dev_dbg(&edev->hdac.dev,
160 "jack report for pcm=%d\n",
161 pcm->pcm_id);
162 snd_jack_report(pcm->jack, SND_JACK_AVOUT);
163 }
164 pcm->jack_event++;
165 } else {
166 /*
167 * Report Jack disconnect event when a device is disconnected
168 * is the only last connected device when same PCM is attached
169 * to multiple ports.
170 */
171 if (pcm->jack_event == 1)
172 snd_jack_report(pcm->jack, 0);
173 if (pcm->jack_event > 0)
174 pcm->jack_event--;
175 }
176}
177
145/* MST supported verbs */ 178/* MST supported verbs */
146/* 179/*
147 * Get the no devices that can be connected to a port on the Pin widget. 180 * Get the no devices that can be connected to a port on the Pin widget.
@@ -484,19 +517,24 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
484 517
485 list_for_each_entry(pcm, &hdmi->pcm_list, head) { 518 list_for_each_entry(pcm, &hdmi->pcm_list, head) {
486 if (pcm->cvt == cvt) { 519 if (pcm->cvt == cvt) {
487 port = pcm->port; 520 if (list_empty(&pcm->port_list))
488 break; 521 continue;
489 }
490 }
491
492 if (port) {
493 ret = hdac_hdmi_query_port_connlist(edev, port->pin, port);
494 if (ret < 0)
495 return NULL;
496 522
497 for (i = 0; i < port->num_mux_nids; i++) { 523 list_for_each_entry(port, &pcm->port_list, head) {
498 if (port->mux_nids[i] == cvt->nid) 524 mutex_lock(&pcm->lock);
499 return port; 525 ret = hdac_hdmi_query_port_connlist(edev,
526 port->pin, port);
527 mutex_unlock(&pcm->lock);
528 if (ret < 0)
529 continue;
530
531 for (i = 0; i < port->num_mux_nids; i++) {
532 if (port->mux_nids[i] == cvt->nid &&
533 port->eld.monitor_present &&
534 port->eld.eld_valid)
535 return port;
536 }
537 }
500 } 538 }
501 } 539 }
502 540
@@ -529,7 +567,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
529 */ 567 */
530 if (!port) 568 if (!port)
531 return 0; 569 return 0;
532
533 if ((!port->eld.monitor_present) || 570 if ((!port->eld.monitor_present) ||
534 (!port->eld.eld_valid)) { 571 (!port->eld.eld_valid)) {
535 572
@@ -645,13 +682,16 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
645{ 682{
646 struct hdac_hdmi_priv *hdmi = edev->private_data; 683 struct hdac_hdmi_priv *hdmi = edev->private_data;
647 struct hdac_hdmi_pcm *pcm = NULL; 684 struct hdac_hdmi_pcm *pcm = NULL;
685 struct hdac_hdmi_port *p;
648 686
649 list_for_each_entry(pcm, &hdmi->pcm_list, head) { 687 list_for_each_entry(pcm, &hdmi->pcm_list, head) {
650 if (!pcm->port) 688 if (list_empty(&pcm->port_list))
651 continue; 689 continue;
652 690
653 if (pcm->port == port) 691 list_for_each_entry(p, &pcm->port_list, head) {
654 return pcm; 692 if (p->id == port->id && port->pin == p->pin)
693 return pcm;
694 }
655 } 695 }
656 696
657 return NULL; 697 return NULL;
@@ -802,6 +842,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
802 struct snd_ctl_elem_value *ucontrol) 842 struct snd_ctl_elem_value *ucontrol)
803{ 843{
804 int ret; 844 int ret;
845 struct hdac_hdmi_port *p, *p_next;
805 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 846 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
806 struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 847 struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
807 struct snd_soc_dapm_context *dapm = w->dapm; 848 struct snd_soc_dapm_context *dapm = w->dapm;
@@ -820,25 +861,30 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
820 861
821 mutex_lock(&hdmi->pin_mutex); 862 mutex_lock(&hdmi->pin_mutex);
822 list_for_each_entry(pcm, &hdmi->pcm_list, head) { 863 list_for_each_entry(pcm, &hdmi->pcm_list, head) {
823 if (!pcm->port && pcm->port == port && 864 if (list_empty(&pcm->port_list))
824 pcm->port->id == port->id) 865 continue;
825 pcm->port = NULL;
826 866
827 /* 867 list_for_each_entry_safe(p, p_next, &pcm->port_list, head) {
828 * Jack status is not reported during device probe as the 868 if (p == port && p->id == port->id &&
829 * PCMs are not registered by then. So report it here. 869 p->pin == port->pin) {
830 */ 870 hdac_hdmi_jack_report(pcm, port, false);
831 if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { 871 list_del(&p->head);
832 pcm->port = port; 872 }
833 if (port->eld.monitor_present && port->eld.eld_valid) { 873 }
834 dev_dbg(&edev->hdac.dev, 874 }
835 "jack report for pcm=%d\n",
836 pcm->pcm_id);
837 875
838 snd_jack_report(pcm->jack, SND_JACK_AVOUT); 876 /*
877 * Jack status is not reported during device probe as the
878 * PCMs are not registered by then. So report it here.
879 */
880 list_for_each_entry(pcm, &hdmi->pcm_list, head) {
881 if (!strcmp(cvt_name, pcm->cvt->name)) {
882 list_add_tail(&port->head, &pcm->port_list);
883 if (port->eld.monitor_present && port->eld.eld_valid) {
884 hdac_hdmi_jack_report(pcm, port, true);
885 mutex_unlock(&hdmi->pin_mutex);
886 return ret;
839 } 887 }
840 mutex_unlock(&hdmi->pin_mutex);
841 return ret;
842 } 888 }
843 } 889 }
844 mutex_unlock(&hdmi->pin_mutex); 890 mutex_unlock(&hdmi->pin_mutex);
@@ -1186,7 +1232,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
1186 1232
1187 if (!port->eld.monitor_present || !port->eld.eld_valid) { 1233 if (!port->eld.monitor_present || !port->eld.eld_valid) {
1188 1234
1189 dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", 1235 dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n",
1190 __func__, pin->nid, port->id); 1236 __func__, pin->nid, port->id);
1191 1237
1192 /* 1238 /*
@@ -1194,25 +1240,16 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
1194 * report jack here. It will be done in usermode mux 1240 * report jack here. It will be done in usermode mux
1195 * control select. 1241 * control select.
1196 */ 1242 */
1197 if (pcm) { 1243 if (pcm)
1198 dev_dbg(&edev->hdac.dev, 1244 hdac_hdmi_jack_report(pcm, port, false);
1199 "jack report for pcm=%d\n", pcm->pcm_id);
1200
1201 snd_jack_report(pcm->jack, 0);
1202 }
1203 1245
1204 mutex_unlock(&hdmi->pin_mutex); 1246 mutex_unlock(&hdmi->pin_mutex);
1205 return; 1247 return;
1206 } 1248 }
1207 1249
1208 if (port->eld.monitor_present && port->eld.eld_valid) { 1250 if (port->eld.monitor_present && port->eld.eld_valid) {
1209 if (pcm) { 1251 if (pcm)
1210 dev_dbg(&edev->hdac.dev, 1252 hdac_hdmi_jack_report(pcm, port, true);
1211 "jack report for pcm=%d\n",
1212 pcm->pcm_id);
1213
1214 snd_jack_report(pcm->jack, SND_JACK_AVOUT);
1215 }
1216 1253
1217 print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, 1254 print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
1218 port->eld.eld_buffer, port->eld.eld_size, false); 1255 port->eld.eld_buffer, port->eld.eld_size, false);
@@ -1540,8 +1577,9 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
1540 return -ENOMEM; 1577 return -ENOMEM;
1541 pcm->pcm_id = device; 1578 pcm->pcm_id = device;
1542 pcm->cvt = hdmi->dai_map[dai->id].cvt; 1579 pcm->cvt = hdmi->dai_map[dai->id].cvt;
1580 pcm->jack_event = 0;
1543 mutex_init(&pcm->lock); 1581 mutex_init(&pcm->lock);
1544 1582 INIT_LIST_HEAD(&pcm->port_list);
1545 snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); 1583 snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
1546 if (snd_pcm) { 1584 if (snd_pcm) {
1547 err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); 1585 err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
@@ -1716,13 +1754,17 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
1716 struct hdac_ext_device *edev = to_ehdac_device(hdac); 1754 struct hdac_ext_device *edev = to_ehdac_device(hdac);
1717 struct hdac_hdmi_priv *hdmi = edev->private_data; 1755 struct hdac_hdmi_priv *hdmi = edev->private_data;
1718 struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 1756 struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
1719 struct hdac_hdmi_port *port = pcm->port; 1757 struct hdac_hdmi_port *port;
1758
1759 if (list_empty(&pcm->port_list))
1760 return;
1720 1761
1721 mutex_lock(&pcm->lock); 1762 mutex_lock(&pcm->lock);
1722 pcm->chmap_set = true; 1763 pcm->chmap_set = true;
1723 memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); 1764 memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap));
1724 if (prepared) 1765 list_for_each_entry(port, &pcm->port_list, head)
1725 hdac_hdmi_setup_audio_infoframe(edev, pcm, port); 1766 if (prepared)
1767 hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
1726 mutex_unlock(&pcm->lock); 1768 mutex_unlock(&pcm->lock);
1727} 1769}
1728 1770
@@ -1731,9 +1773,11 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
1731 struct hdac_ext_device *edev = to_ehdac_device(hdac); 1773 struct hdac_ext_device *edev = to_ehdac_device(hdac);
1732 struct hdac_hdmi_priv *hdmi = edev->private_data; 1774 struct hdac_hdmi_priv *hdmi = edev->private_data;
1733 struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 1775 struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
1734 struct hdac_hdmi_port *port = pcm->port;
1735 1776
1736 return port ? true:false; 1777 if (list_empty(&pcm->port_list))
1778 return false;
1779
1780 return true;
1737} 1781}
1738 1782
1739static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) 1783static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
@@ -1741,7 +1785,15 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
1741 struct hdac_ext_device *edev = to_ehdac_device(hdac); 1785 struct hdac_ext_device *edev = to_ehdac_device(hdac);
1742 struct hdac_hdmi_priv *hdmi = edev->private_data; 1786 struct hdac_hdmi_priv *hdmi = edev->private_data;
1743 struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 1787 struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
1744 struct hdac_hdmi_port *port = pcm->port; 1788 struct hdac_hdmi_port *port;
1789
1790 if (list_empty(&pcm->port_list))
1791 return 0;
1792
1793 port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head);
1794
1795 if (!port)
1796 return 0;
1745 1797
1746 if (!port || !port->eld.eld_valid) 1798 if (!port || !port->eld.eld_valid)
1747 return 0; 1799 return 0;
@@ -1819,13 +1871,19 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
1819 struct hdac_hdmi_pin *pin, *pin_next; 1871 struct hdac_hdmi_pin *pin, *pin_next;
1820 struct hdac_hdmi_cvt *cvt, *cvt_next; 1872 struct hdac_hdmi_cvt *cvt, *cvt_next;
1821 struct hdac_hdmi_pcm *pcm, *pcm_next; 1873 struct hdac_hdmi_pcm *pcm, *pcm_next;
1874 struct hdac_hdmi_port *port;
1822 int i; 1875 int i;
1823 1876
1824 snd_soc_unregister_codec(&edev->hdac.dev); 1877 snd_soc_unregister_codec(&edev->hdac.dev);
1825 1878
1826 list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { 1879 list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
1827 pcm->cvt = NULL; 1880 pcm->cvt = NULL;
1828 pcm->port = NULL; 1881 if (list_empty(&pcm->port_list))
1882 continue;
1883
1884 list_for_each_entry(port, &pcm->port_list, head)
1885 port = NULL;
1886
1829 list_del(&pcm->head); 1887 list_del(&pcm->head);
1830 kfree(pcm); 1888 kfree(pcm);
1831 } 1889 }