* these are for DMAEngine
*/
struct dma_chan *chan;
- struct work_struct work;
int dma_id;
- int loop_cnt;
- int additional_pos;
};
struct fsi_clk {
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
- io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */
- io->additional_pos = 0;
-
return 0;
}
-static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional)
-{
- struct snd_pcm_runtime *runtime = io->substream->runtime;
- int period = io->period_pos + additional;
-
- if (period >= runtime->periods)
- period = 0;
-
- return runtime->dma_addr +
- samples_to_bytes(runtime, period * io->period_samples);
-}
-
static void fsi_dma_complete(void *data)
{
struct fsi_stream *io = (struct fsi_stream *)data;
fsi_pointer_update(io, io->period_samples);
fsi_count_fifo_err(fsi);
- fsi_stream_transfer(io);
}
-static void fsi_dma_do_work(struct work_struct *work)
+static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
{
- struct fsi_stream *io = container_of(work, struct fsi_stream, work);
- struct fsi_priv *fsi = fsi_stream_to_priv(io);
- struct snd_soc_dai *dai;
+ struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+ struct snd_pcm_substream *substream = io->substream;
struct dma_async_tx_descriptor *desc;
- struct snd_pcm_runtime *runtime;
- enum dma_data_direction dir;
int is_play = fsi_stream_is_play(fsi, io);
- int len, i;
- dma_addr_t buf;
-
- if (!fsi_stream_is_working(fsi, io))
- return;
-
- dai = fsi_get_dai(io->substream);
- runtime = io->substream->runtime;
- dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- len = samples_to_bytes(runtime, io->period_samples);
-
- for (i = 0; i < io->loop_cnt; i++) {
- buf = fsi_dma_get_area(io, io->additional_pos);
-
- desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc) {
- dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
- return;
- }
-
- desc->callback = fsi_dma_complete;
- desc->callback_param = io;
-
- if (dmaengine_submit(desc) < 0) {
- dev_err(dai->dev, "tx_submit() fail\n");
- return;
- }
+ enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+ int ret = -EIO;
+
+ desc = dmaengine_prep_dma_cyclic(io->chan,
+ substream->runtime->dma_addr,
+ snd_pcm_lib_buffer_bytes(substream),
+ snd_pcm_lib_period_bytes(substream),
+ dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n");
+ goto fsi_dma_transfer_err;
+ }
- dma_async_issue_pending(io->chan);
+ desc->callback = fsi_dma_complete;
+ desc->callback_param = io;
- io->additional_pos = 1;
+ if (dmaengine_submit(desc) < 0) {
+ dev_err(dai->dev, "tx_submit() fail\n");
+ goto fsi_dma_transfer_err;
}
- io->loop_cnt = 1;
+ dma_async_issue_pending(io->chan);
/*
* FIXME
fsi_reg_write(fsi, DIFF_ST, 0);
}
}
-}
-static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
-{
- schedule_work(&io->work);
+ ret = 0;
- return 0;
+fsi_dma_transfer_err:
+ return ret;
}
static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
return fsi_stream_probe(fsi, dev);
}
- INIT_WORK(&io->work, fsi_dma_do_work);
-
return 0;
}
static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
{
- cancel_work_sync(&io->work);
-
fsi_stream_stop(fsi, io);
if (io->chan)
if (!ret)
ret = fsi_hw_startup(fsi, io, dai->dev);
if (!ret)
- ret = fsi_stream_transfer(io);
+ ret = fsi_stream_start(fsi, io);
if (!ret)
- fsi_stream_start(fsi, io);
+ ret = fsi_stream_transfer(io);
break;
case SNDRV_PCM_TRIGGER_STOP:
if (!ret)