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>
This commit is contained in:
Родитель
625de2bf2e
Коммит
0324e51b5b
|
@ -95,6 +95,9 @@ struct hdac_hdmi_port {
|
||||||
int num_mux_nids;
|
int num_mux_nids;
|
||||||
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
|
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
|
||||||
struct hdac_hdmi_eld eld;
|
struct hdac_hdmi_eld eld;
|
||||||
|
const char *jack_pin;
|
||||||
|
struct snd_soc_dapm_context *dapm;
|
||||||
|
const char *output_pin;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hdac_hdmi_pcm {
|
struct hdac_hdmi_pcm {
|
||||||
|
@ -149,6 +152,11 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
|
||||||
{
|
{
|
||||||
struct hdac_ext_device *edev = port->pin->edev;
|
struct hdac_ext_device *edev = port->pin->edev;
|
||||||
|
|
||||||
|
if (is_connect)
|
||||||
|
snd_soc_dapm_enable_pin(port->dapm, port->jack_pin);
|
||||||
|
else
|
||||||
|
snd_soc_dapm_disable_pin(port->dapm, port->jack_pin);
|
||||||
|
|
||||||
if (is_connect) {
|
if (is_connect) {
|
||||||
/*
|
/*
|
||||||
* Report Jack connect event when a device is connected
|
* Report Jack connect event when a device is connected
|
||||||
|
@ -174,6 +182,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
|
||||||
if (pcm->jack_event > 0)
|
if (pcm->jack_event > 0)
|
||||||
pcm->jack_event--;
|
pcm->jack_event--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snd_soc_dapm_sync(port->dapm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MST supported verbs */
|
/* MST supported verbs */
|
||||||
|
@ -1059,6 +1069,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
|
||||||
SND_SOC_DAPM_POST_PMD);
|
SND_SOC_DAPM_POST_PMD);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
pin->ports[j].output_pin = widgets[i].name;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1557,6 +1568,125 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create jack pin kcontrols */
|
||||||
|
static int create_fill_jack_kcontrols(struct snd_soc_card *card,
|
||||||
|
struct hdac_ext_device *edev)
|
||||||
|
{
|
||||||
|
struct hdac_hdmi_pin *pin;
|
||||||
|
struct snd_kcontrol_new *kc;
|
||||||
|
char kc_name[NAME_SIZE], xname[NAME_SIZE];
|
||||||
|
char *name;
|
||||||
|
int i = 0, j;
|
||||||
|
struct snd_soc_codec *codec = edev->scodec;
|
||||||
|
struct hdac_hdmi_priv *hdmi = edev->private_data;
|
||||||
|
|
||||||
|
kc = devm_kcalloc(codec->dev, hdmi->num_ports,
|
||||||
|
sizeof(*kc), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!kc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
list_for_each_entry(pin, &hdmi->pin_list, head) {
|
||||||
|
for (j = 0; j < pin->num_ports; j++) {
|
||||||
|
snprintf(xname, sizeof(xname), "hif%d-%d Jack",
|
||||||
|
pin->nid, pin->ports[j].id);
|
||||||
|
name = devm_kstrdup(codec->dev, xname, GFP_KERNEL);
|
||||||
|
if (!name)
|
||||||
|
return -ENOMEM;
|
||||||
|
snprintf(kc_name, sizeof(kc_name), "%s Switch", xname);
|
||||||
|
kc[i].name = devm_kstrdup(codec->dev, kc_name,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!kc[i].name)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
kc[i].private_value = (unsigned long)name;
|
||||||
|
kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||||
|
kc[i].access = 0;
|
||||||
|
kc[i].info = snd_soc_dapm_info_pin_switch;
|
||||||
|
kc[i].put = snd_soc_dapm_put_pin_switch;
|
||||||
|
kc[i].get = snd_soc_dapm_get_pin_switch;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return snd_soc_add_card_controls(card, kc, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
|
||||||
|
struct snd_soc_dapm_context *dapm)
|
||||||
|
{
|
||||||
|
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
|
||||||
|
struct hdac_hdmi_priv *hdmi = edev->private_data;
|
||||||
|
struct hdac_hdmi_pin *pin;
|
||||||
|
struct snd_soc_dapm_widget *widgets;
|
||||||
|
struct snd_soc_dapm_route *route;
|
||||||
|
char w_name[NAME_SIZE];
|
||||||
|
int i = 0, j, ret;
|
||||||
|
|
||||||
|
widgets = devm_kcalloc(dapm->dev, hdmi->num_ports,
|
||||||
|
sizeof(*widgets), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!widgets)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
route = devm_kcalloc(dapm->dev, hdmi->num_ports,
|
||||||
|
sizeof(*route), GFP_KERNEL);
|
||||||
|
if (!route)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* create Jack DAPM widget */
|
||||||
|
list_for_each_entry(pin, &hdmi->pin_list, head) {
|
||||||
|
for (j = 0; j < pin->num_ports; j++) {
|
||||||
|
snprintf(w_name, sizeof(w_name), "hif%d-%d Jack",
|
||||||
|
pin->nid, pin->ports[j].id);
|
||||||
|
|
||||||
|
ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
|
||||||
|
snd_soc_dapm_spk, NULL,
|
||||||
|
w_name, NULL, NULL, 0, NULL, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pin->ports[j].jack_pin = widgets[i].name;
|
||||||
|
pin->ports[j].dapm = dapm;
|
||||||
|
|
||||||
|
/* add to route from Jack widget to output */
|
||||||
|
hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin,
|
||||||
|
NULL, pin->ports[j].output_pin, NULL);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add Route from Jack widget to the output widget */
|
||||||
|
ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = snd_soc_dapm_new_widgets(dapm->card);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Add Jack Pin switch Kcontrol */
|
||||||
|
ret = create_fill_jack_kcontrols(dapm->card, edev);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* default set the Jack Pin switch to OFF */
|
||||||
|
list_for_each_entry(pin, &hdmi->pin_list, head) {
|
||||||
|
for (j = 0; j < pin->num_ports; j++)
|
||||||
|
snd_soc_dapm_disable_pin(pin->ports[j].dapm,
|
||||||
|
pin->ports[j].jack_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init);
|
||||||
|
|
||||||
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
|
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
|
||||||
struct snd_soc_jack *jack)
|
struct snd_soc_jack *jack)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,4 +4,6 @@
|
||||||
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
|
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
|
||||||
struct snd_soc_jack *jack);
|
struct snd_soc_jack *jack);
|
||||||
|
|
||||||
|
int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
|
||||||
|
struct snd_soc_dapm_context *dapm);
|
||||||
#endif /* __HDAC_HDMI_H__ */
|
#endif /* __HDAC_HDMI_H__ */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче