From patchwork Wed Dec 9 16:16:10 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Subhransu S. Prusty" X-Patchwork-Id: 7810211 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id B3F8BBEEE1 for ; Wed, 9 Dec 2015 16:14:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 689A420519 for ; Wed, 9 Dec 2015 16:14:57 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 86C702040F for ; Wed, 9 Dec 2015 16:14:52 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 43C61261A06; Wed, 9 Dec 2015 17:14:51 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id DA8D32612D7; Wed, 9 Dec 2015 17:14:17 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 384D72606C1; Wed, 9 Dec 2015 17:14:17 +0100 (CET) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by alsa0.perex.cz (Postfix) with ESMTP id 0DB2F260671 for ; Wed, 9 Dec 2015 17:14:08 +0100 (CET) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 09 Dec 2015 08:13:51 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,404,1444719600"; d="scan'208";a="837735002" Received: from subhransu-desktop.iind.intel.com ([10.223.96.57]) by orsmga001.jf.intel.com with ESMTP; 09 Dec 2015 08:13:46 -0800 From: "Subhransu S. Prusty" To: alsa-devel@alsa-project.org Date: Wed, 9 Dec 2015 21:46:10 +0530 Message-Id: <1449677781-7997-3-git-send-email-subhransu.s.prusty@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1449677781-7997-1-git-send-email-subhransu.s.prusty@intel.com> References: <1449677405-7907-1-git-send-email-subhransu.s.prusty@intel.com> <1449677781-7997-1-git-send-email-subhransu.s.prusty@intel.com> Cc: tiwai@suse.de, lgirdwood@gmail.com, patches.audio@intel.com, broonie@kernel.org, Vinod Koul , "Subhransu S. Prusty" Subject: [alsa-devel] [PATCH v4 03/14] ASoC: hdac_hdmi: Use list to add pins and converters X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP 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: Subhransu S. Prusty Signed-off-by: Vinod Koul --- sound/soc/codecs/hdac_hdmi.c | 154 +++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 48 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 429fa14..b206d5e 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -43,11 +43,13 @@ struct hdac_hdmi_cvt_params { }; struct hdac_hdmi_cvt { + struct list_head head; hda_nid_t nid; struct hdac_hdmi_cvt_params params; }; struct hdac_hdmi_pin { + struct list_head head; hda_nid_t nid; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; @@ -55,14 +57,16 @@ struct hdac_hdmi_pin { struct hdac_hdmi_dai_pin_map { int dai_id; - struct hdac_hdmi_pin pin; - struct hdac_hdmi_cvt cvt; + struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt; }; 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 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) @@ -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) { /* Power up pin widget */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0, + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, + pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, AC_VERB_SET_POWER_STATE, pwr_state); /* Power up converter */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0, + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, + pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, AC_VERB_SET_POWER_STATE, pwr_state); } @@ -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", dd->stream_tag, dd->format); - ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid, - dai_map->pin.nid); + ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, + dai_map->pin->nid); if (ret < 0) return ret; - return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid, - dd->stream_tag, dd->format); + return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, + dai_map->pin->nid, dd->stream_tag, dd->format); } 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, 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); - 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); 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, 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); 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, 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); snd_pcm_hw_constraint_step(substream->runtime, 0, @@ -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); - 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); } @@ -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)); } -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) +static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { - 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; - dai_map->pin.nid = pin_nid; + if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) + return -EINVAL; - ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin); - if (ret < 0) { - dev_err(&edev->hdac.dev, - "Error querying connection list: %d\n", ret); - return ret; - } + /* + * 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 + */ + 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 */ - 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); /* 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); /* 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); - snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + snd_hdac_codec_write(&edev->hdac, pin->nid, 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) int i, num_nodes; struct hdac_device *hdac = &edev->hdac; 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); if (!nid || num_nodes <= 0) { @@ -438,29 +483,25 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) switch (type) { case AC_WID_AUD_OUT: - hdmi->cvt_nid[cvt_nid] = nid; - cvt_nid++; + ret = hdac_hdmi_add_cvt(edev, nid); + if (ret < 0) + return ret; break; case AC_WID_PIN: - hdmi->pin_nid[pin_nid] = nid; - pin_nid++; + ret = hdac_hdmi_add_pin(edev, nid); + if (ret < 0) + return ret; break; } } hdac->end_nid = nid; - if (!pin_nid || !cvt_nid) + if (!hdmi->num_pin || !hdmi->num_cvt) return -EIO; - /* - * 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); + return hdac_hdmi_init_dai_map(edev); } 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) 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); if (ret < 0) return ret; @@ -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) { + 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); + 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; }