summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Marklund <robert.marklund@stericsson.com>2011-05-25 17:37:45 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:51 +0200
commit036c288037f5248dbd685d1db3e2bf15775192b6 (patch)
tree621cf32be05aa9f46c475244936fcdf2c3d17f13
parent3a358a4bbcfdf03c328db82180a090a8522466db (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.c102
-rw-r--r--include/linux/i2s/i2s.h6
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c26
-rw-r--r--sound/soc/ux500/ux500_msp_dai.h4
-rw-r--r--sound/soc/ux500/ux500_pcm.c35
-rw-r--r--sound/soc/ux500/ux500_pcm.h1
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);