From 547cafa3efc3f12101cafd454e651c9a5a8feae4 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 8 Dec 2016 23:01:24 +0530 Subject: ASoC: Intel: Skylake: remove unused 'ret' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In skl_tplg_mixer_dapm_post_pmd_event(), a variable 'ret' is initialized but not used. We don't check return of skl_delete_pipe, so remove the assignment as well, so remove this variable. sound/soc/intel/skylake/skl-topology.c: In function ‘skl_tplg_mixer_dapm_post_pmd_event’: sound/soc/intel/skylake/skl-topology.c:976:6: warning: variable ‘ret’ set but not used [-Wunused-but-set-variable] int ret = 0; ^ Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index bd313c907b20..eb440cd9a2a4 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -974,7 +974,6 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, struct skl_module_cfg *src_module = NULL, *dst_module; struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *s_pipe = mconfig->pipe; - int ret = 0; if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; @@ -996,7 +995,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, src_module = dst_module; } - ret = skl_delete_pipe(ctx, mconfig->pipe); + skl_delete_pipe(ctx, mconfig->pipe); return skl_tplg_unload_pipe_modules(ctx, s_pipe); } -- cgit From cf90c8245bb0d528a8046b4bfa4f223320c9dbb0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 8 Dec 2016 23:01:26 +0530 Subject: ASoC: Intel: sst: remove unused 'ops' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In sst_free_stream(), a variable 'ops' is initialized but not used. So remove it. sound/soc/intel/atom/sst/sst_stream.c: In function ‘sst_free_stream’: sound/soc/intel/atom/sst/sst_stream.c:397:24: warning: variable ‘ops’ set but not used [-Wunused-but-set-variable] struct intel_sst_ops *ops; Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_stream.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 51bdeeecb7c8..83d8dda15233 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -394,7 +394,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) { int retval = 0; struct stream_info *str_info; - struct intel_sst_ops *ops; dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); @@ -407,7 +406,6 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) str_info = get_stream_info(sst_drv_ctx, str_id); if (!str_info) return -EINVAL; - ops = sst_drv_ctx->ops; mutex_lock(&str_info->lock); if (str_info->status != STREAM_UN_INIT) { -- cgit From ee9292e859bec2bd8b79b7d14bc352e9ea5d7257 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 8 Dec 2016 23:01:25 +0530 Subject: ASoC: Intel: sst: remove unused 'msg_high' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In process_fw_async_msg(), a variable 'msg_high' is initialized but not used. So remove it. sound/soc/intel/atom/sst/sst_ipc.c: In function ‘process_fw_async_msg’: sound/soc/intel/atom/sst/sst_ipc.c:263:24: warning: variable ‘msg_high’ set but not used [-Wunused-but-set-variable] union ipc_header_high msg_high; Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_ipc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 374bb61c596d..14c2d9d18180 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -260,10 +260,8 @@ static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, u32 data_size, i; void *data_offset; struct stream_info *stream; - union ipc_header_high msg_high; u32 msg_low, pipe_id; - msg_high = msg->mrfld_header.p.header_high; msg_low = msg->mrfld_header.p.header_low_payload; msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); -- cgit From 7d7c80f3f335e5148e3f744534a0576e638cf581 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 8 Dec 2016 23:01:35 +0530 Subject: ASoC: Intel: sst: remove unused ‘ret_val’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In sst_media_close(), 'ret_val' is initialized and assigned as return value of stream ops close but never used. So remove it. ound/soc/intel/atom/sst-mfld-platform-pcm.c: In function ‘sst_media_close’: sound/soc/intel/atom/sst-mfld-platform-pcm.c:360:6: warning: variable ‘ret_val’ set but not used [-Wunused-but-set-variable] int ret_val = 0, str_id; Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index f5a8050351b5..0fd7848fbe4a 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -357,14 +357,14 @@ static void sst_media_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sst_runtime_stream *stream; - int ret_val = 0, str_id; + int str_id; stream = substream->runtime->private_data; power_down_sst(stream); str_id = stream->stream_info.str_id; if (str_id) - ret_val = stream->ops->close(sst->dev, str_id); + stream->ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); } -- cgit From 12c3be0e720fe8c4e0f456fd25a6dcc8b254606c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 8 Dec 2016 13:41:12 +0530 Subject: ASoC: Intel: Skylake: Update link_index and format in pipe params To configure Host/Link DMA, additionally link index and format are required based on the hw params. So added these parameters in the pipe params and in hw_params the pipe params are updated. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 8 ++++++++ sound/soc/intel/skylake/skl-topology.c | 2 ++ sound/soc/intel/skylake/skl-topology.h | 2 ++ 3 files changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 84b5101e6ca6..105aab7593c8 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -292,6 +292,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, p_params.s_freq = params_rate(params); p_params.host_dma_id = dma_id; p_params.stream = substream->stream; + p_params.format = params_format(params); m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); if (m_cfg) @@ -506,6 +507,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; + struct hdac_ext_link *link; link_dev = snd_hdac_ext_stream_assign(ebus, substream, HDAC_EXT_STREAM_TYPE_LINK); @@ -514,6 +516,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + /* set the stream tag in the codec dai dma params */ dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) @@ -524,6 +530,8 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, p_params.s_freq = params_rate(params); p_params.stream = substream->stream; p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; + p_params.link_index = link->index; + p_params.format = params_format(params); return skl_tplg_be_update_params(dai, &p_params); } diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index eb440cd9a2a4..8f608c45e445 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1206,6 +1206,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, switch (mcfg->dev_type) { case SKL_DEVICE_HDALINK: pipe->p_params->link_dma_id = params->link_dma_id; + pipe->p_params->link_index = params->link_index; break; case SKL_DEVICE_HDAHOST: @@ -1219,6 +1220,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, pipe->p_params->ch = params->ch; pipe->p_params->s_freq = params->s_freq; pipe->p_params->stream = params->stream; + pipe->p_params->format = params->format; } else { memcpy(pipe->p_params, params, sizeof(*params)); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 08d39280b07b..405765f3a6b5 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -254,6 +254,8 @@ struct skl_pipe_params { u32 s_freq; u32 s_fmt; u8 linktype; + snd_pcm_format_t format; + int link_index; int stream; }; -- cgit From bb704a737cecc1c4c9f1b0251aa79d8276308ccc Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 8 Dec 2016 13:41:14 +0530 Subject: ASoC: Intel: Skylake: Configure DMA in PRE_PMD handler of Mixer If system is suspended when PCM was paused/stopped, restart doesn't configure DMA as it is we are in Pause state and results in IO error eventually. Configure host/link DMA before initializing DSP Gateway copier module instead of DAI prepare(). So moved DMA configuration to mixer PRE_PMD widget handler instead of DAI prepare. This uses previously added new API to do the configuration and removes old DAI prepare code. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 50 +--------------------------------- sound/soc/intel/skylake/skl-topology.c | 19 +++++++++++++ 2 files changed, 20 insertions(+), 49 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 105aab7593c8..aebae234152c 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -231,37 +231,19 @@ static int skl_be_prepare(struct snd_pcm_substream *substream, static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct skl *skl = get_skl_ctx(dai->dev); - unsigned int format_val; - int err; struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - format_val = skl_get_format(substream, dai); - dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", - hdac_stream(stream)->stream_tag, format_val); - snd_hdac_stream_reset(hdac_stream(stream)); - /* In case of XRUN recovery, reset the FW pipe to clean state */ if (mconfig && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); - err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); - if (err < 0) - return err; - - err = snd_hdac_stream_setup(hdac_stream(stream)); - if (err < 0) - return err; - - hdac_stream(stream)->prepared = 1; - - return err; + return 0; } static int skl_pcm_hw_params(struct snd_pcm_substream *substream, @@ -436,7 +418,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: if (!w->ignore_suspend) { - skl_pcm_prepare(substream, dai); /* * enable DMA Resume enable bit for the stream, set the * dpib & lpib position to resume before starting the @@ -457,7 +438,6 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, * pipeline is started but there is a delay in starting the * DMA channel on the host. */ - snd_hdac_ext_stream_decouple(ebus, stream, true); ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; @@ -539,41 +519,15 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - unsigned int format_val = 0; - struct skl_dma_params *dma_params; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct hdac_ext_link *link; struct skl *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig = NULL; - dma_params = (struct skl_dma_params *) - snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; - dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", - hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); - if (!link) - return -EINVAL; - - snd_hdac_ext_link_stream_reset(link_dev); - /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); if (mconfig && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); - snd_hdac_ext_link_stream_setup(link_dev, format_val); - - snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); - link_dev->link_prepared = 1; - return 0; } @@ -588,10 +542,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: - skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 8f608c45e445..422a9dee9270 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -496,6 +496,20 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) return 0; } +static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, + struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) +{ + switch (mcfg->dev_type) { + case SKL_DEVICE_HDAHOST: + return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params); + + case SKL_DEVICE_HDALINK: + return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); + } + + return 0; +} + /* * Inside a pipe instance, we can have various modules. These modules need * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by @@ -535,6 +549,11 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) mconfig->m_state = SKL_MODULE_LOADED; } + /* prepare the DMA if the module is gateway cpr */ + ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); + if (ret < 0) + return ret; + /* update blob if blob is null for be with default value */ skl_tplg_update_be_blob(w, ctx); -- cgit From ad036bdee57ab2287535fe53864bb5154e101991 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 8 Dec 2016 13:41:13 +0530 Subject: ASoC: Intel: Skylake: Add helper function to setup host/link dma This patch adds helper function to configure the host/link DMA when the DMA is in decoupled mode. Next patch adds the usage of this helper routines for configuring DMA in Mixer event handler. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 74 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 4 ++ 2 files changed, 78 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index aebae234152c..1abff8e1a298 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -137,6 +137,80 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, skl->supend_active--; } +int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int format_val; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + int err; + + hstream = snd_hdac_get_stream(bus, params->stream, + params->host_dma_id + 1); + if (!hstream) + return -EINVAL; + + stream = stream_to_hdac_ext_stream(hstream); + snd_hdac_ext_stream_decouple(ebus, stream, true); + + format_val = snd_hdac_calc_stream_format(params->s_freq, + params->ch, params->format, 32, 0); + + dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_stream_reset(hdac_stream(stream)); + err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); + if (err < 0) + return err; + + err = snd_hdac_stream_setup(hdac_stream(stream)); + if (err < 0) + return err; + + hdac_stream(stream)->prepared = 1; + + return 0; +} + +int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int format_val; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + struct hdac_ext_link *link; + + hstream = snd_hdac_get_stream(bus, params->stream, + params->link_dma_id + 1); + if (!hstream) + return -EINVAL; + + stream = stream_to_hdac_ext_stream(hstream); + snd_hdac_ext_stream_decouple(ebus, stream, true); + format_val = snd_hdac_calc_stream_format(params->s_freq, + params->ch, params->format, 24, 0); + + dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_ext_link_stream_reset(stream); + + snd_hdac_ext_link_stream_setup(stream, format_val); + + list_for_each_entry(link, &ebus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + hstream->stream_tag); + } + + stream->link_prepared = 1; + + return 0; +} + static int skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 405765f3a6b5..a0d3158196f0 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -385,4 +385,8 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream); enum skl_bitdepth skl_get_bit_depth(int params); +int skl_pcm_host_dma_prepare(struct device *dev, + struct skl_pipe_params *params); +int skl_pcm_link_dma_prepare(struct device *dev, + struct skl_pipe_params *params); #endif -- cgit From f4e4e9893964684397dec517debe77cb7e405a6c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 8 Dec 2016 13:41:15 +0530 Subject: ASoC: Intel: Skylake: Removed unused skl_get_format() Removed the unused function skl_get_format as the format is calculated directly using the HDA core API. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 1abff8e1a298..10fa10df4e57 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -259,32 +259,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, return 0; } -static int skl_get_format(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct skl_dma_params *dma_params; - struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); - int format_val = 0; - - if ((ebus_to_hbus(ebus))->ppcap) { - struct snd_pcm_runtime *runtime = substream->runtime; - - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - 32, 0); - } else { - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; - } - - return format_val; -} - static int skl_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { -- cgit From 571800487837263e914ef68681e4ad6a57d49c7f Mon Sep 17 00:00:00 2001 From: youling257 Date: Wed, 4 Jan 2017 15:44:53 -0600 Subject: ASoC: Intel: bytcr_rt5640: quirks for Insyde devices There are literally dozens of Insyde devices with a different name but with the same audio routing. Use a generic quirk to match on vendor name only to avoid recurring edits of the same thing. Signed-off-by: youling257 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 507a86a5eafe..613e5286555a 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -386,6 +386,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_MCLK_EN | BYT_RT5640_SSP0_AIF1), + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + }, {} }; -- cgit From eee0e16f8c3cf31fbbae4a88e51d25abebbaf147 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 2 Jan 2017 09:50:04 +0530 Subject: ASoC: Intel: Skylake: Clean up manifest info Instead of passing the topology manifest info directly to IPC library, define the manifest info in topology and use this in IPC Library. This will remove the dependency on topology interface definition with IPC library. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 25 ++++++++--------- sound/soc/intel/skylake/skl-sst-dsp.h | 4 +-- sound/soc/intel/skylake/skl-sst-ipc.h | 5 ++-- sound/soc/intel/skylake/skl-topology.c | 41 +++++++++++++--------------- sound/soc/intel/skylake/skl-topology.h | 13 +++++++++ sound/soc/intel/skylake/skl-tplg-interface.h | 12 -------- 6 files changed, 48 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1f9f33d34000..e4a382870132 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -23,7 +23,6 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "skl-sst-ipc.h" -#include "skl-tplg-interface.h" #define BXT_BASEFW_TIMEOUT 3000 #define BXT_INIT_TIMEOUT 500 @@ -52,7 +51,7 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) } static int -bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) +bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { struct snd_dma_buffer dmab; struct skl_sst *skl = ctx->thread_context; @@ -61,11 +60,11 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) int ret = 0, i, dma_id, stream_tag; /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < minfo->lib_count; i++) { - ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev); + for (i = 1; i < lib_count; i++) { + ret = request_firmware(&fw, linfo[i].name, ctx->dev); if (ret < 0) { dev_err(ctx->dev, "Request lib %s failed:%d\n", - minfo->lib[i].name, ret); + linfo[i].name, ret); return ret; } @@ -96,7 +95,7 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i); if (ret < 0) dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", - minfo->lib[i].name, ret); + linfo[i].name, ret); ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); @@ -119,8 +118,7 @@ load_library_failed: static int sst_bxt_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) { - int stream_tag, ret, i; - u32 reg; + int stream_tag, ret; stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); if (stream_tag <= 0) { @@ -432,7 +430,6 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) int ret; struct skl_ipc_dxstate_info dx; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_dfw_manifest *minfo = &skl->manifest; if (skl->fw_loaded == false) { skl->boot_complete = false; @@ -442,8 +439,9 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) return ret; } - if (minfo->lib_count > 1) { - ret = bxt_load_library(ctx, minfo); + if (skl->lib_count > 1) { + ret = bxt_load_library(ctx, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(ctx->dev, "reload libs failed: %d\n", ret); return ret; @@ -640,8 +638,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->manifest.lib_count > 1) { - ret = sst->fw_ops.load_library(sst, &ctx->manifest); + if (ctx->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, ctx->lib_info, + ctx->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 7c272ba0f4b5..849410d0823e 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -19,7 +19,6 @@ #include #include #include "skl-sst-cldma.h" -#include "skl-tplg-interface.h" #include "skl-topology.h" struct sst_dsp; @@ -145,7 +144,7 @@ struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ int (*load_library)(struct sst_dsp *ctx, - struct skl_dfw_manifest *minfo); + struct skl_lib_info *linfo, int count); int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); @@ -236,5 +235,4 @@ int skl_get_pvt_instance_id_map(struct skl_sst *ctx, void skl_freeup_uuid_list(struct skl_sst *ctx); int skl_dsp_strip_extended_manifest(struct firmware *fw); - #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index cc40341233fa..9660ace379ab 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -97,8 +97,9 @@ struct skl_sst { /* multi-core */ struct skl_dsp_cores cores; - /* tplg manifest */ - struct skl_dfw_manifest manifest; + /* library info */ + struct skl_lib_info lib_info[SKL_MAX_LIB]; + int lib_count; /* Callback to update D0i3C register */ void (*update_d0i3c)(struct device *dev, bool enable); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 422a9dee9270..e6e76237f46b 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2300,20 +2300,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, static int skl_tplg_fill_str_mfest_tkn(struct device *dev, struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0; static int ref_count; switch (str_elem->token) { case SKL_TKN_STR_LIB_NAME: - if (ref_count > minfo->lib_count - 1) { + if (ref_count > skl->skl_sst->lib_count - 1) { ref_count = 0; return -EINVAL; } - strncpy(minfo->lib[ref_count].name, str_elem->string, - ARRAY_SIZE(minfo->lib[ref_count].name)); + strncpy(skl->skl_sst->lib_info[ref_count].name, + str_elem->string, + ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); ref_count++; tkn_count++; break; @@ -2328,14 +2329,14 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev, static int skl_tplg_get_str_tkn(struct device *dev, struct snd_soc_tplg_vendor_array *array, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0, ret; struct snd_soc_tplg_vendor_string_elem *str_elem; str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; while (tkn_count < array->num_elems) { - ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo); + ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); str_elem++; if (ret < 0) @@ -2349,13 +2350,13 @@ static int skl_tplg_get_str_tkn(struct device *dev, static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dfw_manifest *minfo) + struct skl *skl) { int tkn_count = 0; switch (tkn_elem->token) { case SKL_TKN_U32_LIB_COUNT: - minfo->lib_count = tkn_elem->value; + skl->skl_sst->lib_count = tkn_elem->value; tkn_count++; break; @@ -2372,7 +2373,7 @@ static int skl_tplg_get_int_tkn(struct device *dev, * type. */ static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl_dfw_manifest *minfo, + char *pvt_data, struct skl *skl, int block_size) { int tkn_count = 0, ret; @@ -2388,7 +2389,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, off += array->size; switch (array->type) { case SND_SOC_TPLG_TUPLE_TYPE_STRING: - ret = skl_tplg_get_str_tkn(dev, array, minfo); + ret = skl_tplg_get_str_tkn(dev, array, skl); if (ret < 0) return ret; @@ -2410,7 +2411,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, while (tkn_count <= array->num_elems - 1) { ret = skl_tplg_get_int_tkn(dev, - tkn_elem, minfo); + tkn_elem, skl); if (ret < 0) return ret; @@ -2431,7 +2432,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, * preceded by descriptors for type and size of data block. */ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl_dfw_manifest *minfo) + struct device *dev, struct skl *skl) { struct snd_soc_tplg_vendor_array *array; int num_blocks, block_size = 0, block_type, off = 0; @@ -2474,7 +2475,7 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, data = (manifest->priv.data + off); if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_manifest_tkn(dev, data, minfo, + ret = skl_tplg_get_manifest_tkn(dev, data, skl, block_size); if (ret < 0) @@ -2492,27 +2493,23 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, static int skl_manifest_load(struct snd_soc_component *cmpnt, struct snd_soc_tplg_manifest *manifest) { - struct skl_dfw_manifest *minfo; struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl *skl = ebus_to_skl(ebus); - int ret = 0; /* proceed only if we have private data defined */ if (manifest->priv.size == 0) return 0; - minfo = &skl->skl_sst->manifest; - - skl_tplg_get_manifest_data(manifest, bus->dev, minfo); + skl_tplg_get_manifest_data(manifest, bus->dev, skl); - if (minfo->lib_count > HDA_MAX_LIB) { + if (skl->skl_sst->lib_count > SKL_MAX_LIB) { dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - minfo->lib_count); - ret = -EINVAL; + skl->skl_sst->lib_count); + return -EINVAL; } - return ret; + return 0; } static struct snd_soc_tplg_ops skl_tplg_ops = { diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index a0d3158196f0..fefab0e99a3b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -334,6 +334,19 @@ struct skl_pipeline { struct list_head node; }; +#define SKL_LIB_NAME_LENGTH 128 +#define SKL_MAX_LIB 16 + +struct skl_lib_info { + char name[SKL_LIB_NAME_LENGTH]; + const struct firmware *fw; +}; + +struct skl_manifest { + u32 lib_count; + struct skl_lib_info lib[SKL_MAX_LIB]; +}; + static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 2f6281e056d6..7a2febf99019 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -157,18 +157,6 @@ struct skl_dfw_algo_data { char params[0]; } __packed; -#define LIB_NAME_LENGTH 128 -#define HDA_MAX_LIB 16 - -struct lib_info { - char name[LIB_NAME_LENGTH]; -} __packed; - -struct skl_dfw_manifest { - u32 lib_count; - struct lib_info lib[HDA_MAX_LIB]; -} __packed; - enum skl_tkn_dir { SKL_DIR_IN, SKL_DIR_OUT -- cgit From 9cc8f9fe0f9e84771f2872f8939d37414ef9d58d Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 2 Jan 2017 09:50:02 +0530 Subject: ASoC: Intel: Common: Update dsp register poll implementation Poll implementation is not quite accurate, especially for smaller values of timeout or timeout values close to the actual timeout needed Use jiffies to set the timeout value and time_before() to get the accurate time. So update the dsp register poll implementation to provide accurate timeout using jiffies. Signed-off-by: Jayachandran B Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp.c | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index c00ede4ea4d7..11c0805393ff 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -252,44 +252,44 @@ void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 timeout, char *operation) + u32 target, u32 time, char *operation) { - int time, ret; u32 reg; - bool done = false; + unsigned long timeout; + int k = 0, s = 500; /* - * we will poll for couple of ms using mdelay, if not successful - * then go to longer sleep using usleep_range + * split the loop into sleeps of varying resolution. more accurately, + * the range of wakeups are: + * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. + * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms + * (usleep_range (500, 1000) and usleep_range(5000, 10000) are + * both possible in this phase depending on whether k > 10 or not). + * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms. */ - /* check if set state successful */ - for (time = 0; time < 5; time++) { - if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) { - done = true; - break; - } - mdelay(1); + timeout = jiffies + msecs_to_jiffies(time); + while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target) + && time_before(jiffies, timeout)) { + k++; + if (k > 10) + s = 5000; + + usleep_range(s, 2*s); } - if (done == false) { - /* sleeping in 10ms steps so adjust timeout value */ - timeout /= 10; + reg = sst_dsp_shim_read_unlocked(ctx, offset); - for (time = 0; time < timeout; time++) { - if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) - break; + if ((reg & mask) == target) { + dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", + reg, operation); - usleep_range(5000, 10000); - } + return 0; } - reg = sst_dsp_shim_read_unlocked(ctx, offset); - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, - (time < timeout) ? "successful" : "timedout"); - ret = time < timeout ? 0 : -ETIME; - - return ret; + dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n", + reg, operation); + return -ETIME; } EXPORT_SYMBOL_GPL(sst_dsp_register_poll); -- cgit From 1448099dd3d55546057cdda0493a6493c007b9fd Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 2 Jan 2017 09:50:03 +0530 Subject: ASoC: Intel: bxtn: Use DSP poll API to poll FW status Use the optimized dsp_register_poll API to poll the DSP firmware status register rather than open coding it. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index e4a382870132..15a063a403cc 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -151,23 +151,13 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, } /* Step 4: Wait for DONE Bit */ - for (i = BXT_INIT_TIMEOUT; i > 0; --i) { - reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); - - if (reg & SKL_ADSP_REG_HIPCIE_DONE) { - sst_dsp_shim_update_bits_forced(ctx, - SKL_ADSP_REG_HIPCIE, + ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE, SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE); - break; - } - mdelay(1); - } - if (!i) { - dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE); + SKL_ADSP_REG_HIPCIE_DONE, + BXT_INIT_TIMEOUT, "HIPCIE Done"); + if (ret < 0) { + dev_err(ctx->dev, "Timout for Purge Request%d\n", ret); + goto base_fw_load_failed; } /* Step 5: power down core1 */ @@ -182,19 +172,10 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, skl_ipc_op_int_enable(ctx); /* Step 7: Wait for ROM init */ - for (i = BXT_INIT_TIMEOUT; i > 0; --i) { - if (SKL_FW_INIT == - (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & - SKL_FW_STS_MASK)) { - - dev_info(ctx->dev, "ROM loaded, continue FW loading\n"); - break; - } - mdelay(1); - } - if (!i) { - dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg); - ret = -EIO; + ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, + SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load"); + if (ret < 0) { + dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); goto base_fw_load_failed; } -- cgit From 09a8bf812c662c833621f19955a1d3fa495801bc Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 2 Jan 2017 12:44:28 +0530 Subject: ALSA: hda: check stream decoupled register state Check stream decoupled register value with requested value before decoupling/coupling the stream. Signed-off-by: Jeeja KP Acked-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/hda/ext/hdac_ext_stream.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 3be051ab5533..c96d7a7a36af 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus, { struct hdac_stream *hstream = &stream->hstream; struct hdac_bus *bus = &ebus->bus; + u32 val; + int mask = AZX_PPCTL_PROCEN(hstream->index); spin_lock_irq(&bus->reg_lock); - if (decouple) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, - AZX_PPCTL_PROCEN(hstream->index)); - else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, - AZX_PPCTL_PROCEN(hstream->index), 0); + val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask; + + if (decouple && !val) + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask); + else if (!decouple && val) + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0); + stream->decoupled = decouple; spin_unlock_irq(&bus->reg_lock); } -- cgit From dd8275771f7a65dd552137e1839d39e15b313ed2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2017 15:12:27 +0200 Subject: ASoC: Intel: remove redundant select SND_SOC_INTEL_SST SND_SOC_INTEL_SKYLAKE selects SND_SOC_INTEL_SST already. Thus no need to duplicate. Remove duplications. Acked-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index fd5d1e091038..86766d7c18b0 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -68,7 +68,6 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_DA7219 select SND_SOC_MAX98357A @@ -84,7 +83,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH config SND_SOC_INTEL_BXT_RT298_MACH tristate "ASoC Audio driver for Broxton with RT298 I2S mode" depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT298 select SND_SOC_DMIC @@ -220,7 +218,6 @@ config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKL_RT286_MACH tristate "ASoC Audio driver for SKL with RT286 I2S mode" depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT286 select SND_SOC_DMIC @@ -234,7 +231,6 @@ config SND_SOC_INTEL_SKL_RT286_MACH config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_NAU8825 select SND_SOC_SSM4567 @@ -249,7 +245,6 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST select SND_SOC_INTEL_SKYLAKE select SND_SOC_NAU8825 select SND_SOC_MAX98357A -- cgit From 231a091ef8dece94b0ad2b85affb059c483af33c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2017 15:12:29 +0200 Subject: ASoC: Intel: rename SND_SST_MFLD_PLATFORM to SND_SST_ATOM_HIFI2_PLATFORM Rename SND_SST_MFLD_PLATFORM to SND_SST_ATOM_HIFI2_PLATFORM to make it clear that is not only about Medfield platform. The new name is derived from Intel Atom and HiFi2. HiFi2 is the DSP version, it's public information for Intel *Field/*Trail parts, see https://www.alsa-project.org/main/index.php/Firmware. By combining HiFi2 with Atom we get a unique non-ambiguous description of the core+DSP hardware for Intel Medfield through Intel Cherrytrail. Suggested-by: Pierre-Louis Bossart Acked-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 14 +++++++------- sound/soc/intel/Makefile | 2 +- sound/soc/intel/atom/Makefile | 7 ++++--- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 1 + 4 files changed, 13 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 86766d7c18b0..9e3b25069de3 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -2,7 +2,7 @@ config SND_MFLD_MACHINE tristate "SOC Machine Audio driver for Intel Medfield MID platform" depends on INTEL_SCU_IPC select SND_SOC_SN95031 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_PCI help This adds support for ASoC machine driver for Intel(R) MID Medfield platform @@ -10,7 +10,7 @@ config SND_MFLD_MACHINE Say Y if you have such a device. If unsure select "N". -config SND_SST_MFLD_PLATFORM +config SND_SST_ATOM_HIFI2_PLATFORM tristate select SND_SOC_COMPRESS @@ -148,7 +148,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5640 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -161,7 +161,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" depends on X86 && I2C && ACPI select SND_SOC_RT5651 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -174,7 +174,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5670 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -187,7 +187,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_RT5645 - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help @@ -200,7 +200,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH depends on X86_INTEL_LPSS && I2C && ACPI select SND_SOC_MAX98090 select SND_SOC_TS3A227E - select SND_SST_MFLD_PLATFORM + select SND_SST_ATOM_HIFI2_PLATFORM select SND_SST_IPC_ACPI select SND_SOC_INTEL_SST_MATCH if ACPI help diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 2b45435e6245..cdd495f7ee2c 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ # Platform Support obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ -obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/ +obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/ # Machine support diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile index ce8074fa6d66..aa6548c6feab 100644 --- a/sound/soc/intel/atom/Makefile +++ b/sound/soc/intel/atom/Makefile @@ -1,7 +1,8 @@ -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ - sst-mfld-platform-compress.o sst-atom-controls.o +snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o \ + sst-atom-controls.o -obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o +obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += snd-soc-sst-atom-hifi2-platform.o # DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 0fd7848fbe4a..21cac1c8dd4c 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -839,4 +839,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); MODULE_AUTHOR("Vinod Koul "); MODULE_AUTHOR("Harsha Priya "); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sst-atom-hifi2-platform"); MODULE_ALIAS("platform:sst-mfld-platform"); -- cgit From ebf79091bf85d9b2270ab29191de9cd3aaf888c5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2017 15:12:26 +0200 Subject: ASoC: Intel: select DW_DMAC_CORE since it's mandatory Select DW_DMAC_CORE like the rest of glue drivers do, e.g. drivers/dma/dw/Kconfig. While here group selectors under SND_SOC_INTEL_HASWELL and SND_SOC_INTEL_BAYTRAIL. Make platforms, which are using a common SST firmware driver, to be dependent on DMADEVICES. Signed-off-by: Andy Shevchenko Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 9e3b25069de3..93c41b7219f2 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -33,11 +33,9 @@ config SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_MATCH if ACPI depends on (X86 || COMPILE_TEST) -# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from -# the reverse selection, each machine driver needs to select -# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE config SND_SOC_INTEL_SST_FIRMWARE tristate + select DW_DMAC_CORE config SND_SOC_INTEL_SST_ACPI tristate @@ -47,16 +45,18 @@ config SND_SOC_INTEL_SST_MATCH config SND_SOC_INTEL_HASWELL tristate + select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_BAYTRAIL tristate + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -97,9 +97,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE + depends on DMADEVICES + depends on SND_SST_IPC_ACPI = n select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -110,9 +109,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE + depends on DMADEVICES + depends on SND_SST_IPC_ACPI = n select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -121,9 +119,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BDW_RT5677_MACH tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" - depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC - depends on DW_DMAC_CORE=y - select SND_SOC_INTEL_SST + depends on X86_INTEL_LPSS && GPIOLIB && I2C + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT5677 help @@ -132,10 +129,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ - I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST + depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help -- cgit From 2914266975fcb09a688cefe98874625366e67c65 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 16 Jan 2017 15:12:28 +0200 Subject: ASoC: Intel: remove ignored dependencies For selected only options the explicit dependencies do not make much sense becase Kbuild ignores them anyway. Remove them explicitly. Acked-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 93c41b7219f2..526855ad479e 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -31,7 +31,6 @@ config SND_SOC_INTEL_SST tristate select SND_SOC_INTEL_SST_ACPI if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI - depends on (X86 || COMPILE_TEST) config SND_SOC_INTEL_SST_FIRMWARE tristate -- cgit From 345233d7c6be80d4124140f2a0993880c7ae2453 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Sat, 14 Jan 2017 16:13:02 +0800 Subject: ASoC: core: Add API to use DMI name in sound card long name Intel DSP platform drivers are used by many different devices but are difficult for userspace to differentiate. This patch adds an API to allow the DMI name to be used in the sound card long name, thereby helping userspace load the correct UCM configuration. Usually machine drivers uses their own name as the sound card name (short name), and leave the long name and driver name blank. This API will use the DMI info like vendor, product and board to make up the card long name. If the machine driver has already explicitly set the long name, this API will do nothing. This patch also allows for further differentiation as many devices that share the same DMI name i.e. Minnowboards, UP boards may be configured with different codecs or firmwares. The API supports flavoring the DMI name into the card longname to provide the extra differentiation required for these devices. For Use Case Manager (UCM) in the user space, changing card long name by this API is backward compatible, since the card name does not change. For a given sound card, even if there is no device-specific UCM configuration file that uses the card long name, UCM will fall back to load the default configuration file that uses the card name. Signed-off-by: Liam Girdwood Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f1901bb1466e..530a4dba0709 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -1888,6 +1889,139 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); + +/* Trim special characters, and replace '-' with '_' since '-' is used to + * separate different DMI fields in the card long name. Only number and + * alphabet characters and a few separator characters are kept. + */ +static void cleanup_dmi_name(char *name) +{ + int i, j = 0; + + for (i = 0; name[i]; i++) { + if (isalnum(name[i]) || (name[i] == '.') + || (name[i] == '_')) + name[j++] = name[i]; + else if (name[i] == '-') + name[j++] = '_'; + } + + name[j] = '\0'; +} + +/** + * snd_soc_set_dmi_name() - Register DMI names to card + * @card: The card to register DMI names + * @flavour: The flavour "differentiator" for the card amongst its peers. + * + * An Intel machine driver may be used by many different devices but are + * difficult for userspace to differentiate, since machine drivers ususally + * use their own name as the card short name and leave the card long name + * blank. To differentiate such devices and fix bugs due to lack of + * device-specific configurations, this function allows DMI info to be used + * as the sound card long name, in the format of + * "vendor-product-version-board" + * (Character '-' is used to separate different DMI fields here). + * This will help the user space to load the device-specific Use Case Manager + * (UCM) configurations for the card. + * + * Possible card long names may be: + * DellInc.-XPS139343-01-0310JH + * ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA + * Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX + * + * This function also supports flavoring the card longname to provide + * the extra differentiation, like "vendor-product-version-board-flavor". + * + * We only keep number and alphabet characters and a few separator characters + * in the card long name since UCM in the user space uses the card long names + * as card configuration directory names and AudoConf cannot support special + * charactors like SPACE. + * + * Returns 0 on success, otherwise a negative error code. + */ +int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) +{ + const char *vendor, *product, *product_version, *board; + size_t longname_buf_size = sizeof(card->snd_card->longname); + size_t len; + + if (card->long_name) + return 0; /* long name already set by driver or from DMI */ + + /* make up dmi long name as: vendor.product.version.board */ + vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + if (!vendor) { + dev_warn(card->dev, "ASoC: no DMI vendor name!\n"); + return 0; + } + + snprintf(card->dmi_longname, sizeof(card->snd_card->longname), + "%s", vendor); + cleanup_dmi_name(card->dmi_longname); + + product = dmi_get_system_info(DMI_PRODUCT_NAME); + if (product) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", product); + + len++; /* skip the separator "-" */ + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + + /* some vendors like Lenovo may only put a self-explanatory + * name in the product version field + */ + product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); + if (product_version) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", product_version); + + len++; + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + } + } + + board = dmi_get_system_info(DMI_BOARD_NAME); + if (board) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", board); + + len++; + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + } else if (!product) { + /* fall back to using legacy name */ + dev_warn(card->dev, "ASoC: no DMI board/product name!\n"); + return 0; + } + + /* Add flavour to dmi long name */ + if (flavour) { + len = strlen(card->dmi_longname); + snprintf(card->dmi_longname + len, + longname_buf_size - len, + "-%s", flavour); + + len++; + if (len < longname_buf_size) + cleanup_dmi_name(card->dmi_longname + len); + } + + /* set the card long name */ + card->long_name = card->dmi_longname; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name); + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; -- cgit From 3122c66fd2159f4ab210da8d95465af2f145fad7 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Sat, 14 Jan 2017 16:13:09 +0800 Subject: ASoC: Intel: Use DMI name for sound card long name in Broadwell machine driver Intel Broadwell machine driver will call API snd_soc_set_dmi_name() to use DMI info to make the sound card long name. For example, here are the changed long name for two Broadwell-based machines: Dell XPS-13(2015): DellInc.-XPS139343-01-0310JH Intel WilsonBeach: Intel Corp.-BroadwellClientplatform-0.1-WilsonBeachSDS They still share the same card name "broadwell-rt286". Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 4d7e9decfa92..faf865bb1765 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -270,6 +270,8 @@ static int broadwell_audio_probe(struct platform_device *pdev) { broadwell_rt286.dev = &pdev->dev; + snd_soc_set_dmi_name(&broadwell_rt286, NULL); + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } -- cgit From 7cbfdf87f422211b9a1f2845acb2e39597b3ef7e Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 10 Jan 2017 17:57:46 +0530 Subject: ASoC: Intel: Skylake: Don't reset pass-through pipe in BE prepare When pipe is pass-through, BE and FE modules are defined inside a pipe, reset of pipe will be done in FE DAI prepare. So don't reset in the BE prepare. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 10fa10df4e57..aefcfca810f4 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -572,8 +572,8 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig && (substream->runtime->status->state == - SNDRV_PCM_STATE_XRUN)) + if (mconfig && !mconfig->pipe->passthru && + (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); return 0; -- cgit From a700a1e65aa3ee76d2e8c58150ee7b7272d93608 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 10 Jan 2017 17:57:47 +0530 Subject: ASoC: Intel: Skylake: set the resume point to LPIB In system suspend, the firmware pipelines will be deleted and there is no need to save the pipeline context. Driver will save the DPIB and LPIB pointers in suspend. In system resume, the firmware pipelines will be created again and the RD/RW pointers in the Firmware buffer points to the base address. So need to fetch the non-played data again to firmware buffer. LPIB indicates the HW rendered position. Instead of setting DPIB as resume point, set it to LPIB to restore from the HW render position so that DMA would fetch the non-played data one more time. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index aefcfca810f4..ae7997ab19b1 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -474,7 +474,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, snd_hdac_ext_stream_drsm_enable(ebus, true, hdac_stream(stream)->index); snd_hdac_ext_stream_set_dpibr(ebus, stream, - stream->dpib); + stream->lpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } -- cgit From 1de777fed54dfa93e166a3c934c5846920b86f0c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 10 Jan 2017 17:57:48 +0530 Subject: ASoC: hdac_hdmi: Enable pin and converter in prepare Instead of enabling pin and cvt in pcm_open(), need to restore pin and cvt state after system resume to restart the playback which is paused/stopped before system suspend. So enable pin and cvt in playback_prepare and call prepare when trigger cmd is paused/started and resume to reconfigure pin and cvt. Signed-off-by: Sachin Mokashi Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c602c4960924..1da4405ee435 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -114,6 +114,12 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; }; +static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map); + +static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, + struct hdac_hdmi_dai_pin_map *dai_map); + static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) { @@ -411,6 +417,10 @@ 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); + hdac_hdmi_enable_cvt(hdac, dai_map); + ret = hdac_hdmi_enable_pin(hdac, dai_map); + if (ret < 0) + return ret; mutex_lock(&pin->lock); pin->channels = substream->runtime->channels; @@ -464,12 +474,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); struct hdac_ext_dma_params *dd; - struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; - - dai_map = &hdmi->dai_map[dai->id]; dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); @@ -622,11 +627,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, dai_map->pin = pin; - hdac_hdmi_enable_cvt(hdac, dai_map); - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; - ret = hdac_hdmi_eld_limit_formats(substream->runtime, pin->eld.eld_buffer); if (ret < 0) @@ -639,18 +639,15 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; - int ret; - - dai_map = &hdmi->dai_map[dai->id]; - if (cmd == SNDRV_PCM_TRIGGER_RESUME) { - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: return hdac_hdmi_playback_prepare(substream, dai); + + default: + return 0; } return 0; -- cgit From 079a248b0e4c24432dc4838cad333b2e759813e0 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 11 Jan 2017 21:18:05 -0800 Subject: ASoC: Intel: boards: Remove ignore_suspend for WoV streams When Ref capture is used during S0IX, only the DSP pipelines are needed, thus remove the ignore_suspend for WoV streams so that DMA can be suspended, but keep them for WoV endpoints. Signed-off-by: Yong Zhi Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 1b4330cd2739..02439ace3519 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -357,7 +357,6 @@ static struct snd_soc_dai_link broxton_dais[] = { .platform_name = "0000:00:0e.0", .init = NULL, .dpcm_capture = 1, - .ignore_suspend = 1, .nonatomic = 1, .dynamic = 1, .ops = &broxton_refcap_ops, -- cgit From f6fa11a35c548a516a41ce1669d0dbcdaabb267f Mon Sep 17 00:00:00 2001 From: Sandeep Tayal Date: Wed, 18 Jan 2017 21:34:41 +0530 Subject: ASoC: hdac_hdmi: use audio component framework to read ELD With codec read sometimes the pin_sense shows invalid monitor present and eld_valid. Currently driver polls for few times to get the valid eld data. To avoid the latency, Instead of reading ELD from codec, read it directly from the display driver using audio component framework. and removed the unused direct codec helper functions. Signed-off-by: Sandeep Tayal Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 201 ++++++++++++------------------------------- 1 file changed, 56 insertions(+), 145 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1da4405ee435..261c31890827 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -46,6 +46,10 @@ #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20 +#define ELD_VER_CEA_861D 2 +#define ELD_VER_PARTIAL 31 +#define ELD_MAX_MNL 16 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -81,8 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - int repoll_count; - struct delayed_work work; struct mutex lock; bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ @@ -179,80 +181,6 @@ format_constraint: } - /* HDMI ELD routines */ -static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, - hda_nid_t nid, int byte_index) -{ - unsigned int val; - - val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, - byte_index); - - dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", - byte_index, val); - - return val; -} - -static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) -{ - return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -/* - * This function queries the ELD size and ELD data and fills in the buffer - * passed by user - */ -static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) -{ - int i, size, ret = 0; - - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned. - */ - - size = hdac_hdmi_get_eld_size(codec, nid); - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - /* set ELD buffer */ - for (i = 0; i < size; i++) { - unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); - /* - * Graphics driver might be writing to ELD buffer right now. - * Just abort. The caller will repoll after a while. - */ - if (!(val & AC_ELDD_ELD_VALID)) { - dev_err(&codec->dev, - "HDMI: invalid ELD data byte %d\n", i); - ret = -EINVAL; - goto error; - } - val &= AC_ELDD_ELD_DATA; - /* - * The first byte cannot be zero. This can happen on some DVI - * connections. Some Intel chips may also need some 250ms delay - * to return non-zero ELD data, even when the graphics driver - * correctly writes ELD content before setting ELD_valid bit. - */ - if (!val && !i) { - dev_err(&codec->dev, "HDMI: 0 ELD data\n"); - ret = -EINVAL; - goto error; - } - buf[i] = val; - } - - *eld_size = size; -error: - return ret; -} - static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -1056,32 +984,59 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); } -static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev, +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin) { + unsigned int ver, mnl; + + ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + >> DRM_ELD_VER_SHIFT; + + if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { + dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + return -EINVAL; + } + + mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; + + if (mnl > ELD_MAX_MNL) { + dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + return -EINVAL; + } + pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + + return 0; } -static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int val; - - pin->repoll_count = repoll; + int size; - pm_runtime_get_sync(&edev->hdac.dev); - val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + mutex_lock(&hdmi->pin_mutex); + pin->eld.monitor_present = false; - dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", - val, pin->nid); + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + &pin->eld.monitor_present, pin->eld.eld_buffer, + ELD_MAX_SIZE); + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(edev, pin) < 0) + size = -EINVAL; + } - mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); - pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + if (size > 0) { + pin->eld.eld_valid = true; + pin->eld.eld_size = size; + } else { + pin->eld.eld_valid = false; + pin->eld.eld_size = 0; + } pcm = hdac_hdmi_get_pcm(edev, pin); @@ -1103,66 +1058,23 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) } mutex_unlock(&hdmi->pin_mutex); - goto put_hdac_device; + return; } if (pin->eld.monitor_present && pin->eld.eld_valid) { - /* TODO: use i915 component for reading ELD later */ - if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, - pin->eld.eld_buffer, - &pin->eld.eld_size) == 0) { - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } - hdac_hdmi_parse_eld(edev, pin); - - print_hex_dump_debug("ELD: ", - DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, - true); - } else { - pin->eld.monitor_present = false; - pin->eld.eld_valid = false; - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); - snd_jack_report(pcm->jack, 0); - } + snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + pin->eld.eld_buffer, pin->eld.eld_size, false); } mutex_unlock(&hdmi->pin_mutex); - - /* - * Sometimes the pin_sense may present invalid monitor - * present and eld_valid. If ELD data is not valid, loop few - * more times to get correct pin sense and valid ELD. - */ - if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) - schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); - -put_hdac_device: - pm_runtime_put_sync(&edev->hdac.dev); -} - -static void hdac_hdmi_repoll_eld(struct work_struct *work) -{ - struct hdac_hdmi_pin *pin = - container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); - - /* picked from legacy HDA driver */ - if (pin->repoll_count++ > 6) - pin->repoll_count = 0; - - hdac_hdmi_present_sense(pin, pin->repoll_count); } static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) @@ -1181,7 +1093,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) pin->edev = edev; mutex_init(&pin->lock); - INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); return 0; } @@ -1392,7 +1303,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port) list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); } } @@ -1493,7 +1404,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) } list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1558,7 +1469,7 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); pm_runtime_put_sync(&edev->hdac.dev); } -- cgit From c9bfb5d74dd2a704bf3c622c6b268f6dc6f37ca6 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:03 +0530 Subject: ASoC: hdac_hdmi: Register widget event handlers In case of hdmi connect/disconnect or when stream need to be route to multiple monitors, corresponding port and audio infoframe needs to be reconfigured. Currently all the configuration are done in DAI ops which results in silence playback. So use dapm widget event handlers to program audio infoframe and enable /disable port configuration when widget is power on/off. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 350 ++++++++++++++++++++++--------------------- 1 file changed, 183 insertions(+), 167 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 4b4e376cc3f6..c0b49f4b7074 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -97,6 +97,9 @@ struct hdac_hdmi_pcm { struct hdac_hdmi_pin *pin; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; + int stream_tag; + int channels; + int format; }; struct hdac_hdmi_dai_pin_map { @@ -116,11 +119,19 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; }; -static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map); +static struct hdac_hdmi_pcm * +hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_cvt *cvt) +{ + struct hdac_hdmi_pcm *pcm = NULL; + + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->cvt == cvt) + break; + } -static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_pin_map *dai_map); + return pcm; +} static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) @@ -181,25 +192,6 @@ format_constraint: } -static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid, - u32 stream_tag, int format) -{ - unsigned int val; - - dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", - cvt_nid, pin_nid, stream_tag, format); - - val = (stream_tag << 4); - - snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, val); - snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); - - return 0; -} - static void hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, int packet_index, int byte_index) @@ -312,54 +304,25 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, return 0; } -static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) +static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) { - /* 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, - 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, - AC_VERB_SET_POWER_STATE, pwr_state); -} - -static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_hdmi_pin *pin; - struct hdac_ext_dma_params *dd; - int ret; + struct hdac_hdmi_pcm *pcm; + + dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask); dai_map = &hdmi->dai_map[dai->id]; - pin = dai_map->pin; - dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); - dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", - dd->stream_tag, dd->format); + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); - hdac_hdmi_enable_cvt(hdac, dai_map); - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; - mutex_lock(&pin->lock); - pin->channels = substream->runtime->channels; + if (pcm) + pcm->stream_tag = (tx_mask << 4); - ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, - dai_map->pin->nid); - mutex_unlock(&pin->lock); - 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 0; } static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, @@ -369,7 +332,8 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; struct hdac_hdmi_pin *pin; - struct hdac_ext_dma_params *dd; + struct hdac_hdmi_pcm *pcm; + int format; dai_map = &hdmi->dai_map[dai->id]; pin = dai_map->pin; @@ -383,74 +347,16 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return -ENODEV; } - dd = snd_soc_dai_get_dma_data(dai, substream); - if (!dd) { - dd = kzalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; - } - - dd->format = snd_hdac_calc_stream_format(params_rate(hparams), + format = snd_hdac_calc_stream_format(params_rate(hparams), params_channels(hparams), params_format(hparams), 24, 0); - snd_soc_dai_set_dma_data(dai, substream, (void *)dd); - - return 0; -} - -static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_dma_params *dd; - - dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); - - if (dd) { - snd_soc_dai_set_dma_data(dai, substream, NULL); - kfree(dd); - } - - return 0; -} - -static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map) -{ - /* Enable transmission */ - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_1, 1); - - /* Category Code (CC) to zero */ - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_2, 0); -} - -static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_pin_map *dai_map) -{ - int mux_idx; - struct hdac_hdmi_pin *pin = dai_map->pin; - - for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) { - if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) { - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, - AC_VERB_SET_CONNECT_SEL, mux_idx); - break; - } - } - - if (mux_idx == pin->num_mux_nids) + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); + if (!pcm) return -EIO; - /* Enable out path for this pin widget */ - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); - - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + pcm->format = format; + pcm->channels = params_channels(hparams); return 0; } @@ -564,23 +470,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, pin->eld.eld_buffer); } -static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - return hdac_hdmi_playback_prepare(substream, dai); - - default: - return 0; - } - - return 0; -} - static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -591,16 +480,6 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; if (dai_map->pin) { - snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, 0); - snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_STREAM_FORMAT, 0); - - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); - - snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - mutex_lock(&dai_map->pin->lock); dai_map->pin->chmap_set = false; memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); @@ -641,10 +520,11 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) } static int hdac_hdmi_fill_widget_info(struct device *dev, - struct snd_soc_dapm_widget *w, - enum snd_soc_dapm_type id, void *priv, - const char *wname, const char *stream, - struct snd_kcontrol_new *wc, int numkc) + struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id, + void *priv, const char *wname, const char *stream, + struct snd_kcontrol_new *wc, int numkc, + int (*event)(struct snd_soc_dapm_widget *, + struct snd_kcontrol *, int), unsigned short event_flags) { w->id = id; w->name = devm_kstrdup(dev, wname, GFP_KERNEL); @@ -657,6 +537,8 @@ static int hdac_hdmi_fill_widget_info(struct device *dev, w->kcontrol_news = wc; w->num_kcontrols = numkc; w->priv = priv; + w->event = event; + w->event_flags = event_flags; return 0; } @@ -686,6 +568,136 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, return NULL; } +static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, + hda_nid_t nid, unsigned int pwr_state) +{ + if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) { + if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state)) + snd_hdac_codec_write(&edev->hdac, nid, 0, + AC_VERB_SET_POWER_STATE, pwr_state); + } +} + +static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, + hda_nid_t nid, int val) +{ + if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP) + snd_hdac_codec_write(&edev->hdac, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); +} + + +static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct hdac_hdmi_pin *pin = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); + struct hdac_hdmi_pcm *pcm; + + dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + __func__, w->name, event); + + pcm = hdac_hdmi_get_pcm(edev, pin); + if (!pcm) + return -EIO; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D0); + + /* Enable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); + + return hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, + pin->nid); + + case SND_SOC_DAPM_POST_PMD: + hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); + + /* Disable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + + hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D3); + break; + + } + + return 0; +} + +static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct hdac_hdmi_cvt *cvt = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm; + + dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + __func__, w->name, event); + + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt); + if (!pcm) + return -EIO; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0); + + /* Enable transmission */ + 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, + AC_VERB_SET_DIGI_CONVERT_2, 0); + + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag); + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_STREAM_FORMAT, pcm->format); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_STREAM_FORMAT, 0); + + hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3); + break; + + } + + return 0; +} + +static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct hdac_hdmi_pin *pin = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); + int mux_idx; + + dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + __func__, w->name, event); + + if (!kc) + kc = w->kcontrols[0]; + + mux_idx = dapm_kcontrol_get_value(kc); + if (mux_idx > 0) { + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); + } + + return 0; +} + /* * Based on user selection, map the PINs with the PCMs. */ @@ -803,7 +815,9 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, return -ENOMEM; return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, - snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1); + snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1, + hdac_hdmi_pin_mux_widget_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); } /* Add cvt <- input <- mux route map */ @@ -874,8 +888,10 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) list_for_each_entry(cvt, &hdmi->cvt_list, head) { sprintf(widget_name, "Converter %d", cvt->nid); ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_aif_in, &cvt->nid, - widget_name, dai_drv[i].playback.stream_name, NULL, 0); + snd_soc_dapm_aif_in, cvt, + widget_name, dai_drv[i].playback.stream_name, NULL, 0, + hdac_hdmi_cvt_output_widget_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); if (ret < 0) return ret; i++; @@ -884,8 +900,10 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) list_for_each_entry(pin, &hdmi->pin_list, head) { sprintf(widget_name, "hif%d Output", pin->nid); ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_output, &pin->nid, - widget_name, NULL, NULL, 0); + snd_soc_dapm_output, pin, + widget_name, NULL, NULL, 0, + hdac_hdmi_pin_output_widget_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); if (ret < 0) return ret; i++; @@ -1141,9 +1159,7 @@ static struct snd_soc_dai_ops hdmi_dai_ops = { .startup = hdac_hdmi_pcm_open, .shutdown = hdac_hdmi_pcm_close, .hw_params = hdac_hdmi_set_hw_params, - .prepare = hdac_hdmi_playback_prepare, - .trigger = hdac_hdmi_trigger, - .hw_free = hdac_hdmi_playback_cleanup, + .set_tdm_slot = hdac_hdmi_set_tdm_slot, }; /* -- cgit From 1011509dfd25f90db333f82fa85c39b0861d2b09 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:04 +0530 Subject: ASoC: Intel: Skylake: Use set_tdm_slot to set the dma channel DMA channel(stream tag) used by the HDA link need to programmed in codec so that codec receives packet from the link associated with the same channel. DMA channel is allocated in link BE dai hw_params, the same needs to be set for the BE codec dai. Instead of using get/set dma_data(), use dai_ops snd_soc_dai_set_tdm_slot() to set the stream tag. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index ae7997ab19b1..55dc9f27d4b2 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -532,10 +532,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; struct hdac_ext_link *link; + int stream_tag; link_dev = snd_hdac_ext_stream_assign(ebus, substream, HDAC_EXT_STREAM_TYPE_LINK); @@ -548,16 +548,16 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, if (!link) return -EINVAL; + stream_tag = hdac_stream(link_dev)->stream_tag; + /* set the stream tag in the codec dai dma params */ - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; + p_params.link_dma_id = stream_tag - 1; p_params.link_index = link->index; p_params.format = params_format(params); -- cgit From 5b101ab465c5c01b091c04b7fbaba6d912372947 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Thu, 26 Jan 2017 13:07:04 +0100 Subject: ASoC: Intel: Atom: Configure media_loop1 and sprot_loop in stereo Most of the devices are using stereo speakers so media_loop1 and sprot_loop default mode should be stereo. As per default all the routing UCM configuration doesn't enable Post processing loops it is not impacting curent configurations. Signed-off-by: Sebastien Guiriec Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index c7b3cbf92faf..0ce1d186cb68 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1087,8 +1087,8 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL), SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL), SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL), - SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop), - SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop), + SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_STEREO, sst_set_media_loop), + SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_STEREO, sst_set_media_loop), SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop), /* Media Mixers */ -- cgit From a50477e55fff69e1028f25624ee9fc9182d59b1f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:38 -0600 Subject: ASoC: Intel: cht_bsw_rt5645: add Baytrail MCLK support The existing code assumes a 19.2 MHz MCLK as the default hardware configuration. This is valid for CherryTrail but not for Baytrail. Add explicit MCLK configuration to set the 19.2 clock on/off depending on DAPM events. This is a prerequisite step to enable devices with Baytrail and RT5645 such as Asus X205TA Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 84 ++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index f504a0e18f91..468228b73b0b 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -45,6 +48,7 @@ struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; char codec_name[16]; + struct clk *mclk; }; static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) @@ -65,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct snd_soc_dai *codec_dai; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; codec_dai = cht_get_codec_dai(card); @@ -73,19 +78,30 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return -EIO; } - if (!SND_SOC_DAPM_EVENT_OFF(event)) - return 0; + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (ctx->mclk) { + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(card->dev, + "could not configure MCLK state"); + return ret; + } + } + } else { + /* Set codec sysclk source to its internal clock because codec PLL will + * be off when idle and MCLK will also be off when codec is + * runtime suspended. Codec needs clock for jack detection and button + * press. MCLK is turned off with clock framework or ACPI. + */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } - /* Set codec sysclk source to its internal clock because codec PLL will - * be off when idle and MCLK will also be off by ACPI when codec is - * runtime suspended. Codec needs clock for jack detection and button - * press. - */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, - 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "can't set codec sysclk: %d\n", ret); - return ret; + if (ctx->mclk) + clk_disable_unprepare(ctx->mclk); } return 0; @@ -97,7 +113,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD), + platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { @@ -225,6 +241,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack); + if (ctx->mclk) { + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(ctx->mclk); + if (!ret) + clk_disable_unprepare(ctx->mclk); + + ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ); + + if (ret) + dev_err(runtime->dev, "unable to set MCLK rate\n"); + } return ret; } @@ -349,6 +385,18 @@ static struct cht_acpi_card snd_soc_cards[] = { static char cht_rt5640_codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static bool is_valleyview(void) +{ + static const struct x86_cpu_id cpu_ids[] = { + { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ + {} + }; + + if (!x86_match_cpu(cpu_ids)) + return false; + return true; +} + static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; @@ -391,6 +439,16 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_dailink[dai_index].codec_name = cht_rt5640_codec_name; } + if (is_valleyview()) { + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(drv->mclk)) { + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %ld\n", + PTR_ERR(drv->mclk)); + return PTR_ERR(drv->mclk); + } + } + snd_soc_card_set_drvdata(card, drv); ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { -- cgit From 03200140ee83b3655152bc0c144378732fec8af1 Mon Sep 17 00:00:00 2001 From: Alexandrov Stansilav Date: Thu, 26 Jan 2017 14:09:31 -0600 Subject: ASoC: rt5640: Add "10EC3276" ACPI ID Add ACPI ID "10EC3276" for sound card found on notebook HP Pavilion X2 10-p000. ACPI DSDT Table on this device describes this card as ALC3276, but it is in fact rt5640. Signed-off-by: Alexandrov Stansilav Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index e29a6defefa0..b857a715ef64 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2313,6 +2313,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, + { "10EC3276", 0 }, { "10EC5640", 0 }, { "10EC5642", 0 }, { "INTCCFFD", 0 }, -- cgit From e7974816a8fce6cd11dc4dfa9f1c1844a9b5d8df Mon Sep 17 00:00:00 2001 From: Alexandrov Stansilav Date: Thu, 26 Jan 2017 14:09:32 -0600 Subject: ASoC: Intel: Atom: Add HP Pavilion x2 10-p000 machine entry Add machine entry for HP X2 Pavilion 10-p100. This notebook contains rt5640 codec, but with ACPI ID "10EC3276". Signed-off-by: Alexandrov Stansilav Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index f4d92bbc5373..896ced2dd73c 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -463,6 +463,8 @@ static struct sst_acpi_mach sst_acpi_chv[] = { /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, &chv_platform_data }, + {"10EC3276", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, + &chv_platform_data }, {}, }; -- cgit From a1a91752cb9c18a81a3e0027054d38da37243ba2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:33 -0600 Subject: ASoC: Intel: add support for Realtek 5651 on Cherrytrail RT5651 is used on some Cherrytrail platforms, add the ACPI ID in machine table. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=156191 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 896ced2dd73c..0699ce511755 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -465,7 +465,9 @@ static struct sst_acpi_mach sst_acpi_chv[] = { &chv_platform_data }, {"10EC3276", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, &chv_platform_data }, - + /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ + {"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL, + &chv_platform_data }, {}, }; -- cgit From 93ffeaa8ee3f10a0628ad135b552a2497e0bef2c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:34 -0600 Subject: ASoC: codecs: rt5670: add quirk for Lenovo Thinkpad 10 the BIOS incorrectly reports this codec as 5640 but it is really a rt5670 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 97bafac3bc15..17d20b99f041 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2814,6 +2814,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); static const struct acpi_device_id rt5670_acpi_match[] = { { "10EC5670", 0}, { "10EC5672", 0}, + { "10EC5640", 0}, /* quirk */ { }, }; MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); -- cgit From 11ad80898620e09bde6ced7147a5f762bcecce81 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:36 -0600 Subject: ASoC: rt5645: add support for RT5648 add ACPI ID 10EC5648 found e.g on Asus X205TA and use rt5645 driver Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 1 + sound/soc/intel/boards/cht_bsw_rt5645.c | 1 + 2 files changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 10c2a564a715..ccfabeb8aab7 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3545,6 +3545,7 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5645_acpi_match[] = { { "10EC5645", 0 }, + { "10EC5648", 0 }, { "10EC5650", 0 }, { "10EC5640", 0 }, {}, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 468228b73b0b..3684bdbd8598 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -380,6 +380,7 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = { static struct cht_acpi_card snd_soc_cards[] = { {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, + {"10EC5648", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, }; -- cgit From e1d06914542a198a6ab3d41b9d7f5d62dd744f8b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:39 -0600 Subject: ASoC: Intel: Atom: add machine driver for baytrail-rt5645 hardware Use machine driver initially defined for CherryTrail Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 0699ce511755..4c0b89ec42e0 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -445,6 +445,12 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { &byt_rvp_platform_data }, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, &byt_rvp_platform_data }, + /* some Baytrail platforms rely on RT5645, use CHT machine driver */ + {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, + &byt_rvp_platform_data }, + {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, + &byt_rvp_platform_data }, + {}, }; -- cgit From 42648c2270ca0c96935dfc5d0f5c4f8d2406cf75 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:41 -0600 Subject: ASoC: Intel: cht_bsw_rt5645: harden ACPI device detection Fix classic issue of having multiple codecs listed in DSDT but a single one actually enabled. The previous code did not handle such errors and could also lead to uninitalized configurations Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 3684bdbd8598..3461e4a88ba8 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -407,22 +407,32 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct sst_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; + bool found = false; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); if (!drv) return -ENOMEM; + mach = (&pdev->dev)->platform_data; + for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { - if (acpi_dev_found(snd_soc_cards[i].codec_id)) { + if (acpi_dev_found(snd_soc_cards[i].codec_id) && + (!strncmp(snd_soc_cards[i].codec_id, mach->id, 8))) { dev_dbg(&pdev->dev, "found codec %s\n", snd_soc_cards[i].codec_id); card = snd_soc_cards[i].soc_card; drv->acpi_card = &snd_soc_cards[i]; + found = true; break; } } + + if (!found) { + dev_err(&pdev->dev, "No matching HID found in supported list\n"); + return -ENODEV; + } + card->dev = &pdev->dev; - mach = card->dev->platform_data; sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); /* set correct codec name */ -- cgit From fd0138dc5d17c636477b371d99265c406437c583 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:35 -0600 Subject: ASoC: Intel: Baytrail: add quirk for Lenovo Thinkpad 10 the BIOS reports this codec as RT5640 but it's a rt5670. Use the quirk mechanism to use the cht_bsw_rt5672 machine driver Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 4c0b89ec42e0..8cc30dfbf87d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev) static unsigned long cht_machine_id; #define CHT_SURFACE_MACH 1 +#define BYT_THINKPAD_10 2 static int cht_surface_quirk_cb(const struct dmi_system_id *id) { @@ -407,6 +408,23 @@ static int cht_surface_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) +{ + cht_machine_id = BYT_THINKPAD_10; + return 1; +} + + +static const struct dmi_system_id byt_table[] = { + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"), + }, + }, + { } +}; static const struct dmi_system_id cht_table[] = { { @@ -424,6 +442,10 @@ static struct sst_acpi_mach cht_surface_mach = { "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }; +static struct sst_acpi_mach byt_thinkpad_10 = { + "10EC5640", "cht-bsw-rt5672", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, + &byt_rvp_platform_data }; + static struct sst_acpi_mach *cht_quirk(void *arg) { struct sst_acpi_mach *mach = arg; @@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg) return mach; } +static struct sst_acpi_mach *byt_quirk(void *arg) +{ + struct sst_acpi_mach *mach = arg; + + dmi_check_system(byt_table); + + if (cht_machine_id == BYT_THINKPAD_10) + return &byt_thinkpad_10; + else + return mach; +} + + static struct sst_acpi_mach sst_acpi_bytcr[] = { - {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", byt_quirk, &byt_rvp_platform_data }, {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, -- cgit From ff9d1fbb3ffa901472cbaf331c999745b5915906 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:37 -0600 Subject: ASoc: rt5645: add ACPI ID 10EC3270 ALC3270 is a low-cost version of RT5645, add ACPI ID to enable probe and use rt5645 codec driver Tested on Asus T100HA Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index ccfabeb8aab7..b0c264d361bc 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3548,6 +3548,7 @@ static const struct acpi_device_id rt5645_acpi_match[] = { { "10EC5648", 0 }, { "10EC5650", 0 }, { "10EC5640", 0 }, + { "10EC3270", 0 }, {}, }; MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); -- cgit From 22af29114eb4c400f6847d425caab460c6241c4e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:43 -0600 Subject: ASoC: Intel: cht-bsw-rt5645: add quirks for SSP0/AIF1/AIF2 routing This driver may be used on Baytrail CR platforms where SSP2 is not available. Add quirks and routing detection based on work done for RT5640. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 238 +++++++++++++++++++++++++++++--- 1 file changed, 220 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 3461e4a88ba8..24b07601fb81 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,8 @@ #include "../common/sst-acpi.h" #define CHT_PLAT_CLK_3_HZ 19200000 -#define CHT_CODEC_DAI "rt5645-aif1" +#define CHT_CODEC_DAI1 "rt5645-aif1" +#define CHT_CODEC_DAI2 "rt5645-aif2" struct cht_acpi_card { char *codec_id; @@ -51,13 +53,33 @@ struct cht_mc_private { struct clk *mclk; }; +#define CHT_RT5645_MAP(quirk) ((quirk) & 0xff) +#define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */ +#define CHT_RT5645_SSP0_AIF1 BIT(17) +#define CHT_RT5645_SSP0_AIF2 BIT(18) + +static unsigned long cht_rt5645_quirk = 0; + +static void log_quirks(struct device *dev) +{ + if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) + dev_info(dev, "quirk SSP2_AIF2 enabled"); + if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) + dev_info(dev, "quirk SSP0_AIF1 enabled"); + if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) + dev_info(dev, "quirk SSP0_AIF2 enabled"); +} + static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; list_for_each_entry(rtd, &card->rtd_list, list) { - if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, - strlen(CHT_CODEC_DAI))) + if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI1, + strlen(CHT_CODEC_DAI1))) + return rtd->codec_dai; + if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI2, + strlen(CHT_CODEC_DAI2))) return rtd->codec_dai; } return NULL; @@ -125,12 +147,6 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"Headphone", NULL, "HPOR"}, {"Ext Spk", NULL, "SPOL"}, {"Ext Spk", NULL, "SPOR"}, - {"AIF1 Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "codec_out0"}, - {"ssp2 Tx", NULL, "codec_out1"}, - {"codec_in0", NULL, "ssp2 Rx" }, - {"codec_in1", NULL, "ssp2 Rx" }, - {"ssp2 Rx", NULL, "AIF1 Capture"}, {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, @@ -146,16 +162,42 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = { {"Headphone", NULL, "HPOR"}, {"Ext Spk", NULL, "SPOL"}, {"Ext Spk", NULL, "SPOR"}, + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Int Mic", NULL, "Platform Clock"}, + {"Ext Spk", NULL, "Platform Clock"}, +}; + +static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif1_map[] = { {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "AIF1 Capture"}, - {"Headphone", NULL, "Platform Clock"}, - {"Headset Mic", NULL, "Platform Clock"}, - {"Int Mic", NULL, "Platform Clock"}, - {"Ext Spk", NULL, "Platform Clock"}, +}; + +static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = { + {"AIF2 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx" }, + {"codec_in1", NULL, "ssp2 Rx" }, + {"ssp2 Rx", NULL, "AIF2 Capture"}, +}; + +static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif1_map[] = { + {"AIF1 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx" }, + {"ssp0 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif2_map[] = { + {"AIF2 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx" }, + {"ssp0 Rx", NULL, "AIF2 Capture"}, }; static const struct snd_kcontrol_new cht_mc_controls[] = { @@ -201,11 +243,25 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream, return 0; } +/* uncomment when we have a real quirk +static int cht_rt5645_quirk_cb(const struct dmi_system_id *id) +{ + cht_rt5645_quirk = (unsigned long)id->driver_data; + return 1; +} +*/ + +static const struct dmi_system_id cht_rt5645_quirk_table[] = { + { + }, +}; + static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { int ret; int jack_type; struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_card *card = runtime->card; struct snd_soc_dai *codec_dai = runtime->codec_dai; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); @@ -217,6 +273,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) RT5645_AD_STEREO_FILTER, RT5645_CLK_SEL_I2S1_ASRC); + if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) { + ret = snd_soc_dapm_add_routes(&card->dapm, + cht_rt5645_ssp2_aif2_map, + ARRAY_SIZE(cht_rt5645_ssp2_aif2_map)); + } else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) { + ret = snd_soc_dapm_add_routes(&card->dapm, + cht_rt5645_ssp0_aif1_map, + ARRAY_SIZE(cht_rt5645_ssp0_aif1_map)); + } else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) { + ret = snd_soc_dapm_add_routes(&card->dapm, + cht_rt5645_ssp0_aif2_map, + ARRAY_SIZE(cht_rt5645_ssp0_aif2_map)); + } else { + ret = snd_soc_dapm_add_routes(&card->dapm, + cht_rt5645_ssp2_aif1_map, + ARRAY_SIZE(cht_rt5645_ssp2_aif1_map)); + } + if (ret) + return ret; + /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); if (ret < 0) { @@ -267,6 +343,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { + int ret; struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, @@ -276,8 +353,39 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) || + (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { + + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 16-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + } else { + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + } return 0; } @@ -384,7 +492,9 @@ static struct cht_acpi_card snd_soc_cards[] = { {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, }; -static char cht_rt5640_codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char cht_rt5645_codec_name[16]; /* i2c-:00 with HID being 8 chars */ +static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */ +static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ static bool is_valleyview(void) { @@ -398,6 +508,11 @@ static bool is_valleyview(void) return true; } +struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ + u64 aif_value; /* 1: AIF1, 2: AIF2 */ + u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ +}; + static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; @@ -408,6 +523,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *i2c_name = NULL; int dai_index = 0; bool found = false; + bool is_bytcr = false; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); if (!drv) @@ -445,9 +561,95 @@ static int snd_cht_mc_probe(struct platform_device *pdev) /* fixup codec name based on HID */ i2c_name = sst_acpi_find_name_from_hid(mach->id); if (i2c_name != NULL) { - snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name), + snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), "%s%s", "i2c-", i2c_name); - cht_dailink[dai_index].codec_name = cht_rt5640_codec_name; + cht_dailink[dai_index].codec_name = cht_rt5645_codec_name; + } + + /* + * swap SSP0 if bytcr is detected + * (will be overridden if DMI quirk is detected) + */ + if (is_valleyview()) { + struct sst_platform_info *p_info = mach->pdata; + const struct sst_res_info *res_info = p_info->res_info; + + if (res_info->acpi_ipc_irq_index == 0) + is_bytcr = true; + } + + if (is_bytcr) { + /* + * Baytrail CR platforms may have CHAN package in BIOS, try + * to find relevant routing quirk based as done on Windows + * platforms. We have to read the information directly from the + * BIOS, at this stage the card is not created and the links + * with the codec driver/pdata are non-existent + */ + + struct acpi_chan_package chan_package; + + /* format specified: 2 64-bit integers */ + struct acpi_buffer format = {sizeof("NN"), "NN"}; + struct acpi_buffer state = {0, NULL}; + struct sst_acpi_package_context pkg_ctx; + bool pkg_found = false; + + state.length = sizeof(chan_package); + state.pointer = &chan_package; + + pkg_ctx.name = "CHAN"; + pkg_ctx.length = 2; + pkg_ctx.format = &format; + pkg_ctx.state = &state; + pkg_ctx.data_valid = false; + + pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx); + if (pkg_found) { + if (chan_package.aif_value == 1) { + dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); + cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF1; + } else if (chan_package.aif_value == 2) { + dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); + cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2; + } else { + dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); + pkg_found = false; + } + } + + if (!pkg_found) { + /* no BIOS indications, assume SSP0-AIF2 connection */ + cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2; + } + } + + /* check quirks before creating card */ + dmi_check_system(cht_rt5645_quirk_table); + log_quirks(&pdev->dev); + + if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) || + (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { + + /* fixup codec aif name */ + snprintf(cht_rt5645_codec_aif_name, + sizeof(cht_rt5645_codec_aif_name), + "%s", "rt5645-aif2"); + + cht_dailink[dai_index].codec_dai_name = + cht_rt5645_codec_aif_name; + } + + if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) || + (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { + + /* fixup cpu dai name name */ + snprintf(cht_rt5645_cpu_dai_name, + sizeof(cht_rt5645_cpu_dai_name), + "%s", "ssp0-port"); + + cht_dailink[dai_index].cpu_dai_name = + cht_rt5645_cpu_dai_name; } if (is_valleyview()) { -- cgit From d74390b5fe47710e94b03b550d1b8b8f249cd416 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:44 -0600 Subject: ASoC: Intel: cht-bsw-rt5645: select ASRC source based on routing quirk Some platforms use AIF2, use routing information to set ASRC as needed Suggested-by: Bard Liao Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=95681 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 24b07601fb81..b175eee5d416 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -265,13 +265,24 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dai *codec_dai = runtime->codec_dai; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); - /* Select clk_i2s1_asrc as ASRC clock source */ - rt5645_sel_asrc_clk_src(codec, - RT5645_DA_STEREO_FILTER | - RT5645_DA_MONO_L_FILTER | - RT5645_DA_MONO_R_FILTER | - RT5645_AD_STEREO_FILTER, - RT5645_CLK_SEL_I2S1_ASRC); + if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) || + (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { + /* Select clk_i2s2_asrc as ASRC clock source */ + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S2_ASRC); + } else { + /* Select clk_i2s1_asrc as ASRC clock source */ + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + } if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) { ret = snd_soc_dapm_add_routes(&card->dapm, -- cgit From bf92c6efc68add6b934a2790f650a675a4c38286 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:40 -0600 Subject: ASoC: Intel: add support for ALC3270 codec Use ACPI ID 10EC3270 to load machine driver for cht-bsw-rt5645 and add reference to 3270 to use the rt5645 mode Tested on Asus T100HA Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 3 +++ sound/soc/intel/boards/cht_bsw_rt5645.c | 1 + 2 files changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 8cc30dfbf87d..747c0f393d2d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -499,6 +499,9 @@ static struct sst_acpi_mach sst_acpi_chv[] = { &chv_platform_data }, {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, + {"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, + &chv_platform_data }, + {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index b175eee5d416..a97eef6860ff 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -500,6 +500,7 @@ static struct cht_acpi_card snd_soc_cards[] = { {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5648", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, + {"10EC3270", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, }; -- cgit From 7bde09dfcf600e7a5c76a5325c6c3dfa60d08295 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Jan 2017 14:09:45 -0600 Subject: ASoC: Intel: cht-bsw-rt5645: fix DAI formats Remove default and set I2S mode correctly both on codec and cpu sides Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 39 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index a97eef6860ff..b972b6526176 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -304,13 +304,6 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; - /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); - if (ret < 0) { - dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); - return ret; - } - if (ctx->acpi_card->codec_type == CODEC_TYPE_RT5650) jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | SND_JACK_BTN_0 | SND_JACK_BTN_1 | @@ -377,7 +370,17 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, */ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_fmt(rtd->codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS ); if (ret < 0) { @@ -396,6 +399,24 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP2 to 24-bit */ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + /* + * Default mode for SSP configuration is TDM 4 slot + */ + ret = snd_soc_dai_set_fmt(rtd->codec_dai, + SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to TDM %d\n", ret); + return ret; + } + + /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0xF, 0xF, 4, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret); + return ret; + } } return 0; } @@ -458,8 +479,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .codec_dai_name = "rt5645-aif1", .codec_name = "i2c-10EC5645:00", - .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBS_CFS, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, .nonatomic = true, -- cgit From 77e546b7ba3e39e8a739cb18489582044222b7ba Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 1 Feb 2017 12:27:05 -0600 Subject: ASoC: cht-bsw-rt5645: fix unused variable compiler warning Missed unused variable in previous changes, oops. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index b972b6526176..5bcde01d15e6 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -262,7 +262,6 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) int jack_type; struct snd_soc_codec *codec = runtime->codec; struct snd_soc_card *card = runtime->card; - struct snd_soc_dai *codec_dai = runtime->codec_dai; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) || -- cgit From ab1eea19d0223481fab7345072825d00ce98c339 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:05 +0530 Subject: ASoC: hdac_hdmi: Move channel info from pin to PCM structure Channel info is part of the pcm parameter and channel map control is created for each pcm. So move channel info to pcm instead of pin structure and the mutex lock to pcm. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 76 ++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c0b49f4b7074..2a370d694f6d 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -85,10 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - struct mutex lock; - bool chmap_set; - unsigned char chmap[8]; /* ALSA API channel-map */ - int channels; /* current number of channels */ }; struct hdac_hdmi_pcm { @@ -100,6 +96,9 @@ struct hdac_hdmi_pcm { int stream_tag; int channels; int format; + bool chmap_set; + unsigned char chmap[8]; /* ALSA API channel-map */ + struct mutex lock; }; struct hdac_hdmi_dai_pin_map { @@ -217,13 +216,13 @@ struct dp_audio_infoframe { }; static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid) + struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_pin *pin) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; struct dp_audio_infoframe dp_ai; struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt = pcm->cvt; u8 *dip; int ret; int i; @@ -231,19 +230,14 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, u8 conn_type; int channels, ca; - list_for_each_entry(pin, &hdmi->pin_list, head) { - if (pin->nid == pin_nid) - break; - } - ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, - pin->channels, pin->chmap_set, true, pin->chmap); + pcm->channels, pcm->chmap_set, true, pcm->chmap); channels = snd_hdac_get_active_channels(ca); - hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); + hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels); snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, - pin->channels, pin->chmap, pin->chmap_set); + pcm->channels, pcm->chmap, pcm->chmap_set); eld_buf = pin->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf); @@ -279,26 +273,26 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, } /* stop infoframe transmission */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); /* Fill infoframe. Index auto-incremented */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { for (i = 0; i < sizeof(buffer); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); } else { for (i = 0; i < sizeof(dp_ai); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, dip[i]); } /* Start infoframe */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); return 0; @@ -476,18 +470,22 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_pcm *pcm; dai_map = &hdmi->dai_map[dai->id]; - if (dai_map->pin) { - mutex_lock(&dai_map->pin->lock); - dai_map->pin->chmap_set = false; - memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); - dai_map->pin->channels = 0; - mutex_unlock(&dai_map->pin->lock); + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); - dai_map->pin = NULL; + if (pcm) { + mutex_lock(&pcm->lock); + pcm->chmap_set = false; + memset(pcm->chmap, 0, sizeof(pcm->chmap)); + pcm->channels = 0; + mutex_unlock(&pcm->lock); } + + if (dai_map->pin) + dai_map->pin = NULL; } static int @@ -611,8 +609,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); - return hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, - pin->nid); + return hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); case SND_SOC_DAPM_POST_PMD: hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); @@ -1110,7 +1107,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) hdmi->num_pin++; pin->edev = edev; - mutex_init(&pin->lock); return 0; } @@ -1361,6 +1357,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + mutex_init(&pcm->lock); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { @@ -1506,13 +1503,8 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; - - /* chmap is already set to 0 in caller */ - if (!pin) - return; - memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); + memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap)); } static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, @@ -1523,12 +1515,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_pin *pin = pcm->pin; - mutex_lock(&pin->lock); - pin->chmap_set = true; - memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); + mutex_lock(&pcm->lock); + pcm->chmap_set = true; + memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); - mutex_unlock(&pin->lock); + hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + mutex_unlock(&pcm->lock); } static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) -- cgit From 51e0f3c825f0f800479aa6fd2066587b425d1010 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:06 +0530 Subject: ASoC: Intel: bxt: add channel map support in rt298 machine HDMI registers channel map controls per pcm. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback. Register for late probe and call the jack_init API which registers channel map in the late probe callback handler. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 52 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 1309405b3808..bc9ee0975073 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -26,8 +26,18 @@ #include "../../codecs/hdac_hdmi.h" #include "../../codecs/rt298.h" -static struct snd_soc_jack broxton_headset; /* Headset jack detection DAPM pins */ +static struct snd_soc_jack broxton_headset; + +struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_rt286_private { + struct list_head hdmi_pcm_list; +}; enum { BXT_DPCM_AUDIO_PB = 0, @@ -139,9 +149,20 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; - return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; } static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, @@ -432,6 +453,22 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { }, }; +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + + /* broxton audio machine driver for SPT + RT298S */ static struct snd_soc_card broxton_rt298 = { .name = "broxton-rt298", @@ -445,11 +482,22 @@ static struct snd_soc_card broxton_rt298 = { .dapm_routes = broxton_rt298_map, .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, + }; static int broxton_audio_probe(struct platform_device *pdev) { + struct bxt_rt286_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + broxton_rt298.dev = &pdev->dev; + snd_soc_card_set_drvdata(&broxton_rt298, ctx); return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298); } -- cgit From 111c2ae1fb46f66e1acd8b077377919954d6aa64 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:09 +0530 Subject: ASoC: Intel: Skylake: Add route change to rt286 machine To support MST moved pin to port, this changes the routes based on port. So change the route in skl_rt286 machine. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index dc5c3611a6ff..5e56af3a6ee3 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -94,9 +94,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"}, - {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, -- cgit From 6d707a74a79c7698bd3b797586c2f6ae55eae56c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:13 +0530 Subject: ASoC: Intel: bxt: Add route change to da7219_max98357a machine To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_da7219_max98357a machine. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 02439ace3519..876d82d4a39e 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -84,9 +84,9 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"codec0_in", NULL, "ssp1 Rx"}, {"ssp1 Rx", NULL, "Capture"}, - {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"}, {"hifi3", NULL, "iDisp3 Tx"}, {"iDisp3 Tx", NULL, "iDisp3_out"}, -- cgit From ba2103467794645e43d8115bef6f4fd18a40b47b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 24 Jan 2017 21:49:07 +0530 Subject: ASoC: Intel: bxt: add channel map support in bxt_da7219_max98357a machine HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback. Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 49 ++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 876d82d4a39e..a9647a27ebc2 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -34,6 +34,16 @@ static struct snd_soc_jack broxton_headset; +struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_card_private { + struct list_head hdmi_pcm_list; +}; + enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, @@ -147,9 +157,20 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; - return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; } static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) @@ -496,6 +517,21 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + /* broxton audio machine driver for SPT + da7219 */ static struct snd_soc_card broxton_audio_card = { .name = "bxtda7219max", @@ -509,11 +545,22 @@ static struct snd_soc_card broxton_audio_card = { .dapm_routes = broxton_map, .num_dapm_routes = ARRAY_SIZE(broxton_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, }; static int broxton_audio_probe(struct platform_device *pdev) { + struct bxt_card_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + broxton_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } -- cgit From 0cf5a17159edbebfe3ce2a0ce1dd36bd5809479a Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 11 Jan 2017 16:31:02 +0530 Subject: ASoC: Intel: Skylake: Report Platform ID info from NHLT This patch create entry in sysfs file system to report the platform_id = "pci-id-oem_id-oem_table_id-oem_revision" for board identification. Signed-off-by: Subhransu S. Prusty Signed-off-by: Sodhi, VunnyX Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 42 +++++++++++++++++++++++++++++++++++--- sound/soc/intel/skylake/skl.c | 5 +++++ sound/soc/intel/skylake/skl.h | 2 ++ 3 files changed, 46 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 3f8e6f0b7eb5..2710a3704a38 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -189,9 +189,9 @@ int skl_get_dmic_geo(struct skl *skl) return dmic_geo; } -static void skl_nhlt_trim_space(struct skl *skl) +static void skl_nhlt_trim_space(char *trim) { - char *s = skl->tplg_name; + char *s = trim; int cnt; int i; @@ -218,7 +218,43 @@ int skl_nhlt_update_topology_bin(struct skl *skl) skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, nhlt->header.oem_revision, "-tplg.bin"); - skl_nhlt_trim_space(skl); + skl_nhlt_trim_space(skl->tplg_name); return 0; } + +static ssize_t skl_nhlt_platform_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; + char platform_id[32]; + + sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, + nhlt->header.oem_id, nhlt->header.oem_table_id, + nhlt->header.oem_revision); + + skl_nhlt_trim_space(platform_id); + return sprintf(buf, "%s\n", platform_id); +} + +static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); + +int skl_nhlt_create_sysfs(struct skl *skl) +{ + struct device *dev = &skl->pci->dev; + + if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) + dev_warn(dev, "Error creating sysfs entry\n"); + + return 0; +} + +void skl_nhlt_remove_sysfs(struct skl *skl) +{ + struct device *dev = &skl->pci->dev; + + sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); +} diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index da5db5098274..1152e46daede 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -732,6 +732,10 @@ static int skl_probe(struct pci_dev *pci, goto out_display_power_off; } + err = skl_nhlt_create_sysfs(skl); + if (err < 0) + goto out_nhlt_free; + skl_nhlt_update_topology_bin(skl); pci_set_drvdata(skl->pci, ebus); @@ -852,6 +856,7 @@ static void skl_remove(struct pci_dev *pci) skl_free_dsp(skl); skl_machine_device_unregister(skl); skl_dmic_device_unregister(skl); + skl_nhlt_remove_sysfs(skl); skl_nhlt_free(skl->nhlt); skl_free(ebus); dev_set_drvdata(&pci->dev, NULL); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4986e3929dd3..0a1b02e21277 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -130,5 +130,7 @@ int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); void skl_update_d0i3c(struct device *dev, bool enable); +int skl_nhlt_create_sysfs(struct skl *skl); +void skl_nhlt_remove_sysfs(struct skl *skl); #endif /* __SOUND_SOC_SKL_H */ -- cgit From 754695f9960b58a9c9d6b9ab7fae68f7c4b47d9c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 6 Feb 2017 12:09:14 +0530 Subject: ASoC: hdac_hdmi: Begin to add support for DP Multi-stream audio With MST each pin contains several ports to which device can be connected. As a preparatory work to support DP MST this patch adds below changes: 1. Defines the port structure and moves all stream related information like ELD, converter list, chmap to port. 2. Creates ports for each pin based on the max_ports support. 3. Based on Pin-Port combination creates DAPM Mux widget instead of Pin to allow user to select a converter. 4. Port zero is the default port when pin does not support MST. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 393 ++++++++++++++++++++++++++----------------- 1 file changed, 240 insertions(+), 153 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 2a370d694f6d..d3858b53d273 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -42,6 +42,7 @@ #define HDA_MAX_CONNECTIONS 32 #define HDA_MAX_CVTS 3 +#define HDA_MAX_PORTS 3 #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20 @@ -81,16 +82,23 @@ struct hdac_hdmi_eld { struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; + struct hdac_hdmi_port *ports; + int num_ports; + struct hdac_ext_device *edev; +}; + +struct hdac_hdmi_port { + int id; + struct hdac_hdmi_pin *pin; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; - struct hdac_ext_device *edev; }; struct hdac_hdmi_pcm { struct list_head head; int pcm_id; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; int stream_tag; @@ -101,19 +109,20 @@ struct hdac_hdmi_pcm { struct mutex lock; }; -struct hdac_hdmi_dai_pin_map { +struct hdac_hdmi_dai_port_map { int dai_id; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; }; struct hdac_hdmi_priv { - struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; + struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS]; struct list_head pin_list; struct list_head cvt_list; struct list_head pcm_list; int num_pin; int num_cvt; + int num_ports; struct mutex pin_mutex; struct hdac_chmap chmap; }; @@ -216,10 +225,11 @@ struct dp_audio_infoframe { }; static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, - struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_pin *pin) + struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; + struct hdac_hdmi_pin *pin = port->pin; struct dp_audio_infoframe dp_ai; struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_cvt *cvt = pcm->cvt; @@ -230,7 +240,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, u8 conn_type; int channels, ca; - ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, + ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc, pcm->channels, pcm->chmap_set, true, pcm->chmap); channels = snd_hdac_get_active_channels(ca); @@ -239,7 +249,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, pcm->channels, pcm->chmap, pcm->chmap_set); - eld_buf = pin->eld.eld_buffer; + eld_buf = port->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf); switch (conn_type) { @@ -304,7 +314,7 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask); @@ -324,20 +334,21 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_dai_port_map *dai_map; + struct hdac_hdmi_port *port; struct hdac_hdmi_pcm *pcm; int format; dai_map = &hdmi->dai_map[dai->id]; - pin = dai_map->pin; + port = dai_map->port; - if (!pin) + if (!port) return -ENODEV; - if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { - dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", - pin->nid); + if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { + dev_err(&hdac->hdac.dev, + "device is not configured for this pin:port%d:%d\n", + port->pin->nid, port->id); return -ENODEV; } @@ -355,8 +366,9 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return 0; } -static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, + struct hdac_hdmi_pin *pin, + struct hdac_hdmi_port *port) { if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { dev_warn(&hdac->hdac.dev, @@ -365,51 +377,52 @@ static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, return -EINVAL; } - pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, - pin->mux_nids, HDA_MAX_CONNECTIONS); - if (pin->num_mux_nids == 0) - dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", - pin->nid); + port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + port->mux_nids, HDA_MAX_CONNECTIONS); + if (port->num_mux_nids == 0) + dev_warn(&hdac->hdac.dev, + "No connections found for pin:port %d:%d\n", + pin->nid, port->id); - dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", - pin->num_mux_nids, pin->nid); + dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n", + port->num_mux_nids, pin->nid, port->id); - return pin->num_mux_nids; + return port->num_mux_nids; } /* - * Query pcm list and return pin widget to which stream is routed. + * Query pcm list and return port to which stream is routed. * - * Also query connection list of the pin, to validate the cvt to pin map. + * Also query connection list of the pin, to validate the cvt to port map. * - * Same stream rendering to multiple pins simultaneously can be done - * possibly, but not supported for now in driver. So return the first pin + * Same stream rendering to multiple ports simultaneously can be done + * possibly, but not supported for now in driver. So return the first port * connected. */ -static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( +static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( struct hdac_ext_device *edev, struct hdac_hdmi_priv *hdmi, struct hdac_hdmi_cvt *cvt) { struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_port *port = NULL; int ret, i; list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - pin = pcm->pin; + port = pcm->port; break; } } - if (pin) { - ret = hdac_hdmi_query_pin_connlist(edev, pin); + if (port) { + ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); if (ret < 0) return NULL; - for (i = 0; i < pin->num_mux_nids; i++) { - if (pin->mux_nids[i] == cvt->nid) - return pin; + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid) + return port; } } @@ -426,42 +439,43 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; int ret; dai_map = &hdmi->dai_map[dai->id]; cvt = dai_map->cvt; - pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); + port = hdac_hdmi_get_port_from_cvt(hdac, hdmi, cvt); /* * To make PA and other userland happy. * userland scans devices so returning error does not help. */ - if (!pin) + if (!port) return 0; - if ((!pin->eld.monitor_present) || - (!pin->eld.eld_valid)) { + if ((!port->eld.monitor_present) || + (!port->eld.eld_valid)) { dev_warn(&hdac->hdac.dev, - "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", - pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); + "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n", + port->eld.monitor_present, port->eld.eld_valid, + port->pin->nid, port->id); return 0; } - dai_map->pin = pin; + dai_map->port = port; ret = hdac_hdmi_eld_limit_formats(substream->runtime, - pin->eld.eld_buffer); + port->eld.eld_buffer); if (ret < 0) return ret; return snd_pcm_hw_constraint_eld(substream->runtime, - pin->eld.eld_buffer); + port->eld.eld_buffer); } static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, @@ -469,7 +483,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm; dai_map = &hdmi->dai_map[dai->id]; @@ -484,8 +498,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, mutex_unlock(&pcm->lock); } - if (dai_map->pin) - dai_map->pin = NULL; + if (dai_map->port) + dai_map->port = NULL; } static int @@ -553,13 +567,16 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, } static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin) + struct hdac_hdmi_port *port) { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (pcm->pin == pin) + if (!pcm->port) + continue; + + if (pcm->port == port) return pcm; } @@ -588,37 +605,37 @@ static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kc, int event) { - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); struct hdac_hdmi_pcm *pcm; dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", __func__, w->name, event); - pcm = hdac_hdmi_get_pcm(edev, pin); + pcm = hdac_hdmi_get_pcm(edev, port); if (!pcm) return -EIO; switch (event) { case SND_SOC_DAPM_PRE_PMU: - hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D0); + hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0); /* Enable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); + hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE); - return hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + return hdac_hdmi_setup_audio_infoframe(edev, pcm, port); case SND_SOC_DAPM_POST_PMD: - hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); + hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE); /* Disable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D3); + hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3); break; } @@ -676,7 +693,7 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kc, int event) { - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); int mux_idx; @@ -688,7 +705,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, mux_idx = dapm_kcontrol_get_value(kc); if (mux_idx > 0) { - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); } @@ -698,14 +715,14 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, /* * Based on user selection, map the PINs with the PCMs. */ -static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, +static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; @@ -715,18 +732,22 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, if (ret < 0) return ret; + if (port == NULL) + return -EINVAL; + mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (pcm->pin == pin) - pcm->pin = NULL; + if (!pcm->port && pcm->port == port && + pcm->port->id == port->id) + pcm->port = NULL; /* * Jack status is not reported during device probe as the * PCMs are not registered by then. So report it here. */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { - pcm->pin = pin; - if (pin->eld.monitor_present && pin->eld.eld_valid) { + if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { + pcm->port = port; + if (port->eld.monitor_present && port->eld.eld_valid) { dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", pcm->pcm_id); @@ -751,12 +772,13 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, * care of selecting the right one and leaving all other inputs selected to * "NONE" */ -static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin, +static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, + struct hdac_hdmi_port *port, struct snd_soc_dapm_widget *widget, const char *widget_name) { struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin = port->pin; struct snd_kcontrol_new *kc; struct hdac_hdmi_cvt *cvt; struct soc_enum *se; @@ -775,7 +797,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, if (!se) return -ENOMEM; - sprintf(kc_name, "Pin %d Input", pin->nid); + sprintf(kc_name, "Pin %d port %d Input", pin->nid, port->id); kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); if (!kc->name) return -ENOMEM; @@ -784,7 +806,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = 0; kc->info = snd_soc_info_enum_double; - kc->put = hdac_hdmi_set_pin_mux; + kc->put = hdac_hdmi_set_pin_port_mux; kc->get = snd_soc_dapm_get_enum_double; se->reg = SND_SOC_NOPM; @@ -812,7 +834,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, return -ENOMEM; return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, - snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1, + snd_soc_dapm_mux, port, widget_name, NULL, kc, 1, hdac_hdmi_pin_mux_widget_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); } @@ -825,10 +847,10 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, struct hdac_hdmi_priv *hdmi = edev->private_data; const struct snd_kcontrol_new *kc; struct soc_enum *se; - int mux_index = hdmi->num_cvt + hdmi->num_pin; + int mux_index = hdmi->num_cvt + hdmi->num_ports; int i, j; - for (i = 0; i < hdmi->num_pin; i++) { + for (i = 0; i < hdmi->num_ports; i++) { kc = widgets[mux_index].kcontrol_news; se = (struct soc_enum *)kc->private_value; for (j = 0; j < hdmi->num_cvt; j++) { @@ -847,17 +869,18 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, /* * Widgets are added in the below sequence * Converter widgets for num converters enumerated - * Pin widgets for num pins enumerated - * Pin mux widgets to represent connenction list of pin widget + * Pin-port widgets for num ports for Pins enumerated + * Pin-port mux widgets to represent connenction list of pin widget * - * Total widgets elements = num_cvt + num_pin + num_pin; + * For each port, one Mux and One output widget is added + * Total widgets elements = num_cvt + (num_ports * 2); * * Routes are added as below: - * pin mux -> pin (based on num_pins) - * cvt -> "Input sel control" -> pin_mux + * pin-port mux -> pin (based on num_ports) + * cvt -> "Input sel control" -> pin-port_mux * * Total route elements: - * num_pins + (pin_muxes * num_cvt) + * num_ports + (pin_muxes * num_cvt) */ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) { @@ -869,14 +892,14 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) char widget_name[NAME_SIZE]; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_pin *pin; - int ret, i = 0, num_routes = 0; + int ret, i = 0, num_routes = 0, j; if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) return -EINVAL; - widgets = devm_kzalloc(dapm->dev, - (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), - GFP_KERNEL); + widgets = devm_kzalloc(dapm->dev, (sizeof(*widgets) * + ((2 * hdmi->num_ports) + hdmi->num_cvt)), + GFP_KERNEL); if (!widgets) return -ENOMEM; @@ -895,31 +918,39 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) } list_for_each_entry(pin, &hdmi->pin_list, head) { - sprintf(widget_name, "hif%d Output", pin->nid); - ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_output, pin, - widget_name, NULL, NULL, 0, - hdac_hdmi_pin_output_widget_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); - if (ret < 0) - return ret; - i++; + for (j = 0; j < pin->num_ports; j++) { + sprintf(widget_name, "hif%d-%d Output", + pin->nid, pin->ports[j].id); + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_output, &pin->ports[j], + widget_name, NULL, NULL, 0, + hdac_hdmi_pin_output_widget_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD); + if (ret < 0) + return ret; + i++; + } } /* DAPM widgets to represent the connection list to pin widget */ list_for_each_entry(pin, &hdmi->pin_list, head) { - sprintf(widget_name, "Pin %d Mux", pin->nid); - ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], - widget_name); - if (ret < 0) - return ret; - i++; + for (j = 0; j < pin->num_ports; j++) { + sprintf(widget_name, "Pin%d-Port%d Mux", + pin->nid, pin->ports[j].id); + ret = hdac_hdmi_create_pin_port_muxs(edev, + &pin->ports[j], &widgets[i], + widget_name); + if (ret < 0) + return ret; + i++; - /* For cvt to pin_mux mapping */ - num_routes += hdmi->num_cvt; + /* For cvt to pin_mux mapping */ + num_routes += hdmi->num_cvt; - /* For pin_mux to pin mapping */ - num_routes++; + /* For pin_mux to pin mapping */ + num_routes++; + } } route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), @@ -930,20 +961,22 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) i = 0; /* Add pin <- NULL <- mux route map */ list_for_each_entry(pin, &hdmi->pin_list, head) { - int sink_index = i + hdmi->num_cvt; - int src_index = sink_index + hdmi->num_pin; + for (j = 0; j < pin->num_ports; j++) { + int sink_index = i + hdmi->num_cvt; + int src_index = sink_index + pin->num_ports * + hdmi->num_pin; - hdac_hdmi_fill_route(&route[i], + hdac_hdmi_fill_route(&route[i], widgets[sink_index].name, NULL, widgets[src_index].name, NULL); - i++; - + i++; + } } hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i); snd_soc_dapm_new_controls(dapm, widgets, - ((2 * hdmi->num_pin) + hdmi->num_cvt)); + ((2 * hdmi->num_ports) + hdmi->num_cvt)); snd_soc_dapm_add_routes(dapm, route, num_routes); snd_soc_dapm_new_widgets(dapm->card); @@ -955,7 +988,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; int dai_id = 0; @@ -999,12 +1032,12 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); } -static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, + struct hdac_hdmi_port *port) { unsigned int ver, mnl; - ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + ver = (port->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT; if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { @@ -1012,7 +1045,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, return -EINVAL; } - mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + mnl = (port->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; if (mnl > ELD_MAX_MNL) { @@ -1020,45 +1053,50 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, return -EINVAL; } - pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + port->eld.info.spk_alloc = port->eld.eld_buffer[DRM_ELD_SPEAKER]; return 0; } -static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, + struct hdac_hdmi_port *port) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int size; + int size = 0; + + if (!hdmi) + return; mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = false; + port->eld.monitor_present = false; size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, - &pin->eld.monitor_present, pin->eld.eld_buffer, + &port->eld.monitor_present, + port->eld.eld_buffer, ELD_MAX_SIZE); if (size > 0) { size = min(size, ELD_MAX_SIZE); - if (hdac_hdmi_parse_eld(edev, pin) < 0) + if (hdac_hdmi_parse_eld(edev, port) < 0) size = -EINVAL; } if (size > 0) { - pin->eld.eld_valid = true; - pin->eld.eld_size = size; + port->eld.eld_valid = true; + port->eld.eld_size = size; } else { - pin->eld.eld_valid = false; - pin->eld.eld_size = 0; + port->eld.eld_valid = false; + port->eld.eld_size = 0; } - pcm = hdac_hdmi_get_pcm(edev, pin); + pcm = hdac_hdmi_get_pcm(edev, port); - if (!pin->eld.monitor_present || !pin->eld.eld_valid) { + if (!port->eld.monitor_present || !port->eld.eld_valid) { - dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", - __func__, pin->nid); + dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + __func__, pin->nid, port->id); /* * PCMs are not registered during device probe, so don't @@ -1076,7 +1114,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) return; } - if (pin->eld.monitor_present && pin->eld.eld_valid) { + if (port->eld.monitor_present && port->eld.eld_valid) { if (pcm) { dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", @@ -1086,27 +1124,57 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) } print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, false); - } + port->eld.eld_buffer, port->eld.eld_size, false); + } mutex_unlock(&hdmi->pin_mutex); } +static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_pin *pin) +{ + struct hdac_hdmi_port *ports; + int max_ports = HDA_MAX_PORTS; + int i; + + /* + * FIXME: max_port may vary for each platform, so pass this as + * as driver data or query from i915 interface when this API is + * implemented. + */ + + ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL); + if (!ports) + return -ENOMEM; + + for (i = 0; i < max_ports; i++) { + ports[i].id = i; + ports[i].pin = pin; + } + pin->ports = ports; + pin->num_ports = max_ports; + return 0; +} + 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; + int ret; pin = kzalloc(sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM; pin->nid = nid; + pin->edev = edev; + ret = hdac_hdmi_add_ports(hdmi, pin); + if (ret < 0) + return ret; list_add_tail(&pin->head, &hdmi->pin_list); hdmi->num_pin++; - - pin->edev = edev; + hdmi->num_ports += pin->num_ports; return 0; } @@ -1292,13 +1360,15 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) { struct hdac_ext_device *edev = aptr; struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_port *hport = NULL; struct snd_soc_codec *codec = edev->scodec; /* Don't know how this mapping is derived */ hda_nid_t pin_nid = port + 0x04; - dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); + dev_dbg(&edev->hdac.dev, "%s: for pin:%d port=%d\n", __func__, + pin_nid, pipe); /* * skip notification during system suspend (but not in runtime PM); @@ -1314,9 +1384,19 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) return; list_for_each_entry(pin, &hdmi->pin_list, head) { - if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin); + if (pin->nid != pin_nid) + continue; + + /* In case of non MST pin, pipe is -1 */ + if (pipe == -1) { + /* if not MST, default is port[0] */ + hport = &pin->ports[0]; + break; + } } + + if (hport) + hdac_hdmi_present_sense(pin, hport); } static struct i915_audio_component_audio_ops aops = { @@ -1388,7 +1468,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; - int ret; + int ret, i; edev->scodec = codec; @@ -1417,7 +1497,8 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) } list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin); + for (i = 0; i < pin->num_ports; i++) + hdac_hdmi_present_sense(pin, &pin->ports[i]); /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1468,6 +1549,7 @@ static void hdmi_codec_complete(struct device *dev) struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pin *pin; struct hdac_device *hdac = &edev->hdac; + int i; /* Power up afg */ snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, @@ -1482,7 +1564,8 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin); + for (i = 0; i < pin->num_ports; i++) + hdac_hdmi_present_sense(pin, &pin->ports[i]); pm_runtime_put_sync(&edev->hdac.dev); } @@ -1513,13 +1596,13 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; + struct hdac_hdmi_port *port = pcm->port; mutex_lock(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + hdac_hdmi_setup_audio_infoframe(edev, pcm, port); mutex_unlock(&pcm->lock); } @@ -1528,9 +1611,9 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; + struct hdac_hdmi_port *port = pcm->port; - return pin ? true:false; + return port ? true:false; } static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -1538,12 +1621,12 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; + struct hdac_hdmi_port *port = pcm->port; - if (!pin || !pin->eld.eld_valid) + if (!port || !port->eld.eld_valid) return 0; - return pin->eld.info.spk_alloc; + return port->eld.info.spk_alloc; } static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) @@ -1616,12 +1699,13 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + int i; snd_soc_unregister_codec(&edev->hdac.dev); list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->pin = NULL; + pcm->port = NULL; list_del(&pcm->head); kfree(pcm); } @@ -1633,6 +1717,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) } list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { + for (i = 0; i < pin->num_ports; i++) + pin->ports[i].pin = NULL; + kfree(pin->ports); list_del(&pin->head); kfree(pin); } -- cgit From eaba31035aa925b04d7d63120283e40a0e96e4a8 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 6 Feb 2017 12:09:17 +0530 Subject: ASoC: Intel: bxt: Add route change to rt298 machine To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_rt298 machine. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index bc9ee0975073..09be868833d1 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -92,9 +92,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"}, - {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"}, /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp5 Tx"}, -- cgit From b0aad231bd1edd297a3e60acf26f9dceff1937a7 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 6 Feb 2017 12:09:15 +0530 Subject: ASoC: Intel: Skylake: Add route change to nau88l25_max98357a machine To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_max98357a machine. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index fddd1cd12f13..bb4196867752 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -111,8 +111,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -130,8 +130,8 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" }, - {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"}, /* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" }, -- cgit From 8d13640f6b9f1f99035d7078b3cd4002e9af5d9c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 6 Feb 2017 12:09:16 +0530 Subject: ASoC: Intel: Skylake: Add route change to nau88l25_ssm4567 machine To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_ssm4567 machine. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 8ab865ee0cad..41117bc51450 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -115,8 +115,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -135,8 +135,9 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"}, - {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"}, + /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, -- cgit From 2acd8309a3a4e6dc04e72d2db0716825095c02d6 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 6 Feb 2017 12:09:18 +0530 Subject: ASoC: hdac_hdmi: Add support to handle MST capable pin To handle jack event and configuration of the pin widget for MST capable pin, this patch adds: o Flag to identify the pin is MST capable. o In notify callback(), based on the pipe and port information marks if the port is mst_capable. In case of non MST, port is defaulted to zero. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index d3858b53d273..17a1ad3ead21 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -82,6 +82,7 @@ struct hdac_hdmi_eld { struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; + bool mst_capable; struct hdac_hdmi_port *ports; int num_ports; struct hdac_ext_device *edev; @@ -1065,14 +1066,22 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; int size = 0; + int port_id = -1; if (!hdmi) return; + /* + * In case of non MST pin, get_eld info API expectes port + * to be -1. + */ mutex_lock(&hdmi->pin_mutex); port->eld.monitor_present = false; - size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + if (pin->mst_capable) + port_id = port->id; + + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, port_id, &port->eld.monitor_present, port->eld.eld_buffer, ELD_MAX_SIZE); @@ -1167,6 +1176,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) return -ENOMEM; pin->nid = nid; + pin->mst_capable = false; pin->edev = edev; ret = hdac_hdmi_add_ports(hdmi, pin); if (ret < 0) @@ -1363,6 +1373,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) struct hdac_hdmi_pin *pin = NULL; struct hdac_hdmi_port *hport = NULL; struct snd_soc_codec *codec = edev->scodec; + int i; /* Don't know how this mapping is derived */ hda_nid_t pin_nid = port + 0x04; @@ -1389,13 +1400,23 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) /* In case of non MST pin, pipe is -1 */ if (pipe == -1) { + pin->mst_capable = false; /* if not MST, default is port[0] */ hport = &pin->ports[0]; - break; + goto out; + } else { + for (i = 0; i < pin->num_ports; i++) { + pin->mst_capable = true; + if (pin->ports[i].id == pipe) { + hport = &pin->ports[i]; + goto out; + } + } } } - if (hport) +out: + if (pin && hport) hdac_hdmi_present_sense(pin, hport); } -- cgit From fc181b04f2d44805624d4bc5a0615bc084199a81 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:45 +0530 Subject: ASoC: hdac_hdmi: Add MST verb support To support DP MST audio, new pin verbs/params are added. This patch adds helper functions to do following: o To set a specific port o To get the currently selected port o To get the length of port. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 17a1ad3ead21..84b7d6cd7c37 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -142,6 +142,76 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, return pcm; } +/* MST supported verbs */ +/* + * Get the no devices that can be connected to a port on the Pin widget. + */ +static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid) +{ + unsigned int caps; + unsigned int type, param; + + caps = get_wcaps(&hdac->hdac, nid); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) + return 0; + + param = snd_hdac_read_parm_uncached(&hdac->hdac, nid, + AC_PAR_DEVLIST_LEN); + if (param == -1) + return param; + + return param & AC_DEV_LIST_LEN_MASK; +} + +/* + * Get the port entry select on the pin. Return the port entry + * id selected on the pin. Return 0 means the first port entry + * is selected or MST is not supported. + */ +static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + return snd_hdac_codec_read(&hdac->hdac, port->pin->nid, + 0, AC_VERB_GET_DEVICE_SEL, 0); +} + +/* + * Sets the selected port entry for the configuring Pin widget verb. + * returns error if port set is not equal to port get otherwise success + */ +static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + int num_ports; + + if (!port->pin->mst_capable) + return 0; + + /* AC_PAR_DEVLIST_LEN is 0 based. */ + num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid); + + if (num_ports < 0) + return -EIO; + /* + * Device List Length is a 0 based integer value indicating the + * number of sink device that a MST Pin Widget can support. + */ + if (num_ports + 1 < port->id) + return 0; + + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, + AC_VERB_SET_DEVICE_SEL, port->id); + + if (port->id != hdac_hdmi_port_select_get(hdac, port)) + return -EIO; + + dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id); + + return 0; +} + static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) { -- cgit From a9ce96bcd9c4d0c1ffd3d37c000bcee470b2535b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:46 +0530 Subject: ASoC: hdac_hdmi: Handle MST pin jack detection at boot/resume The ELD notification can be received asynchronously from the graphics side and this may happen just at the moment the sound driver is initializing and notification will be missed. Similarly at system resume, the notification is ignored as the ELD and connection states are updated in anyway at the end of the resume. So check the jack status in boot/resume by querying the port presence based on pin caps and report the jack status. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 84b7d6cd7c37..c5527e81a490 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1551,15 +1551,38 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) } EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); +static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev, + struct hdac_hdmi_priv *hdmi, bool detect_pin_caps) +{ + int i; + struct hdac_hdmi_pin *pin; + + list_for_each_entry(pin, &hdmi->pin_list, head) { + if (detect_pin_caps) { + + if (hdac_hdmi_get_port_len(edev, pin->nid) == 0) + pin->mst_capable = false; + else + pin->mst_capable = true; + } + + for (i = 0; i < pin->num_ports; i++) { + if (!pin->mst_capable && i > 0) + continue; + + hdac_hdmi_present_sense(pin, &pin->ports[i]); + } + } +} + static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); struct hdac_hdmi_priv *hdmi = edev->private_data; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); - struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; - int ret, i; + int ret; edev->scodec = codec; @@ -1587,10 +1610,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) return ret; } - list_for_each_entry(pin, &hdmi->pin_list, head) - for (i = 0; i < pin->num_ports; i++) - hdac_hdmi_present_sense(pin, &pin->ports[i]); - + hdac_hdmi_present_sense_all_pins(edev, hdmi, true); /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1638,9 +1658,7 @@ static void hdmi_codec_complete(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_pin *pin; struct hdac_device *hdac = &edev->hdac; - int i; /* Power up afg */ snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, @@ -1652,11 +1670,10 @@ static void hdmi_codec_complete(struct device *dev) /* * As the ELD notify callback request is not entertained while the * device is in suspend state. Need to manually check detection of - * all pins here. + * all pins here. pin capablity change is not support, so use the + * already set pin caps. */ - list_for_each_entry(pin, &hdmi->pin_list, head) - for (i = 0; i < pin->num_ports; i++) - hdac_hdmi_present_sense(pin, &pin->ports[i]); + hdac_hdmi_present_sense_all_pins(edev, hdmi, false); pm_runtime_put_sync(&edev->hdac.dev); } -- cgit From 1b46ebd136b3ad334762d6e66b0b96b432680e50 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:47 +0530 Subject: ASoc: hdac_hdmi: Configure pin verbs for MST To enable stream on a specific port of a MST capable pin, the port needs to be selected before we configure the pin widget verb. When port is selected, all the pin widget verb controlling the sink device operation will be directed to selected port. So add port selection before configuring the pin widget verb. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c5527e81a490..6cf86a0a118c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -448,6 +448,9 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, return -EINVAL; } + if (hdac_hdmi_port_select_set(hdac, port) < 0) + return -EIO; + port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, port->mux_nids, HDA_MAX_CONNECTIONS); if (port->num_mux_nids == 0) @@ -687,6 +690,10 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, if (!pcm) return -EIO; + /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(edev, port) < 0) + return -EIO; + switch (event) { case SND_SOC_DAPM_PRE_PMU: hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0); @@ -775,6 +782,11 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, kc = w->kcontrols[0]; mux_idx = dapm_kcontrol_get_value(kc); + + /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(edev, port) < 0) + return -EIO; + if (mux_idx > 0) { snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); -- cgit From e0e5d3e5a53b3bc354c18030b78b7ebcb33e004b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:48 +0530 Subject: 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 Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 168 +++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 55 deletions(-) (limited to 'sound') 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 { }; struct hdac_hdmi_port { + struct list_head head; int id; struct hdac_hdmi_pin *pin; int num_mux_nids; @@ -99,7 +100,7 @@ struct hdac_hdmi_port { struct hdac_hdmi_pcm { struct list_head head; int pcm_id; - struct hdac_hdmi_port *port; + struct list_head port_list; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; int stream_tag; @@ -108,6 +109,7 @@ struct hdac_hdmi_pcm { bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ struct mutex lock; + int jack_event; }; struct hdac_hdmi_dai_port_map { @@ -142,6 +144,37 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, return pcm; } +static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, + struct hdac_hdmi_port *port, bool is_connect) +{ + struct hdac_ext_device *edev = port->pin->edev; + + if (is_connect) { + /* + * Report Jack connect event when a device is connected + * for the first time where same PCM is attached to multiple + * ports. + */ + if (pcm->jack_event == 0) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + snd_jack_report(pcm->jack, SND_JACK_AVOUT); + } + pcm->jack_event++; + } else { + /* + * Report Jack disconnect event when a device is disconnected + * is the only last connected device when same PCM is attached + * to multiple ports. + */ + if (pcm->jack_event == 1) + snd_jack_report(pcm->jack, 0); + if (pcm->jack_event > 0) + pcm->jack_event--; + } +} + /* MST supported verbs */ /* * 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( list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - port = pcm->port; - break; - } - } - - if (port) { - ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); - if (ret < 0) - return NULL; + if (list_empty(&pcm->port_list)) + continue; - for (i = 0; i < port->num_mux_nids; i++) { - if (port->mux_nids[i] == cvt->nid) - return port; + list_for_each_entry(port, &pcm->port_list, head) { + mutex_lock(&pcm->lock); + ret = hdac_hdmi_query_port_connlist(edev, + port->pin, port); + mutex_unlock(&pcm->lock); + if (ret < 0) + continue; + + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid && + port->eld.monitor_present && + port->eld.eld_valid) + return port; + } + } } } @@ -529,7 +567,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, */ if (!port) return 0; - if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { @@ -645,13 +682,16 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_port *p; list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port) + if (list_empty(&pcm->port_list)) continue; - if (pcm->port == port) - return pcm; + list_for_each_entry(p, &pcm->port_list, head) { + if (p->id == port->id && port->pin == p->pin) + return pcm; + } } return NULL; @@ -802,6 +842,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; + struct hdac_hdmi_port *p, *p_next; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; @@ -820,25 +861,30 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port && pcm->port == port && - pcm->port->id == port->id) - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue; - /* - * Jack status is not reported during device probe as the - * PCMs are not registered by then. So report it here. - */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { - pcm->port = port; - if (port->eld.monitor_present && port->eld.eld_valid) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + list_for_each_entry_safe(p, p_next, &pcm->port_list, head) { + if (p == port && p->id == port->id && + p->pin == port->pin) { + hdac_hdmi_jack_report(pcm, port, false); + list_del(&p->head); + } + } + } - snd_jack_report(pcm->jack, SND_JACK_AVOUT); + /* + * Jack status is not reported during device probe as the + * PCMs are not registered by then. So report it here. + */ + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (!strcmp(cvt_name, pcm->cvt->name)) { + list_add_tail(&port->head, &pcm->port_list); + if (port->eld.monitor_present && port->eld.eld_valid) { + hdac_hdmi_jack_report(pcm, port, true); + mutex_unlock(&hdmi->pin_mutex); + return ret; } - mutex_unlock(&hdmi->pin_mutex); - return ret; } } mutex_unlock(&hdmi->pin_mutex); @@ -1186,7 +1232,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, if (!port->eld.monitor_present || !port->eld.eld_valid) { - dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", __func__, pin->nid, port->id); /* @@ -1194,25 +1240,16 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * report jack here. It will be done in usermode mux * control select. */ - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", pcm->pcm_id); - - snd_jack_report(pcm->jack, 0); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, false); mutex_unlock(&hdmi->pin_mutex); return; } if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, true); print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, 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) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + pcm->jack_event = 0; mutex_init(&pcm->lock); - + INIT_LIST_HEAD(&pcm->port_list); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { 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, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return; mutex_lock(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); - if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm, port); + list_for_each_entry(port, &pcm->port_list, head) + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm, port); mutex_unlock(&pcm->lock); } @@ -1731,9 +1773,11 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; - return port ? true:false; + if (list_empty(&pcm->port_list)) + return false; + + return true; } static 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) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return 0; + + port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); + + if (!port) + return 0; if (!port || !port->eld.eld_valid) return 0; @@ -1819,13 +1871,19 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + struct hdac_hdmi_port *port; int i; snd_soc_unregister_codec(&edev->hdac.dev); list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue; + + list_for_each_entry(port, &pcm->port_list, head) + port = NULL; + list_del(&pcm->head); kfree(pcm); } -- cgit From 624900163d060f15d71ff383104a909737de770c Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:49 +0530 Subject: ASoC: hdac_hdmi: Use ASoC jack instead of snd_jack Use snd_soc_jack instead of snd_jack and create the jack in machine driver and pass the jack pointer to hdac_hdmi driver for jack reporting. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 19 ++++++++----------- sound/soc/codecs/hdac_hdmi.h | 3 ++- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f8b6e9f1c6f6..0f2c1e823281 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -102,7 +102,7 @@ struct hdac_hdmi_pcm { int pcm_id; struct list_head port_list; struct hdac_hdmi_cvt *cvt; - struct snd_jack *jack; + struct snd_soc_jack *jack; int stream_tag; int channels; int format; @@ -159,7 +159,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", pcm->pcm_id); - snd_jack_report(pcm->jack, SND_JACK_AVOUT); + snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT, + SND_JACK_AVOUT); } pcm->jack_event++; } else { @@ -169,7 +170,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, * to multiple ports. */ if (pcm->jack_event == 1) - snd_jack_report(pcm->jack, 0); + snd_soc_jack_report(pcm->jack, 0, SND_JACK_AVOUT); if (pcm->jack_event > 0) pcm->jack_event--; } @@ -1556,13 +1557,11 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, return NULL; } -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) { - char jack_name[NAME_SIZE]; struct snd_soc_codec *codec = dai->codec; struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; struct snd_pcm *snd_pcm; @@ -1578,6 +1577,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; pcm->jack_event = 0; + pcm->jack = jack; mutex_init(&pcm->lock); INIT_LIST_HEAD(&pcm->port_list); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); @@ -1594,10 +1594,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) list_add_tail(&pcm->head, &hdmi->pcm_list); - sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); - - return snd_jack_new(dapm->card->snd_card, jack_name, - SND_JACK_AVOUT, &pcm->jack, true, false); + return 0; } EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index 8dfd1e0b57b3..bf7edb3227d2 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h @@ -1,6 +1,7 @@ #ifndef __HDAC_HDMI_H__ #define __HDAC_HDMI_H__ -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); #endif /* __HDAC_HDMI_H__ */ -- cgit From f3af359242f58b9c5f6f78ff4d13e8f108514bc0 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:50 +0530 Subject: ASoC: Intel: Skylake: Create ASoC jack for hdmi in rt286 machine Creates ASoC jack for HDMI pcm and calls hdmi codec API to initialize jack in skl_rt268 machine Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 5e56af3a6ee3..11647b0ea147 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -29,6 +29,7 @@ #include "../../codecs/hdac_hdmi.h" static struct snd_soc_jack skylake_headset; +static struct snd_soc_jack skylake_hdmi[3]; struct skl_hdmi_pcm { struct list_head head; @@ -458,16 +459,30 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { }, }; +#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; } return 0; -- cgit From c541b2dd45042c1e031778e0229d032dff90f045 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:51 +0530 Subject: ASoC: Intel: Skylake: Create ASoC jack for hdmi in skl_nau88l25_max98357a machine Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in skl_nau88l25_max98357a machine Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index bb4196867752..48f7c96b3f3d 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -32,6 +32,7 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3]; struct skl_hdmi_pcm { struct list_head head; @@ -603,16 +604,31 @@ static struct snd_soc_dai_link skylake_dais[] = { }, }; +#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, + &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; } return 0; -- cgit From 9e4278cd9b8e6e6464a4eb5e65c2b232076aa6c6 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:52 +0530 Subject: ASoC: Intel: Skylake: Create ASoC jack for hdmi in nau88l25_ssm4567 machine Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in skl_nau88l25_ssm4567 machine Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 41117bc51450..5deb68f0c1f0 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -36,6 +36,7 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3]; struct skl_hdmi_pcm { struct list_head head; @@ -654,16 +655,31 @@ static struct snd_soc_dai_link skylake_dais[] = { }, }; +#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, + &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; } return 0; -- cgit From 7932b8ace390c4474d1dc62d7843e843bc3ae9b5 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:53 +0530 Subject: ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_rt298 machine Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in bxt_rt298.c machine Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 09be868833d1..d5f53a6de041 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -28,6 +28,7 @@ /* Headset jack detection DAPM pins */ static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3]; struct bxt_hdmi_pcm { struct list_head head; @@ -453,16 +454,30 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { }, }; +#define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); if (err < 0) return err; + + i++; } return 0; -- cgit From 625de2bf2ed1632cb74a4a38f8f09a2063fb74af Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:54 +0530 Subject: ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_da7219_max98357 machine Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in bxt_da7219_max98357 machine Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index a9647a27ebc2..18f3d0e1a6b2 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -33,6 +33,7 @@ #define QUAD_CHANNEL 4 static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3]; struct bxt_hdmi_pcm { struct list_head head; @@ -517,16 +518,30 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; +#define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); if (err < 0) return err; + + i++; } return 0; -- cgit From 0324e51b5ba405cd2d66e9e95430f6b9562d0ac0 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:55 +0530 Subject: 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 Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 130 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/hdac_hdmi.h | 2 + 2 files changed, 132 insertions(+) (limited to 'sound') 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 { int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; + const char *jack_pin; + struct snd_soc_dapm_context *dapm; + const char *output_pin; }; 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; + 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) { /* * 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) pcm->jack_event--; } + + snd_soc_dapm_sync(port->dapm); } /* 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); if (ret < 0) return ret; + pin->ports[j].output_pin = widgets[i].name; i++; } } @@ -1557,6 +1568,125 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, 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, struct snd_soc_jack *jack) { 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 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, 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__ */ -- cgit From 64f8620d482d38ed093eca78d8ca9b1bb64a6172 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:56 +0530 Subject: ASoC: Intel: Skylake: Add jack port initialize in rt286 machine After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 11647b0ea147..f5ab7b8d51d1 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -95,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"}, - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, @@ -464,10 +460,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -485,7 +483,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; } - return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); } /* skylake audio machine driver for SPT + RT286S */ -- cgit From 565f13a95ec3d541324e80657bd512a19df8e576 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:57 +0530 Subject: ASoC: Intel: Skylake: Add jack port initialize in nau88l25_max98357a machine After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 48f7c96b3f3d..3b12bc1fa518 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -131,9 +131,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" }, - {"DP1", NULL, "hif5-0 Output"}, - {"DP2", NULL, "hif6-0 Output"}, - /* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" }, { "ssp0 Tx", NULL, "codec0_out" }, @@ -609,10 +606,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -631,7 +630,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; } - return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); } /* skylake audio machine driver for SPT + NAU88L25 */ -- cgit From 86b5703158ff39e5efe9480784a7cad1b4baef59 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:09:58 +0530 Subject: ASoC: Intel: Skylake: Add jack port initialize in nau88l25_ssm4567 machine After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5deb68f0c1f0..eb7751b0599b 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -136,9 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"}, - {"DP1", NULL, "hif5-0 Output"}, - {"DP2", NULL, "hif6-0 Output"}, - /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, @@ -660,10 +657,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -682,7 +681,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; } - return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); } /* skylake audio machine driver for SPT + NAU88L25 */ -- cgit From c5cf9f37a0fb6e50d68f6dcf58b93b2c47c780a1 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 7 Feb 2017 19:10:00 +0530 Subject: ASoC: Intel: bxt: Add jack port initialize in da7219_max98357a machine After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 18f3d0e1a6b2..2cda06cde4d1 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -523,10 +523,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -544,7 +546,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; } - return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); } /* broxton audio machine driver for SPT + da7219 */ -- cgit From db2f586b803eb6a7974098dd8ce1201f048071d0 Mon Sep 17 00:00:00 2001 From: Senthilnathan Veppur Date: Thu, 9 Feb 2017 16:44:01 +0530 Subject: ASoC: Intel: Skylake: Check device type to get endpoint configuration Geminilake has two different devices connected to the same SSP, so use device_type check to get correct device configuration. Signed-off-by: Senthilnathan Veppur Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 16 ++++++++++------ sound/soc/intel/skylake/skl-topology.c | 32 ++++++++++++++++++++++++++++++-- sound/soc/intel/skylake/skl.h | 3 ++- 3 files changed, 42 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 2710a3704a38..7eb9c419dc7f 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -102,14 +102,16 @@ static void dump_config(struct device *dev, u32 instance_id, u8 linktype, } static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, - u32 instance_id, u8 link_type, u8 dirn) + u32 instance_id, u8 link_type, u8 dirn, u8 dev_type) { - dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n", - epnt->virtual_bus_id, epnt->linktype, epnt->direction); + dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n", + epnt->virtual_bus_id, epnt->linktype, + epnt->direction, epnt->device_type); if ((epnt->virtual_bus_id == instance_id) && (epnt->linktype == link_type) && - (epnt->direction == dirn)) + (epnt->direction == dirn) && + (epnt->device_type == dev_type)) return true; else return false; @@ -117,7 +119,8 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, - u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn) + u8 s_fmt, u8 num_ch, u32 s_rate, + u8 dirn, u8 dev_type) { struct nhlt_fmt *fmt; struct nhlt_endpoint *epnt; @@ -135,7 +138,8 @@ struct nhlt_specific_cfg dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); for (j = 0; j < nhlt->endpoint_count; j++) { - if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { + if (skl_check_ep_match(dev, epnt, instance, link_type, + dirn, dev_type)) { fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); sp_config = skl_get_specific_cfg(dev, fmt, num_ch, diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index e6e76237f46b..ed58b5b3555a 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -330,6 +330,31 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, multiplier; } +static u8 skl_tplg_be_dev_type(int dev_type) +{ + int ret; + + switch (dev_type) { + case SKL_DEVICE_BT: + ret = NHLT_DEVICE_BT; + break; + + case SKL_DEVICE_DMIC: + ret = NHLT_DEVICE_DMIC; + break; + + case SKL_DEVICE_I2S: + ret = NHLT_DEVICE_I2S; + break; + + default: + ret = NHLT_DEVICE_INVALID; + break; + } + + return ret; +} + static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, struct skl_sst *ctx) { @@ -338,6 +363,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, u32 ch, s_freq, s_fmt; struct nhlt_specific_cfg *cfg; struct skl *skl = get_skl_ctx(ctx->dev); + u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); /* check if we already have blob */ if (m_cfg->formats_config.caps_size > 0) @@ -374,7 +400,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, /* update the blob based on virtual bus_id and default params */ cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, - s_fmt, ch, s_freq, dir); + s_fmt, ch, s_freq, dir, dev_type); if (cfg) { m_cfg->formats_config.caps_size = cfg->size; m_cfg->formats_config.caps = (u32 *) &cfg->caps; @@ -1448,6 +1474,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, struct nhlt_specific_cfg *cfg; struct skl *skl = get_skl_ctx(dai->dev); int link_type = skl_tplg_be_link_type(mconfig->dev_type); + u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); skl_tplg_fill_dma_id(mconfig, params); @@ -1457,7 +1484,8 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, /* update the blob based on virtual bus_id*/ cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, params->s_fmt, params->ch, - params->s_freq, params->stream); + params->s_freq, params->stream, + dev_type); if (cfg) { mconfig->formats_config.caps_size = cfg->size; mconfig->formats_config.caps = (u32 *) &cfg->caps; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 0a1b02e21277..bbef77d2b917 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -118,7 +118,8 @@ int skl_platform_register(struct device *dev); struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); void skl_nhlt_free(struct nhlt_acpi_table *addr); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, - u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); + u8 link_type, u8 s_fmt, u8 no_ch, + u32 s_rate, u8 dirn, u8 dev_type); int skl_get_dmic_geo(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl); -- cgit From 06a99ddd2049e2697de32a9435c4d5c5b5c78360 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 9 Feb 2017 16:44:02 +0530 Subject: ASoC: rt298: Add DMI match for Geminilake reference platform Geminilake reference platform also uses combo jack for audio connector so we need to set codec pdata to use this based on DMI match for this board. Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 7150a407ffd9..d9e96e65e1c4 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1163,6 +1163,13 @@ static const struct dmi_system_id force_combo_jack_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Broxton P") } }, + { + .ident = "Intel Gemini Lake", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp"), + DMI_MATCH(DMI_PRODUCT_NAME, "Geminilake") + } + }, { } }; -- cgit From 255048634366c9aee87d7ab801fa530c34f10b9f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 9 Feb 2017 16:44:03 +0530 Subject: ASoC: Intel: Skylake: Add Geminlake IDs Geminilake is next gen SoC, so add the IDs for Geminilake. Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 7 +++++++ sound/soc/intel/skylake/skl.c | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index e79cbcf6e462..e66870474f10 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -220,6 +220,13 @@ static const struct skl_dsp_ops dsp_ops[] = { .init_fw = bxt_sst_init_fw, .cleanup = bxt_sst_dsp_cleanup }, + { + .id = 0x3198, + .loader_ops = bxt_get_loader_ops, + .init = bxt_sst_dsp_init, + .init_fw = bxt_sst_init_fw, + .cleanup = bxt_sst_dsp_cleanup + }, }; const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 1152e46daede..0c57d4eaae3a 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -883,6 +883,10 @@ static struct sst_acpi_mach sst_kbl_devdata[] = { {} }; +static struct sst_acpi_mach sst_glk_devdata[] = { + { "INT343A", "glk_alc298s_i2s", "intel/dsp_fw_glk.bin", NULL, NULL, NULL }, +}; + /* PCI IDs */ static const struct pci_device_id skl_ids[] = { /* Sunrise Point-LP */ @@ -894,6 +898,9 @@ static const struct pci_device_id skl_ids[] = { /* KBL */ { PCI_DEVICE(0x8086, 0x9D71), .driver_data = (unsigned long)&sst_kbl_devdata}, + /* GLK */ + { PCI_DEVICE(0x8086, 0x3198), + .driver_data = (unsigned long)&sst_glk_devdata}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); -- cgit From e3efb2ad834b50cb9c8625155e3e2674f5bc443b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 9 Feb 2017 16:44:04 +0530 Subject: ASoC: hdac_hdmi: Add device id for Geminilake Geminilake is new Intel SoC, so add codec entry for HDMI Signed-off-by: Vinod Koul Signed-off-by: Senthilnathan Veppur Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 0a5510a3a8e1..78fca8acd3ec 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2127,6 +2127,7 @@ static const struct hda_device_id hdmi_list[] = { HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), + HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0), {} }; -- cgit From 7ba8ba3f4f9604ce776475e3b501e41c762af797 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 17 Feb 2017 15:04:46 +0530 Subject: ASoC: Intel: bxt: Add jack port initialize in bxt_rt298 machine After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected. Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index d5f53a6de041..176c080a9818 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -459,10 +459,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -480,7 +482,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; } - return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); } -- cgit