From 343e424303fc8fd222ec75d11c69cc5a9c2bd484 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 13 Aug 2019 13:51:53 +0800 Subject: [PATCH 1/4] ASoC: codec: rt700: Add prepare support in rt700 Now set soundwire stream in prepare function to follow hda codec driver. It makes easier for soundwire dai driver to prepare soundwire stream data for codec driver for the soundwire stream data is not available in hw_params function Signed-off-by: Rander Wang --- sound/soc/codecs/rt700.c | 64 ++++++++++++++++++++++++---------------- sound/soc/codecs/rt700.h | 2 ++ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 24a61d45c68ab0..e4851c73039037 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1232,20 +1232,14 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); - struct sdw_stream_config stream_config; - struct sdw_port_config port_config; + struct sdw_stream_config *stream_config; + struct sdw_port_config *port_config; enum sdw_data_direction direction; - struct sdw_stream_data *stream; - int retval, port, num_channels; + int port, num_channels; unsigned int val = 0; dev_err(dai->dev, "%s %s", __func__, dai->name); - stream = snd_soc_dai_get_dma_data(dai, substream); - - if (!stream) - return -ENOMEM; - dev_err(dai->dev, "1 %s %s", __func__, dai->name); if (!rt700->slave) return 0; @@ -1269,24 +1263,17 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(component->dev, "Invalid DAI id %d\n", dai->id); return -EINVAL; } - dev_err(dai->dev, "2 %s %s", __func__, dai->name); - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; + stream_config = &rt700->stream_config; + stream_config->frame_rate = params_rate(params); + stream_config->ch_count = params_channels(params); + stream_config->bps = snd_pcm_format_width(params_format(params)); + stream_config->direction = direction; - dev_err(dai->dev, "3 %s %s", __func__, dai->name); num_channels = params_channels(params); - port_config.ch_mask = (1 << (num_channels)) - 1; - port_config.num = port; - - retval = sdw_stream_add_slave(rt700->slave, &stream_config, - &port_config, 1, stream->sdw_stream); - if (retval) { - dev_err(dai->dev, "Unable to configure port\n"); - return retval; - } + port_config = &rt700->port_config; + port_config->ch_mask = (1 << (num_channels)) - 1; + port_config->num = port; dev_err(dai->dev, "4 %s %s", __func__, dai->name); switch (params_rate(params)) { @@ -1339,7 +1326,33 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_component_write(component, RT700_ADC_FORMAT_L, val); dev_err(dai->dev, "5 %s %s", __func__, dai->name); - return retval; + return 0; +} + +static int rt700_prepare_stream(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream; + int retval; + + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) { + dev_err(dai->dev, "no dma data found in dai %s", dai->name); + return -ENOMEM; + } + + retval = sdw_stream_add_slave(rt700->slave, &rt700->stream_config, + &rt700->port_config, 1, + stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + return 0; } static int rt700_pcm_hw_free(struct snd_pcm_substream *substream, @@ -1365,6 +1378,7 @@ static struct snd_soc_dai_ops rt700_ops = { .hw_params = rt700_pcm_hw_params, .hw_free = rt700_pcm_hw_free, .set_sdw_stream = rt700_set_sdw_stream, + .prepare = rt700_prepare_stream, .shutdown = rt700_shutdown, }; diff --git a/sound/soc/codecs/rt700.h b/sound/soc/codecs/rt700.h index c0771e98b3c9dd..ce00e0f1af33de 100644 --- a/sound/soc/codecs/rt700.h +++ b/sound/soc/codecs/rt700.h @@ -25,6 +25,8 @@ struct rt700_priv { int dbg_payload; enum sdw_slave_status status; struct sdw_bus_params params; + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; bool hw_init; }; From 835b6a8f9f93880c54871c32518ceb792e71beae Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 13 Aug 2019 14:54:41 +0800 Subject: [PATCH 2/4] ASoC: SOF: sdw: revert change for sdw dai in sof driver Now move these functions to sdw dai driver. And there is no need to check dai index and store sdw stream data in privated_data in runtime. Signed-off-by: Rander Wang --- sound/soc/sof/intel/cnl.c | 1 - sound/soc/sof/intel/hda-pcm.c | 189 +------------------------------ sound/soc/sof/intel/hda-stream.c | 46 +------- sound/soc/sof/pcm.c | 17 +-- 4 files changed, 10 insertions(+), 243 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3a6432c4ad27a6..6d7d9c93252c81 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -224,7 +224,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, - .pcm_prepare = sdw_pcm_prepare, /* firmware loading */ .load_firmware = snd_sof_load_firmware_raw, diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 40e08e85b6850a..365685045ca2eb 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -128,99 +128,15 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, return 0; } -static int sof_sdw_stream_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct hdac_stream *hstream = substream->runtime->private_data; - struct sof_intel_hda_stream *hda_stream; - struct sdw_stream_runtime *sdw_stream; - int ret; - - if (rtd->cpu_dai->id < SDW_DAI_ID_RANGE_START || - rtd->cpu_dai->id > SDW_DAI_ID_RANGE_END) - return 0; - - hda_stream = container_of(hstream, - struct sof_intel_hda_stream, - hda_stream.hstream); - - sdw_stream = hda_stream->sdw_stream; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - ret = sdw_enable_stream(sdw_stream); - if (ret) { - dev_err(rtd->cpu_dai->dev, - "sdw_enable_stream: failed: %d", ret); - return ret; - } - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - ret = sdw_disable_stream(sdw_stream); - if (ret) { - dev_err(rtd->cpu_dai->dev, - "sdw_disable_stream: failed: %d", ret); - return ret; - } - break; - - default: - return -EINVAL; - } - - return 0; -} - int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); - if (rtd->dai_link->no_pcm) - return sof_sdw_stream_trigger(substream, cmd); - return hda_dsp_stream_trigger(sdev, stream, cmd); } -int sdw_pcm_prepare(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream) -{ - //struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct hdac_stream *hstream = substream->runtime->private_data; - struct sof_intel_hda_stream *hda_stream; - struct sdw_stream_runtime *sdw_stream; - struct device *dev; - int ret = 0; - - if (rtd->cpu_dai->id >= SDW_DAI_ID_RANGE_START && - rtd->cpu_dai->id <= SDW_DAI_ID_RANGE_END) { - - hda_stream = container_of(hstream, - struct sof_intel_hda_stream, - hda_stream.hstream); - - sdw_stream = hda_stream->sdw_stream; - - if (!sdw_stream) - return -EINVAL; - - dev = rtd->cpu_dai->dev; - ret = sdw_prepare_stream(sdw_stream); - if (ret) - dev_err(dev, "sdw_prepare_stream: failed: %d", ret); - } - - return ret; -} - snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -293,24 +209,6 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, { struct hdac_ext_stream *dsp_stream; int direction = substream->stream; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct hdac_stream *hstream; - struct sof_intel_hda_stream *hda_stream; - struct sdw_stream_runtime *sdw_stream = NULL; - struct snd_soc_dai_link *dai_link = rtd->dai_link; - int i, ret = 0; - char *name; - - pr_err("plb: in %s dai_link->name %s dai_link->cpus->dai_name %s no pcm %d\n", __func__, dai_link->name, dai_link->cpus->dai_name, dai_link->no_pcm); - - if (runtime->private_data) { - hstream = runtime->private_data; - if (hstream->opened) { - pr_err("bard: hstream is already used\n"); - return 0; - } - } dsp_stream = hda_dsp_stream_get(sdev, direction); @@ -321,82 +219,16 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, /* binding pcm substream to hda stream */ substream->runtime->private_data = &dsp_stream->hstream; - - /* SoundWire handling: THIS IS A HACK */ - if (rtd->cpu_dai->id >= SDW_DAI_ID_RANGE_START && - rtd->cpu_dai->id <= SDW_DAI_ID_RANGE_END) { - - pr_err("plb: in %s sdw handling cpu_dai->id %d\n", __func__, rtd->cpu_dai->id); - - hstream = substream->runtime->private_data; - hda_stream = container_of(hstream, - struct sof_intel_hda_stream, - hda_stream.hstream); - - if (hda_stream->sdw_stream) { - pr_err("bard: sdw_stream is already allocated\n"); - return 0; - } - - name = kzalloc(32, GFP_KERNEL); - if (!name) - return -ENOMEM; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snprintf(name, 32, "%s-Playback", rtd->cpu_dai->name); - else - snprintf(name, 32, "%s-Capture", rtd->cpu_dai->name); - - sdw_stream = sdw_alloc_stream(name); - if (!sdw_stream) { - dev_err(rtd->cpu_dai->dev, - "alloc stream failed for DAI %s: %d", - rtd->cpu_dai->name, ret); - ret = -ENOMEM; - goto error; - } - - /* Set stream pointer on CPU DAI */ - snd_soc_dai_set_sdw_stream(rtd->cpu_dai, - sdw_stream, - substream->stream); - - /* Set stream pointer on all CODEC DAIs */ - for (i = 0; i < rtd->num_codecs; i++) - snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], - sdw_stream, - substream->stream); - - hda_stream->sdw_stream = sdw_stream; - } - return 0; - -error: - kfree(name); - sdw_release_stream(sdw_stream); - return ret; } int hda_dsp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - struct hdac_stream *hstream = NULL; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct sof_intel_hda_stream *hda_stream; - struct sdw_stream_runtime *sdw_stream = NULL; + struct hdac_stream *hstream = substream->runtime->private_data; int direction = substream->stream; int ret; - hstream = runtime->private_data; - - if (rtd->dai_link->no_pcm) - goto be; - - if (!hstream->opened) - goto free; - ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag); if (ret) { @@ -404,23 +236,6 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev, return -ENODEV; } - goto free; - -be: - hda_stream = container_of(hstream, - struct sof_intel_hda_stream, - hda_stream.hstream); - sdw_stream = hda_stream->sdw_stream; - if (!sdw_stream) - return -EINVAL; - - sdw_release_stream(sdw_stream); - hda_stream->sdw_stream = NULL; - -free: - /* unbinding pcm substream to hda stream */ - if (!hstream->opened && !hda_stream->sdw_stream) - substream->runtime->private_data = NULL; - return 0; } + diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 191a8f64531f81..4c8d19527f9038 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -488,59 +488,19 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, { struct hdac_stream *stream = substream->runtime->private_data; struct hdac_ext_stream *link_dev = container_of(stream, - struct hdac_ext_stream, - hstream); - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct hdac_stream *hstream = substream->runtime->private_data; - struct sof_intel_hda_stream *hda_stream; - struct sdw_stream_runtime *sdw_stream; + struct hdac_ext_stream, + hstream); struct hdac_bus *bus = sof_to_bus(sdev); u32 mask = 0x1 << stream->index; - int ret; - struct sof_ipc_dai_config config; - struct sof_ipc_reply reply; - u32 size = sizeof(config); - - if (rtd->dai_link->no_pcm) - goto be; spin_lock_irq(&bus->reg_lock); /* couple host and link DMA if link DMA channel is idle */ if (!link_dev->link_locked) snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPCTL, mask, 0); + SOF_HDA_REG_PP_PPCTL, mask, 0); spin_unlock_irq(&bus->reg_lock); return 0; -be: - - hda_stream = container_of(hstream, - struct sof_intel_hda_stream, - hda_stream.hstream); - sdw_stream = hda_stream->sdw_stream; - if (!sdw_stream) - return -EINVAL; - - ret = sdw_deprepare_stream(sdw_stream); - if (ret) - dev_err(sdev->dev, "sdw_deprepare_stream: failed %d", ret); - - memset(&config, 0, size); - config.hdr.size = size; - config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; - config.type = SOF_DAI_INTEL_ALH; - config.dai_index = 0; /* FIXME: make this dynamic */ - config.alh.stream_id = 0xFFFFFFFF; - - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config.hdr.cmd, &config, size, &reply, - sizeof(reply)); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI hw_free for ALH %d\n", - config.dai_index); - } - return ret; } irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index badbee6723d515..b698edbfc1cc4f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -248,7 +248,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) /* skip front-end specific inits for BE */ if (rtd->dai_link->no_pcm) - goto platform_hw_free; + return 0; spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) @@ -269,7 +269,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (ret < 0) return ret; -platform_hw_free: ret = snd_sof_pcm_platform_hw_free(sdev, substream); if (ret < 0) dev_err(sdev->dev, "error: platform hw free failed\n"); @@ -287,10 +286,8 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) int ret; /* skip front-end specific inits for BE */ - if (rtd->dai_link->no_pcm) { - snd_sof_pcm_platform_prepare(sdev, substream); + if (rtd->dai_link->no_pcm) return 0; - } spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) @@ -329,10 +326,8 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int ret; /* skip front-end specific inits for BE */ - if (rtd->dai_link->no_pcm) { - snd_sof_pcm_platform_trigger(sdev, substream, cmd); + if (rtd->dai_link->no_pcm) return 0; - } spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) @@ -433,7 +428,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) /* skip front-end specific inits for BE */ if (rtd->dai_link->no_pcm) - goto platform_open; + return 0; spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) @@ -490,7 +485,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].substream = substream; spcm->prepared[substream->stream] = false; -platform_open: ret = snd_sof_pcm_platform_open(sdev, substream); if (ret < 0) dev_err(sdev->dev, "error: pcm open failed %d\n", ret); @@ -509,7 +503,7 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) /* skip front-end specific inits for BE */ if (rtd->dai_link->no_pcm) - goto platform_close; + return 0; spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) @@ -518,7 +512,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); -platform_close: err = snd_sof_pcm_platform_close(sdev, substream); if (err < 0) { dev_err(sdev->dev, "error: pcm close failed %d\n", From 7c0809baa335da87eb9b6dd698606a8f5871f280 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 13 Aug 2019 15:00:55 +0800 Subject: [PATCH 3/4] soundwire: intel: add more features for sdw dai driver Support prepare and trigger functions. Free more resource in hw_free function. Setup sdw stream in hw_params function. Signed-off-by: Rander Wang --- drivers/soundwire/intel.c | 149 ++++++++++++++++++++++++++++ include/linux/soundwire/sdw_intel.h | 1 + 2 files changed, 150 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 312c0ad2573fc6..bbb205e69caa47 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -593,6 +593,17 @@ static int intel_config_stream(struct sdw_intel *sdw, return -EIO; } +static int intel_free_stream(struct sdw_intel *sdw, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (sdw->res->ops && sdw->res->ops->free_stream && sdw->res->arg) + return sdw->res->ops->free_stream(sdw->res->arg, + substream, dai); + + return 0; +} + /* * bank switch routines */ @@ -738,6 +749,62 @@ static int intel_startup(struct snd_pcm_substream *substream, return ret; } +static int sdw_stream_setup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sdw_stream_runtime *sdw_stream = NULL; + char *name; + int i, ret = 0; + + name = kzalloc(32, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snprintf(name, 32, "%s-Playback", dai->name); + else + snprintf(name, 32, "%s-Capture", dai->name); + + sdw_stream = sdw_alloc_stream(name); + if (!sdw_stream) { + dev_err(dai->dev, + "alloc stream failed for DAI %s: %d", + dai->name, ret); + ret = -ENOMEM; + goto error; + } + + /* Set stream pointer on CPU DAI */ + ret = snd_soc_dai_set_sdw_stream(dai, + sdw_stream, + substream->stream); + if (ret < 0) { + dev_err(dai->dev, "failed to set stream pointer on cpu dai %s", + dai->name); + return ret; + } + + /* Set stream pointer on all CODEC DAIs */ + for (i = 0; i < rtd->num_codecs; i++) { + ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], + sdw_stream, + substream->stream); + if (ret < 0) { + dev_err(dai->dev, "failed to set stream pointer on codec dai %s", + rtd->codec_dais[i]->name); + return ret; + } + } + + return 0; + +error: + kfree(name); + sdw_release_stream(sdw_stream); + return ret; +} + static int intel_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -750,6 +817,12 @@ static int intel_hw_params(struct snd_pcm_substream *substream, int ret, i, ch, dir; bool pcm = true; + ret = sdw_stream_setup(substream, dai); + if (ret) { + dev_err(cdns->dev, "stream setup failed:%d\n", ret); + return -EIO; + } + dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) return -EIO; @@ -835,10 +908,72 @@ static int intel_hw_params(struct snd_pcm_substream *substream, return ret; } +static int intel_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_cdns_dma_data *dma; + int ret; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) { + dev_err(dai->dev, "failed to get dma data in %s", + __func__); + return -EIO; + } + + ret = sdw_prepare_stream(dma->stream); + return ret; +} + +static int intel_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct sdw_cdns_dma_data *dma; + int ret; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) { + dev_err(dai->dev, "failed to get dma data in %s", __func__); + return -EIO; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + ret = sdw_enable_stream(dma->stream); + if (ret) { + dev_err(dai->dev, + "%s trigger %d failed: %d", + __func__, cmd, ret); + return ret; + } + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sdw_disable_stream(dma->stream); + if (ret) { + dev_err(dai->dev, + "%s trigger %d failed: %d", + __func__, cmd, ret); + return ret; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + static int intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_cdns_dma_data *dma; int ret; @@ -846,6 +981,12 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) if (!dma) return -EIO; + ret = sdw_deprepare_stream(dma->stream); + if (ret) { + dev_err(dai->dev, "sdw_deprepare_stream: failed %d", ret); + return ret; + } + ret = sdw_stream_remove_master(&cdns->bus, dma->stream); if (ret < 0) dev_err(dai->dev, "remove master from stream %s failed: %d\n", @@ -853,6 +994,10 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) intel_port_cleanup(dma); kfree(dma->port); + + ret = intel_free_stream(sdw, substream, dai); + sdw_release_stream(dma->stream); + return ret; } @@ -898,6 +1043,8 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .hw_free = intel_hw_free, .shutdown = intel_shutdown, .set_sdw_stream = intel_pcm_set_sdw_stream, + .prepare = intel_prepare, + .trigger = intel_trigger, }; static const struct snd_soc_dai_ops intel_pdm_dai_ops = { @@ -905,6 +1052,8 @@ static const struct snd_soc_dai_ops intel_pdm_dai_ops = { .hw_free = intel_hw_free, .shutdown = intel_shutdown, .set_sdw_stream = intel_pdm_set_sdw_stream, + .prepare = intel_prepare, + .trigger = intel_trigger, }; static const struct snd_soc_component_driver dai_component = { diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index c9427cb6020b3e..5fab33c2530923 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -13,6 +13,7 @@ struct sdw_intel_ops { int (*config_stream)(void *arg, void *substream, void *dai, void *hw_params, int stream_num); + int (*free_stream)(void *arg, void *substream, void *dai); }; /** From 847e2a0d1284dd25f355c0c1fc06fdd35ffee55b Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 13 Aug 2019 15:08:36 +0800 Subject: [PATCH 4/4] ASoC: SOF: sdw: add a callback function to free resource in FW sdw_free_stream release dma usage in FW when sdw stream is free. Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5a85d86654671c..6684bbb5d25957 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -81,8 +81,36 @@ static int sdw_config_stream(void *arg, void *s, void *dai, return ret; } +static int sdw_free_stream(void *arg, void *s, void *dai) +{ + struct snd_sof_dev *sdev = arg; + struct sof_ipc_dai_config config; + struct sof_ipc_reply reply; + int size = sizeof(config); + int ret; + + memset(&config, 0, size); + config.hdr.size = size; + config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config.type = SOF_DAI_INTEL_ALH; + config.dai_index = 0; /* FIXME: make this dynamic */ + config.alh.stream_id = 0xFFFFFFFF; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config.hdr.cmd, &config, size, &reply, + sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI hw_free for ALH %d\n", + config.dai_index); + } + + return ret; +} + static const struct sdw_intel_ops sdw_callback = { .config_stream = sdw_config_stream, + .free_stream = sdw_free_stream, }; static int hda_sdw_init(struct snd_sof_dev *sdev)