Merge branch 'fix/intel' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[cascardo/linux.git] / sound / soc / intel / sst-haswell-ipc.c
index 6c7052a..863a9ca 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
 #include <linux/pm_runtime.h>
+#include <sound/asound.h>
 
 #include "sst-haswell-ipc.h"
 #include "sst-dsp.h"
@@ -94,6 +95,8 @@
 /* Mailbox */
 #define IPC_MAX_MAILBOX_BYTES  256
 
+#define INVALID_STREAM_HW_ID   0xffffffff
+
 /* Global Message - Types and Replies */
 enum ipc_glb_type {
        IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
@@ -240,6 +243,9 @@ struct sst_hsw_stream {
        u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
        void *pdata;
 
+       /* record the fw read position when playback */
+       snd_pcm_uframes_t old_position;
+       bool play_silence;
        struct list_head node;
 };
 
@@ -275,7 +281,6 @@ struct sst_hsw {
        /* FW config */
        struct sst_hsw_ipc_fw_ready fw_ready;
        struct sst_hsw_ipc_fw_version version;
-       struct sst_module *scratch;
        bool fw_done;
        struct sst_fw *sst_fw;
 
@@ -337,12 +342,6 @@ static inline u32 msg_get_stage_type(u32 msg)
        return (msg & IPC_STG_TYPE_MASK) >>  IPC_STG_TYPE_SHIFT;
 }
 
-static inline u32 msg_set_stage_type(u32 msg, u32 type)
-{
-       return (msg & ~IPC_STG_TYPE_MASK) +
-               (type << IPC_STG_TYPE_SHIFT);
-}
-
 static inline u32 msg_get_stream_id(u32 msg)
 {
        return (msg & IPC_STR_ID_MASK) >>  IPC_STR_ID_SHIFT;
@@ -969,45 +968,6 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw,
 }
 
 /* Mixer Controls */
-int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel)
-{
-       int ret;
-
-       ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel,
-               &stream->mute_volume[channel]);
-       if (ret < 0)
-               return ret;
-
-       ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
-                       stream->reply.stream_hw_id, channel);
-               return ret;
-       }
-
-       stream->mute[channel] = 1;
-       return 0;
-}
-
-int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel)
-
-{
-       int ret;
-
-       stream->mute[channel] = 0;
-       ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel,
-               stream->mute_volume[channel]);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
-                       stream->reply.stream_hw_id, channel);
-               return ret;
-       }
-
-       return 0;
-}
-
 int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
        u32 stage_id, u32 channel, u32 *volume)
 {
@@ -1021,17 +981,6 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream
        return 0;
 }
 
-int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u64 curve_duration,
-       enum sst_hsw_volume_curve curve)
-{
-       /* curve duration in steps of 100ns */
-       stream->vol_req.curve_duration = curve_duration;
-       stream->vol_req.curve_type = curve;
-
-       return 0;
-}
-
 /* stream volume */
 int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
@@ -1083,42 +1032,6 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
        return 0;
 }
 
-int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
-{
-       int ret;
-
-       ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel,
-               &hsw->mute_volume[channel]);
-       if (ret < 0)
-               return ret;
-
-       ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
-                       channel);
-               return ret;
-       }
-
-       hsw->mute[channel] = 1;
-       return 0;
-}
-
-int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
-{
-       int ret;
-
-       ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel,
-               hsw->mixer_info.volume_register_address[channel]);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
-                       channel);
-               return ret;
-       }
-
-       hsw->mute[channel] = 0;
-       return 0;
-}
-
 int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 *volume)
 {
@@ -1132,16 +1045,6 @@ int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        return 0;
 }
 
-int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
-        u64 curve_duration, enum sst_hsw_volume_curve curve)
-{
-       /* curve duration in steps of 100ns */
-       hsw->curve_duration = curve_duration;
-       hsw->curve_type = curve;
-
-       return 0;
-}
-
 /* global mixer volume */
 int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 volume)
@@ -1208,6 +1111,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
                return NULL;
 
        spin_lock_irqsave(&sst->spinlock, flags);
+       stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
        list_add(&stream->node, &hsw->stream_list);
        stream->notify_position = notify_position;
        stream->pdata = data;
@@ -1447,50 +1351,32 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        return 0;
 }
 
-/* Stream Information - these calls could be inline but we want the IPC
- ABI to be opaque to client PCM drivers to cope with any future ABI changes */
-int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
 {
-       return stream->reply.stream_hw_id;
+       return stream->old_position;
 }
 
-int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, snd_pcm_uframes_t val)
 {
-       return stream->reply.mixer_hw_id;
+       stream->old_position = val;
 }
 
-u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
 {
-       return stream->reply.read_position_register_address;
-}
-
-u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
-{
-       return stream->reply.presentation_position_register_address;
-}
-
-u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 channel)
-{
-       if (channel >= 2)
-               return 0;
-
-       return stream->reply.peak_meter_register_address[channel];
+       return stream->play_silence;
 }
 
-u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 channel)
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, bool val)
 {
-       if (channel >= 2)
-               return 0;
-
-       return stream->reply.volume_register_address[channel];
+       stream->play_silence = val;
 }
 
+/* Stream Information - these calls could be inline but we want the IPC
+ ABI to be opaque to client PCM drivers to cope with any future ABI changes */
 int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
 {
        struct sst_hsw_ipc_stream_info_reply *reply;
@@ -1628,30 +1514,6 @@ u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
        return ppos;
 }
 
-int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 stage_id, u32 position)
-{
-       u32 header;
-       int ret;
-
-       trace_stream_write_position(stream->reply.stream_hw_id, position);
-
-       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
-               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
-       header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
-       header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT);
-       header |= (stage_id << IPC_STG_ID_SHIFT);
-       stream->wpos.position = position;
-
-       ret = ipc_tx_message_nowait(hsw, header, &stream->wpos,
-               sizeof(stream->wpos));
-       if (ret < 0)
-               dev_err(hsw->dev, "error: stream %d set position %d failed\n",
-                       stream->reply.stream_hw_id, position);
-
-       return ret;
-}
-
 /* physical BE config */
 int sst_hsw_device_set_config(struct sst_hsw *hsw,
        enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
@@ -2148,7 +2010,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
        dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
                        hsw->dx_context, hsw->dx_context_paddr);
        sst_dsp_free(hsw->dsp);
-       kfree(hsw->scratch);
        kthread_stop(hsw->tx_thread);
        kfree(hsw->msg);
 }