diff options
author | Jeeja KP <jeeja.kp@intel.com> | 2017-02-07 08:39:55 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-02-16 13:56:06 -0500 |
commit | 0324e51b5ba405cd2d66e9e95430f6b9562d0ac0 (patch) | |
tree | 45a3f3cdcabf0b7b4ccabd5093e585e74a43cb4b | |
parent | 625de2bf2ed1632cb74a4a38f8f09a2063fb74af (diff) |
ASoC: hdac_hdmi: Add machine pin widget for each port
Represent each port as machine DAPM pin widget. This helps in
enable/disable pin when monitor is connected/disconnected in case pcm
is rendered to multiple ports.
Create machine pin widgets and pin switch kcontrol for each port and
report based on the pin status
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.c | 130 | ||||
-rw-r--r-- | sound/soc/codecs/hdac_hdmi.h | 2 |
2 files changed, 132 insertions, 0 deletions
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 0f2c1e823281..0a5510a3a8e1 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c | |||
@@ -95,6 +95,9 @@ struct hdac_hdmi_port { | |||
95 | int num_mux_nids; | 95 | int num_mux_nids; |
96 | hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; | 96 | hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; |
97 | struct hdac_hdmi_eld eld; | 97 | struct hdac_hdmi_eld eld; |
98 | const char *jack_pin; | ||
99 | struct snd_soc_dapm_context *dapm; | ||
100 | const char *output_pin; | ||
98 | }; | 101 | }; |
99 | 102 | ||
100 | struct hdac_hdmi_pcm { | 103 | struct hdac_hdmi_pcm { |
@@ -149,6 +152,11 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, | |||
149 | { | 152 | { |
150 | struct hdac_ext_device *edev = port->pin->edev; | 153 | struct hdac_ext_device *edev = port->pin->edev; |
151 | 154 | ||
155 | if (is_connect) | ||
156 | snd_soc_dapm_enable_pin(port->dapm, port->jack_pin); | ||
157 | else | ||
158 | snd_soc_dapm_disable_pin(port->dapm, port->jack_pin); | ||
159 | |||
152 | if (is_connect) { | 160 | if (is_connect) { |
153 | /* | 161 | /* |
154 | * Report Jack connect event when a device is connected | 162 | * Report Jack connect event when a device is connected |
@@ -174,6 +182,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, | |||
174 | if (pcm->jack_event > 0) | 182 | if (pcm->jack_event > 0) |
175 | pcm->jack_event--; | 183 | pcm->jack_event--; |
176 | } | 184 | } |
185 | |||
186 | snd_soc_dapm_sync(port->dapm); | ||
177 | } | 187 | } |
178 | 188 | ||
179 | /* MST supported verbs */ | 189 | /* MST supported verbs */ |
@@ -1059,6 +1069,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) | |||
1059 | SND_SOC_DAPM_POST_PMD); | 1069 | SND_SOC_DAPM_POST_PMD); |
1060 | if (ret < 0) | 1070 | if (ret < 0) |
1061 | return ret; | 1071 | return ret; |
1072 | pin->ports[j].output_pin = widgets[i].name; | ||
1062 | i++; | 1073 | i++; |
1063 | } | 1074 | } |
1064 | } | 1075 | } |
@@ -1557,6 +1568,125 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, | |||
1557 | return NULL; | 1568 | return NULL; |
1558 | } | 1569 | } |
1559 | 1570 | ||
1571 | /* create jack pin kcontrols */ | ||
1572 | static int create_fill_jack_kcontrols(struct snd_soc_card *card, | ||
1573 | struct hdac_ext_device *edev) | ||
1574 | { | ||
1575 | struct hdac_hdmi_pin *pin; | ||
1576 | struct snd_kcontrol_new *kc; | ||
1577 | char kc_name[NAME_SIZE], xname[NAME_SIZE]; | ||
1578 | char *name; | ||
1579 | int i = 0, j; | ||
1580 | struct snd_soc_codec *codec = edev->scodec; | ||
1581 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
1582 | |||
1583 | kc = devm_kcalloc(codec->dev, hdmi->num_ports, | ||
1584 | sizeof(*kc), GFP_KERNEL); | ||
1585 | |||
1586 | if (!kc) | ||
1587 | return -ENOMEM; | ||
1588 | |||
1589 | list_for_each_entry(pin, &hdmi->pin_list, head) { | ||
1590 | for (j = 0; j < pin->num_ports; j++) { | ||
1591 | snprintf(xname, sizeof(xname), "hif%d-%d Jack", | ||
1592 | pin->nid, pin->ports[j].id); | ||
1593 | name = devm_kstrdup(codec->dev, xname, GFP_KERNEL); | ||
1594 | if (!name) | ||
1595 | return -ENOMEM; | ||
1596 | snprintf(kc_name, sizeof(kc_name), "%s Switch", xname); | ||
1597 | kc[i].name = devm_kstrdup(codec->dev, kc_name, | ||
1598 | GFP_KERNEL); | ||
1599 | if (!kc[i].name) | ||
1600 | return -ENOMEM; | ||
1601 | |||
1602 | kc[i].private_value = (unsigned long)name; | ||
1603 | kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1604 | kc[i].access = 0; | ||
1605 | kc[i].info = snd_soc_dapm_info_pin_switch; | ||
1606 | kc[i].put = snd_soc_dapm_put_pin_switch; | ||
1607 | kc[i].get = snd_soc_dapm_get_pin_switch; | ||
1608 | i++; | ||
1609 | } | ||
1610 | } | ||
1611 | |||
1612 | return snd_soc_add_card_controls(card, kc, i); | ||
1613 | } | ||
1614 | |||
1615 | int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, | ||
1616 | struct snd_soc_dapm_context *dapm) | ||
1617 | { | ||
1618 | struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); | ||
1619 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
1620 | struct hdac_hdmi_pin *pin; | ||
1621 | struct snd_soc_dapm_widget *widgets; | ||
1622 | struct snd_soc_dapm_route *route; | ||
1623 | char w_name[NAME_SIZE]; | ||
1624 | int i = 0, j, ret; | ||
1625 | |||
1626 | widgets = devm_kcalloc(dapm->dev, hdmi->num_ports, | ||
1627 | sizeof(*widgets), GFP_KERNEL); | ||
1628 | |||
1629 | if (!widgets) | ||
1630 | return -ENOMEM; | ||
1631 | |||
1632 | route = devm_kcalloc(dapm->dev, hdmi->num_ports, | ||
1633 | sizeof(*route), GFP_KERNEL); | ||
1634 | if (!route) | ||
1635 | return -ENOMEM; | ||
1636 | |||
1637 | /* create Jack DAPM widget */ | ||
1638 | list_for_each_entry(pin, &hdmi->pin_list, head) { | ||
1639 | for (j = 0; j < pin->num_ports; j++) { | ||
1640 | snprintf(w_name, sizeof(w_name), "hif%d-%d Jack", | ||
1641 | pin->nid, pin->ports[j].id); | ||
1642 | |||
1643 | ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], | ||
1644 | snd_soc_dapm_spk, NULL, | ||
1645 | w_name, NULL, NULL, 0, NULL, 0); | ||
1646 | if (ret < 0) | ||
1647 | return ret; | ||
1648 | |||
1649 | pin->ports[j].jack_pin = widgets[i].name; | ||
1650 | pin->ports[j].dapm = dapm; | ||
1651 | |||
1652 | /* add to route from Jack widget to output */ | ||
1653 | hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin, | ||
1654 | NULL, pin->ports[j].output_pin, NULL); | ||
1655 | |||
1656 | i++; | ||
1657 | } | ||
1658 | } | ||
1659 | |||
1660 | /* Add Route from Jack widget to the output widget */ | ||
1661 | ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports); | ||
1662 | if (ret < 0) | ||
1663 | return ret; | ||
1664 | |||
1665 | ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports); | ||
1666 | if (ret < 0) | ||
1667 | return ret; | ||
1668 | |||
1669 | ret = snd_soc_dapm_new_widgets(dapm->card); | ||
1670 | if (ret < 0) | ||
1671 | return ret; | ||
1672 | |||
1673 | /* Add Jack Pin switch Kcontrol */ | ||
1674 | ret = create_fill_jack_kcontrols(dapm->card, edev); | ||
1675 | |||
1676 | if (ret < 0) | ||
1677 | return ret; | ||
1678 | |||
1679 | /* default set the Jack Pin switch to OFF */ | ||
1680 | list_for_each_entry(pin, &hdmi->pin_list, head) { | ||
1681 | for (j = 0; j < pin->num_ports; j++) | ||
1682 | snd_soc_dapm_disable_pin(pin->ports[j].dapm, | ||
1683 | pin->ports[j].jack_pin); | ||
1684 | } | ||
1685 | |||
1686 | return 0; | ||
1687 | } | ||
1688 | EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init); | ||
1689 | |||
1560 | int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, | 1690 | int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, |
1561 | struct snd_soc_jack *jack) | 1691 | struct snd_soc_jack *jack) |
1562 | { | 1692 | { |
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index bf7edb3227d2..dfc3a9cf7199 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h | |||
@@ -4,4 +4,6 @@ | |||
4 | int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, | 4 | int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, |
5 | struct snd_soc_jack *jack); | 5 | struct snd_soc_jack *jack); |
6 | 6 | ||
7 | int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, | ||
8 | struct snd_soc_dapm_context *dapm); | ||
7 | #endif /* __HDAC_HDMI_H__ */ | 9 | #endif /* __HDAC_HDMI_H__ */ |