int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
        const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
 int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream);
 snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream);
 
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 
 
 struct dmaengine_pcm_runtime_data {
        struct dma_chan *dma_chan;
+       dma_cookie_t cookie;
 
        unsigned int pos;
 
 
        desc->callback = dmaengine_pcm_dma_complete;
        desc->callback_param = substream;
-       dmaengine_submit(desc);
+       prtd->cookie = dmaengine_submit(desc);
 
        return 0;
 }
 }
 EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
 
+/**
+ * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function can be used as the PCM pointer callback for dmaengine based PCM
+ * driver implementations.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+       struct dma_tx_state state;
+       enum dma_status status;
+       unsigned int buf_size;
+       unsigned int pos = 0;
+
+       status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+       if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
+               buf_size = snd_pcm_lib_buffer_bytes(substream);
+               if (state.residue > 0 && state.residue <= buf_size)
+                       pos = buf_size - state.residue;
+       }
+
+       return bytes_to_frames(substream->runtime, pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
+
 static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd,
        dma_filter_fn filter_fn, void *filter_data)
 {