diff options
author | Robert Marklund <robert.marklund@stericsson.com> | 2011-05-25 17:37:45 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-05-22 11:04:51 +0200 |
commit | 036c288037f5248dbd685d1db3e2bf15775192b6 (patch) | |
tree | 621cf32be05aa9f46c475244936fcdf2c3d17f13 | |
parent | 3a358a4bbcfdf03c328db82180a090a8522466db (diff) |
ux500-ASoC: Update ux500 driver to use dmaengine
ST-Ericsson Linux next: 342252
ST-Ericsson ID: 342253
ST-Ericsson FOSS-OUT ID: Trivial
Signed-off-by: Robert Marklund <robert.marklund@stericsson.com>
Change-Id: I6d0b04aaa9f3e0d170cb3dd2510960f606c4435f
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24728
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-rw-r--r-- | drivers/misc/i2s/msp_i2s.c | 102 | ||||
-rw-r--r-- | include/linux/i2s/i2s.h | 6 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_dai.c | 26 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_dai.h | 4 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_pcm.c | 35 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_pcm.h | 1 |
6 files changed, 69 insertions, 105 deletions
diff --git a/drivers/misc/i2s/msp_i2s.c b/drivers/misc/i2s/msp_i2s.c index bf80cc5cc1b..90629398202 100644 --- a/drivers/misc/i2s/msp_i2s.c +++ b/drivers/misc/i2s/msp_i2s.c @@ -78,16 +78,13 @@ static int stm_msp_disable(struct msp *msp, int direction, i2s_flag flag); static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag); static int stm_msp_hw_status(struct i2s_controller *i2s_cont); -static dma_addr_t stm_msp_get_pointer(struct i2s_controller *i2s_cont, - enum i2s_direction_t i2s_direction); #define I2S_DEVICE "i2s_device" static struct i2s_algorithm i2s_algo = { - .cont_setup = stm_msp_configure_enable, - .cont_transfer = stm_msp_transceive_data, - .cont_cleanup = stm_msp_close, - .cont_hw_status = stm_msp_hw_status, - .cont_get_pointer = stm_msp_get_pointer, + .cont_setup = stm_msp_configure_enable, + .cont_transfer = stm_msp_transceive_data, + .cont_cleanup = stm_msp_close, + .cont_hw_status = stm_msp_hw_status, }; /** @@ -1049,7 +1046,6 @@ static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data, if (transmit) { if (!msp->tx_pipeid) return -EINVAL; - desc = msp->tx_pipeid->device-> device_prep_slave_sg(msp->tx_pipeid, &sg, 1, DMA_TO_DEVICE, @@ -1102,50 +1098,49 @@ static int msp_single_dma_rx(struct msp *msp, dma_addr_t data, size_t bytes) } static void msp_cyclic_dma_start(struct msp *msp, - struct scatterlist *sg, - int sg_len, + dma_addr_t buf_addr, + size_t buf_len, + size_t period_len, enum dma_data_direction direction) { -#if 0 - struct stedma40_cyclic_desc *cdesc; int ret; + struct dma_async_tx_descriptor *cdesc; struct dma_chan *pipeid = (direction == DMA_TO_DEVICE) ? msp->tx_pipeid : msp->rx_pipeid; - cdesc = stedma40_cyclic_prep_sg(pipeid, - sg, - sg_len, - direction, - DMA_PREP_INTERRUPT); + pr_debug("%s: buf_addr = %p\n", __func__, (void *) buf_addr); + pr_debug("%s: buf_len = %d\n", __func__, buf_len); + pr_debug("%s: perios_len = %d\n", __func__, period_len); + + /* setup the cyclic description */ + cdesc = pipeid->device->device_prep_dma_cyclic(pipeid, + buf_addr, /* reuse the sq list for the moment */ + buf_len, + period_len, + direction); + if (IS_ERR(cdesc)) { - pr_err("%s: Error: stedma40_cyclic_prep_sg failed (%ld)!\n", + pr_err("%s: Error: device_prep_dma_cyclic failed (%ld)!\n", __func__, PTR_ERR(cdesc)); return; } - cdesc->period_callback = (direction == DMA_TO_DEVICE) ? + cdesc->callback = (direction == DMA_TO_DEVICE) ? msp->xfer_data.tx_handler : msp->xfer_data.rx_handler; - cdesc->period_callback_param = (direction == DMA_TO_DEVICE) ? + cdesc->callback_param = (direction == DMA_TO_DEVICE) ? msp->xfer_data.tx_callback_data : msp->xfer_data.rx_callback_data; - ret = stedma40_cyclic_start(pipeid); - if (ret) { - pr_err("%s: stedma40_cyclic_start failed (%d)!\n", __func__, ret); - goto free; - } + /* submit to the dma */ + ret = dmaengine_submit(cdesc); - msp->infinite = true; + /* start the dma */ + dma_async_issue_pending(pipeid); return; - -free: - stedma40_cyclic_free(pipeid); -#endif - return; } /* Legacy function. Used by HATS driver. */ @@ -1205,7 +1200,7 @@ free_tx: stedma40_cyclic_free(msp->tx_pipeid); free_rx: stedma40_cyclic_free(msp->rx_pipeid); -#endif +#endif return; } @@ -1260,16 +1255,18 @@ static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg) case I2S_TRANSFER_MODE_CYCLIC_DMA: if (msg->i2s_direction == I2S_DIRECTION_TX) { msp_cyclic_dma_start(msp, - msg->sg, - msg->sg_len, + msg->buf_addr, + msg->buf_len, + msg->period_len, DMA_TO_DEVICE); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)), msp->registers + MSP_GCR); } else { msp_cyclic_dma_start(msp, - msg->sg, - msg->sg_len, + msg->buf_addr, + msg->buf_len, + msg->period_len, DMA_FROM_DEVICE); stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)), @@ -1653,37 +1650,20 @@ static int stm_msp_disable(struct msp *msp, int direction, i2s_flag flag) return 0; } if (msp->work_mode == MSP_DMA_MODE) { -#if 0 if (flag == DISABLE_ALL || flag == DISABLE_TRANSMIT) { if (msp->tx_pipeid != NULL) { - if (msp->infinite) { - stedma40_cyclic_stop(msp->tx_pipeid); - stedma40_cyclic_free(msp->tx_pipeid); - } - msp->tx_pipeid->device-> - device_control(msp->tx_pipeid, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(msp->tx_pipeid); dma_release_channel(msp->tx_pipeid); msp->tx_pipeid = NULL; } } if ((flag == DISABLE_ALL || flag == DISABLE_RECEIVE)) { if (msp->rx_pipeid != NULL) { - if (msp->infinite) { - stedma40_cyclic_stop(msp->rx_pipeid); - stedma40_cyclic_free(msp->rx_pipeid); - } - - msp->rx_pipeid->device-> - device_control(msp->rx_pipeid, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(msp->rx_pipeid); dma_release_channel(msp->rx_pipeid); msp->rx_pipeid = NULL; } } - - msp->infinite = false; -#endif } if (flag == DISABLE_TRANSMIT) msp_disable_transmit(msp); @@ -1823,18 +1803,6 @@ static int stm_msp_hw_status(struct i2s_controller *i2s_cont) return status; } -static dma_addr_t stm_msp_get_pointer(struct i2s_controller *i2s_cont, - enum i2s_direction_t i2s_direction) -{ -#if 0 - struct msp *msp = (struct msp *)i2s_cont->data; - return (i2s_direction == I2S_DIRECTION_TX) ? - stedma40_get_src_addr(msp->tx_pipeid) : - stedma40_get_dst_addr(msp->rx_pipeid); -#endif - return 0; -} - /*Platform driver's functions */ /** * msp_probe - Probe function diff --git a/include/linux/i2s/i2s.h b/include/linux/i2s/i2s.h index 94e461656a4..79df549d6bd 100644 --- a/include/linux/i2s/i2s.h +++ b/include/linux/i2s/i2s.h @@ -159,9 +159,11 @@ struct i2s_message { int dma_flag; int tx_offset; int rx_offset; + /* cyclic dma */ bool cyclic_dma; - struct scatterlist *sg; - int sg_len; + dma_addr_t buf_addr; + size_t buf_len; + size_t period_len; }; typedef enum { diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 354a0edb8bf..78e78e1fc04 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -97,17 +97,15 @@ dma_addr_t ux500_msp_dai_i2s_get_pointer(int dai_idx, int stream_id) } int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, - int sg_len, - int sg_size, + int period_cnt, + size_t period_len, int dai_idx, int stream_id) { struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx]; struct i2s_message message; struct i2s_device *i2s_dev; - int i; int ret = 0; - struct scatterlist *sg; bool playback_req_valid = (drvdata->playback_active && stream_id == SNDRV_PCM_STREAM_PLAYBACK); @@ -115,11 +113,11 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, (drvdata->capture_active && stream_id == SNDRV_PCM_STREAM_CAPTURE); - pr_debug("%s: Enter (MSP Index: %u, SG-length: %u, SG-size: %u).\n", + pr_debug("%s: Enter (MSP Index: %u, period-cnt: %u, period-len: %u).\n", __func__, dai_idx, - sg_len, - sg_size); + period_cnt, + period_len); if (!playback_req_valid && !capture_req_valid) { pr_err("%s: The I2S controller is not available." @@ -131,19 +129,13 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, i2s_dev = drvdata->i2s; - sg = kzalloc(sizeof(struct scatterlist) * sg_len, GFP_ATOMIC); - sg_init_table(sg, sg_len); - for (i = 0; i < sg_len; i++) { - sg_dma_address(&sg[i]) = dma_addr + i * sg_size; - sg_dma_len(&sg[i]) = sg_size; - } - message.i2s_transfer_mode = I2S_TRANSFER_MODE_CYCLIC_DMA; message.i2s_direction = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? I2S_DIRECTION_TX : I2S_DIRECTION_RX; - message.sg = sg; - message.sg_len = sg_len; + message.buf_addr = dma_addr; + message.buf_len = period_cnt * period_len; + message.period_len = period_len; ret = i2s_transfer(i2s_dev->controller, &message); if (ret < 0) { @@ -152,8 +144,6 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, dai_idx); } - kfree(sg); - return ret; } diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h index 36aaa386c6a..64a23506bca 100644 --- a/sound/soc/ux500/ux500_msp_dai.h +++ b/sound/soc/ux500/ux500_msp_dai.h @@ -67,8 +67,8 @@ extern struct snd_soc_dai ux500_msp_dai[UX500_NBR_OF_DAI]; bool ux500_msp_dai_i2s_get_underrun_status(int dai_idx); dma_addr_t ux500_msp_dai_i2s_get_pointer(int dai_idx, int stream_id); int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr, - int sg_len, - int sg_size, + int perod_cnt, + size_t period_len, int dai_idx, int stream_id); int ux500_msp_dai_i2s_send_data(void *data, size_t bytes, int dai_idx); diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 0556706776d..1372e8d6e3f 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -111,8 +111,17 @@ void ux500_pcm_dma_eot_handler(void *data) runtime = substream->runtime; private = substream->runtime->private_data; - if (ux500_msp_dai_i2s_get_underrun_status(private->msp_id)) + if (ux500_msp_dai_i2s_get_underrun_status(private->msp_id)) { private->no_of_underruns++; + pr_debug("%s: Nr of underruns (%d)\n", __func__, + private->no_of_underruns); + } + + /* calc the offset in the circular buffer */ + private->offset += frames_to_bytes(runtime, + runtime->period_size); + private->offset %= frames_to_bytes(runtime, + runtime->period_size) * runtime->periods; snd_pcm_period_elapsed(substream); } @@ -250,12 +259,12 @@ static int ux500_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: private->no_of_underruns = 0; + private->offset = 0; ret = ux500_msp_dai_i2s_configure_sg(runtime->dma_addr, - runtime->periods, - frames_to_bytes(runtime, - runtime->period_size), - private->msp_id, - stream_id); + runtime->periods, + frames_to_bytes(runtime, runtime->period_size), + private->msp_id, + stream_id); if (ret) { pr_err("%s: Failed to configure sg-list!\n", __func__); return -EINVAL; @@ -284,18 +293,12 @@ static int ux500_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static snd_pcm_uframes_t ux500_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct ux500_pcm_private *private = substream->runtime->private_data; - int stream_id = substream->pstr->stream; - unsigned int offset; - dma_addr_t addr; - - pr_debug("%s: Enter\n", __func__); + struct ux500_pcm_private *private = runtime->private_data; - addr = ux500_msp_dai_i2s_get_pointer(private->msp_id, stream_id); - offset = bytes_to_frames(runtime, addr - runtime->dma_addr); - pr_debug("%s: Offset = %u\n", __func__, offset); + pr_debug("%s: dma_offset %d frame %ld\n", __func__, private->offset, + bytes_to_frames(substream->runtime, private->offset)); - return offset; + return bytes_to_frames(substream->runtime, private->offset); } static int ux500_pcm_mmap(struct snd_pcm_substream *substream, diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h index de2df94fd97..50f46615275 100644 --- a/sound/soc/ux500/ux500_pcm.h +++ b/sound/soc/ux500/ux500_pcm.h @@ -36,6 +36,7 @@ struct ux500_pcm_private { int msp_id; int stream_id; unsigned int no_of_underruns; + unsigned int offset; }; void ux500_pcm_dma_eot_handler(void *data); |