Commit 15b91447 authored by Subhransu S. Prusty's avatar Subhransu S. Prusty Committed by Mark Brown

ASoC: hdac_hdmi: Use list to add pins and converters

Future platforms may have a different set of pins/converters.
So use lists to add pins and converters based on enumeration.

Also it may be required to connect any converter to any pin
dynamically as per different use cases (for example DP is
connected to pin 6 on skylake board). So this will help in
dynamically select and route.

Fix the dai map as well to use the pin/cvt from list. Not
enabling all dai maps for now.
Signed-off-by: default avatarSubhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 53072460
...@@ -43,11 +43,13 @@ struct hdac_hdmi_cvt_params { ...@@ -43,11 +43,13 @@ struct hdac_hdmi_cvt_params {
}; };
struct hdac_hdmi_cvt { struct hdac_hdmi_cvt {
struct list_head head;
hda_nid_t nid; hda_nid_t nid;
struct hdac_hdmi_cvt_params params; struct hdac_hdmi_cvt_params params;
}; };
struct hdac_hdmi_pin { struct hdac_hdmi_pin {
struct list_head head;
hda_nid_t nid; hda_nid_t nid;
int num_mux_nids; int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
...@@ -55,14 +57,16 @@ struct hdac_hdmi_pin { ...@@ -55,14 +57,16 @@ struct hdac_hdmi_pin {
struct hdac_hdmi_dai_pin_map { struct hdac_hdmi_dai_pin_map {
int dai_id; int dai_id;
struct hdac_hdmi_pin pin; struct hdac_hdmi_pin *pin;
struct hdac_hdmi_cvt cvt; struct hdac_hdmi_cvt *cvt;
}; };
struct hdac_hdmi_priv { struct hdac_hdmi_priv {
hda_nid_t pin_nid[3];
hda_nid_t cvt_nid[3];
struct hdac_hdmi_dai_pin_map dai_map[3]; struct hdac_hdmi_dai_pin_map dai_map[3];
struct list_head pin_list;
struct list_head cvt_list;
int num_pin;
int num_cvt;
}; };
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
...@@ -149,13 +153,15 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, ...@@ -149,13 +153,15 @@ static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
{ {
/* Power up pin widget */ /* Power up pin widget */
if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state)) if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0, pwr_state))
snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_POWER_STATE, pwr_state); AC_VERB_SET_POWER_STATE, pwr_state);
/* Power up converter */ /* Power up converter */
if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state)) if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, pwr_state))
snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
AC_VERB_SET_POWER_STATE, pwr_state); AC_VERB_SET_POWER_STATE, pwr_state);
} }
...@@ -179,13 +185,13 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, ...@@ -179,13 +185,13 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
dd->stream_tag, dd->format); dd->stream_tag, dd->format);
ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid, ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
dai_map->pin.nid); dai_map->pin->nid);
if (ret < 0) if (ret < 0)
return ret; return ret;
return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid, return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
dd->stream_tag, dd->format); dai_map->pin->nid, dd->stream_tag, dd->format);
} }
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
...@@ -221,9 +227,9 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, ...@@ -221,9 +227,9 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id]; dai_map = &hdmi->dai_map[dai->id];
snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
AC_VERB_SET_CHANNEL_STREAMID, 0); AC_VERB_SET_CHANNEL_STREAMID, 0);
snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, 0); AC_VERB_SET_STREAM_FORMAT, 0);
dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
...@@ -249,7 +255,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, ...@@ -249,7 +255,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id]; dai_map = &hdmi->dai_map[dai->id];
val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin.nid, 0, val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_GET_PIN_SENSE, 0); AC_VERB_GET_PIN_SENSE, 0);
dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val); dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
...@@ -260,7 +266,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, ...@@ -260,7 +266,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0, snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
snd_pcm_hw_constraint_step(substream->runtime, 0, snd_pcm_hw_constraint_step(substream->runtime, 0,
...@@ -280,7 +286,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, ...@@ -280,7 +286,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0, snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
} }
...@@ -368,40 +374,79 @@ static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, ...@@ -368,40 +374,79 @@ static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
} }
static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev, static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
struct hdac_hdmi_dai_pin_map *dai_map,
hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id)
{ {
int ret; struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_pin *pin;
dai_map->dai_id = dai_id; if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
dai_map->pin.nid = pin_nid; return -EINVAL;
ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin); /*
if (ret < 0) { * Currently on board only 1 pin and 1 converter is enabled for
dev_err(&edev->hdac.dev, * simplification, more will be added eventually
"Error querying connection list: %d\n", ret); * So using fixed map for dai_id:pin:cvt
return ret; */
} cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
dai_map->dai_id = 0;
dai_map->pin = pin;
dai_map->cvt.nid = cvt_nid; dai_map->cvt = cvt;
/* Enable out path for this pin widget */ /* Enable out path for this pin widget */
snd_hdac_codec_write(&edev->hdac, pin_nid, 0, snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
/* Enable transmission */ /* Enable transmission */
snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, 1); AC_VERB_SET_DIGI_CONVERT_1, 1);
/* Category Code (CC) to zero */ /* Category Code (CC) to zero */
snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, 0); AC_VERB_SET_DIGI_CONVERT_2, 0);
snd_hdac_codec_write(&edev->hdac, pin_nid, 0, snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
AC_VERB_SET_CONNECT_SEL, 0); AC_VERB_SET_CONNECT_SEL, 0);
return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt); return 0;
}
static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_cvt *cvt;
cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
if (!cvt)
return -ENOMEM;
cvt->nid = nid;
list_add_tail(&cvt->head, &hdmi->cvt_list);
hdmi->num_cvt++;
return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
}
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin;
pin = kzalloc(sizeof(*pin), GFP_KERNEL);
if (!pin)
return -ENOMEM;
pin->nid = nid;
list_add_tail(&pin->head, &hdmi->pin_list);
hdmi->num_pin++;
return 0;
} }
/* /*
...@@ -414,7 +459,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) ...@@ -414,7 +459,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
int i, num_nodes; int i, num_nodes;
struct hdac_device *hdac = &edev->hdac; struct hdac_device *hdac = &edev->hdac;
struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_priv *hdmi = edev->private_data;
int cvt_nid = 0, pin_nid = 0; int ret;
num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
if (!nid || num_nodes <= 0) { if (!nid || num_nodes <= 0) {
...@@ -438,29 +483,25 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) ...@@ -438,29 +483,25 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
switch (type) { switch (type) {
case AC_WID_AUD_OUT: case AC_WID_AUD_OUT:
hdmi->cvt_nid[cvt_nid] = nid; ret = hdac_hdmi_add_cvt(edev, nid);
cvt_nid++; if (ret < 0)
return ret;
break; break;
case AC_WID_PIN: case AC_WID_PIN:
hdmi->pin_nid[pin_nid] = nid; ret = hdac_hdmi_add_pin(edev, nid);
pin_nid++; if (ret < 0)
return ret;
break; break;
} }
} }
hdac->end_nid = nid; hdac->end_nid = nid;
if (!pin_nid || !cvt_nid) if (!hdmi->num_pin || !hdmi->num_cvt)
return -EIO; return -EIO;
/* return hdac_hdmi_init_dai_map(edev);
* Currently on board only 1 pin and 1 converter is enabled for
* simplification, more will be added eventually
* So using fixed map for dai_id:pin:cvt
*/
return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0],
hdmi->cvt_nid[0], 0);
} }
static int hdmi_codec_probe(struct snd_soc_codec *codec) static int hdmi_codec_probe(struct snd_soc_codec *codec)
...@@ -544,6 +585,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) ...@@ -544,6 +585,9 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
dev_set_drvdata(&codec->dev, edev); dev_set_drvdata(&codec->dev, edev);
INIT_LIST_HEAD(&hdmi_priv->pin_list);
INIT_LIST_HEAD(&hdmi_priv->cvt_list);
ret = hdac_hdmi_parse_and_map_nid(edev); ret = hdac_hdmi_parse_and_map_nid(edev);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -555,8 +599,22 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) ...@@ -555,8 +599,22 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
{ {
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
snd_soc_unregister_codec(&edev->hdac.dev); snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
list_del(&cvt->head);
kfree(cvt);
}
list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
list_del(&pin->head);
kfree(pin);
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment