ASoC: SOF: pcm: add ALH support
[platform/kernel/linux-rpi.git] / sound / soc / sof / pcm.c
index 334e9d5..e3f6a6d 100644 (file)
@@ -208,11 +208,31 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       spcm->prepared[substream->stream] = true;
+
        /* save pcm hw_params */
        memcpy(&spcm->params[substream->stream], params, sizeof(*params));
 
-       /* clear hw_params_upon_resume flag */
-       spcm->hw_params_upon_resume[substream->stream] = 0;
+       return ret;
+}
+
+static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream,
+                               struct snd_sof_dev *sdev,
+                               struct snd_sof_pcm *spcm)
+{
+       struct sof_ipc_stream stream;
+       struct sof_ipc_reply reply;
+       int ret;
+
+       stream.hdr.size = sizeof(stream);
+       stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
+       stream.comp_id = spcm->stream[substream->stream].comp_id;
+
+       /* send IPC to the DSP */
+       ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
+                                sizeof(stream), &reply, sizeof(reply));
+       if (!ret)
+               spcm->prepared[substream->stream] = false;
 
        return ret;
 }
@@ -224,8 +244,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
                snd_soc_rtdcom_lookup(rtd, DRV_NAME);
        struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
        struct snd_sof_pcm *spcm;
-       struct sof_ipc_stream stream;
-       struct sof_ipc_reply reply;
        int ret;
 
        /* nothing to do for BE */
@@ -236,16 +254,13 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
        if (!spcm)
                return -EINVAL;
 
+       if (!spcm->prepared[substream->stream])
+               return 0;
+
        dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
                substream->stream);
 
-       stream.hdr.size = sizeof(stream);
-       stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
-       stream.comp_id = spcm->stream[substream->stream].comp_id;
-
-       /* send IPC to the DSP */
-       ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
-                                sizeof(stream), &reply, sizeof(reply));
+       ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
 
        snd_pcm_lib_free_pages(substream);
 
@@ -278,11 +293,7 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream)
        if (!spcm)
                return -EINVAL;
 
-       /*
-        * check if hw_params needs to be set-up again.
-        * This is only needed when resuming from system sleep.
-        */
-       if (!spcm->hw_params_upon_resume[substream->stream])
+       if (spcm->prepared[substream->stream])
                return 0;
 
        dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id,
@@ -311,6 +322,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_sof_pcm *spcm;
        struct sof_ipc_stream stream;
        struct sof_ipc_reply reply;
+       bool reset_hw_params = false;
        int ret;
 
        /* nothing to do for BE */
@@ -351,6 +363,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
                stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
+               reset_hw_params = true;
                break;
        default:
                dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd);
@@ -363,21 +376,10 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
                                 sizeof(stream), &reply, sizeof(reply));
 
-       if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND)
-               return ret;
+       if (!ret && reset_hw_params)
+               ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
 
-       /*
-        * The hw_free op is usually called when the pcm stream is closed.
-        * Since the stream is not closed during suspend, the DSP needs to be
-        * notified explicitly to free pcm to prevent errors upon resume.
-        */
-       stream.hdr.size = sizeof(stream);
-       stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
-       stream.comp_id = spcm->stream[substream->stream].comp_id;
-
-       /* send IPC to the DSP */
-       return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
-                                 sizeof(stream), &reply, sizeof(reply));
+       return ret;
 }
 
 static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream)
@@ -481,6 +483,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
        spcm->stream[substream->stream].posn.host_posn = 0;
        spcm->stream[substream->stream].posn.dai_posn = 0;
        spcm->stream[substream->stream].substream = substream;
+       spcm->prepared[substream->stream] = false;
 
        ret = snd_sof_pcm_platform_open(sdev, substream);
        if (ret < 0)
@@ -672,6 +675,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
        case SOF_DAI_INTEL_HDA:
                /* do nothing for HDA dai_link */
                break;
+       case SOF_DAI_INTEL_ALH:
+               /* do nothing for ALH dai_link */
+               break;
        default:
                dev_err(sdev->dev, "error: invalid DAI type %d\n",
                        dai->dai_config->type);