diff options
Diffstat (limited to 'sound/soc/intel/sst-haswell-ipc.c')
-rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 177 |
1 files changed, 19 insertions, 158 deletions
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 8156cc1accb7..394af5684c05 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -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, @@ -2132,7 +1994,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); } |