Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma
[deliverable/linux.git] / sound / soc / sh / fsi.c
index 7cee22515d9de55c505eae1dd460107b1eacee3a..0540408a9fa9ab706c28e7ef6ed60a329bec027c 100644 (file)
@@ -247,7 +247,7 @@ struct fsi_priv {
 struct fsi_stream_handler {
        int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
-       int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io);
+       int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
        int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
        void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
@@ -571,16 +571,16 @@ static int fsi_stream_transfer(struct fsi_stream *io)
 #define fsi_stream_stop(fsi, io)\
        fsi_stream_handler_call(io, start_stop, fsi, io, 0)
 
-static int fsi_stream_probe(struct fsi_priv *fsi)
+static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
 {
        struct fsi_stream *io;
        int ret1, ret2;
 
        io = &fsi->playback;
-       ret1 = fsi_stream_handler_call(io, probe, fsi, io);
+       ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
 
        io = &fsi->capture;
-       ret2 = fsi_stream_handler_call(io, probe, fsi, io);
+       ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
 
        if (ret1 < 0)
                return ret1;
@@ -1052,6 +1052,13 @@ static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io)
        return 0;
 }
 
+static dma_addr_t fsi_dma_get_area(struct fsi_stream *io)
+{
+       struct snd_pcm_runtime *runtime = io->substream->runtime;
+
+       return io->dma + samples_to_bytes(runtime, io->buff_sample_pos);
+}
+
 static void fsi_dma_complete(void *data)
 {
        struct fsi_stream *io = (struct fsi_stream *)data;
@@ -1061,7 +1068,7 @@ static void fsi_dma_complete(void *data)
        enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
                DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
-       dma_sync_single_for_cpu(dai->dev, io->dma,
+       dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io),
                        samples_to_bytes(runtime, io->period_samples), dir);
 
        io->buff_sample_pos += io->period_samples;
@@ -1078,24 +1085,14 @@ static void fsi_dma_complete(void *data)
        snd_pcm_period_elapsed(io->substream);
 }
 
-static dma_addr_t fsi_dma_get_area(struct fsi_stream *io)
-{
-       struct snd_pcm_runtime *runtime = io->substream->runtime;
-
-       return io->dma + samples_to_bytes(runtime, io->buff_sample_pos);
-}
-
 static void fsi_dma_do_tasklet(unsigned long data)
 {
        struct fsi_stream *io = (struct fsi_stream *)data;
        struct fsi_priv *fsi = fsi_stream_to_priv(io);
-       struct dma_chan *chan;
        struct snd_soc_dai *dai;
        struct dma_async_tx_descriptor *desc;
-       struct scatterlist sg;
        struct snd_pcm_runtime *runtime;
        enum dma_data_direction dir;
-       dma_cookie_t cookie;
        int is_play = fsi_stream_is_play(fsi, io);
        int len;
        dma_addr_t buf;
@@ -1104,22 +1101,15 @@ static void fsi_dma_do_tasklet(unsigned long data)
                return;
 
        dai     = fsi_get_dai(io->substream);
-       chan    = io->chan;
        runtime = io->substream->runtime;
        dir     = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        len     = samples_to_bytes(runtime, io->period_samples);
        buf     = fsi_dma_get_area(io);
 
-       dma_sync_single_for_device(dai->dev, io->dma, len, dir);
+       dma_sync_single_for_device(dai->dev, buf, len, dir);
 
-       sg_init_table(&sg, 1);
-       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
-                   len , offset_in_page(buf));
-       sg_dma_address(&sg) = buf;
-       sg_dma_len(&sg) = len;
-
-       desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
-                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       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;
@@ -1128,13 +1118,12 @@ static void fsi_dma_do_tasklet(unsigned long data)
        desc->callback          = fsi_dma_complete;
        desc->callback_param    = io;
 
-       cookie = desc->tx_submit(desc);
-       if (cookie < 0) {
+       if (dmaengine_submit(desc) < 0) {
                dev_err(dai->dev, "tx_submit() fail\n");
                return;
        }
 
-       dma_async_issue_pending(chan);
+       dma_async_issue_pending(io->chan);
 
        /*
         * FIXME
@@ -1172,12 +1161,19 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
 static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                                 int start)
 {
+       struct fsi_master *master = fsi_get_master(fsi);
+       u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
        u32 enable = start ? DMA_ON : 0;
 
        fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
+
+       dmaengine_terminate_all(io->chan);
+
+       if (fsi_is_clk_master(fsi))
+               fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
-static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
+static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
 {
        dma_cap_mask_t mask;
 
@@ -1185,8 +1181,19 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
        dma_cap_set(DMA_SLAVE, mask);
 
        io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
-       if (!io->chan)
-               return -EIO;
+       if (!io->chan) {
+
+               /* switch to PIO handler */
+               if (fsi_stream_is_play(fsi, io))
+                       fsi->playback.handler   = &fsi_pio_push_handler;
+               else
+                       fsi->capture.handler    = &fsi_pio_pop_handler;
+
+               dev_info(dev, "switch handler (dma => pio)\n");
+
+               /* probe again */
+               return fsi_stream_probe(fsi, dev);
+       }
 
        tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
 
@@ -1624,8 +1631,8 @@ static void fsi_handler_init(struct fsi_priv *fsi)
        fsi->capture.priv       = fsi;
 
        if (fsi->info->tx_id) {
-               fsi->playback.slave.slave_id    = fsi->info->tx_id;
-               fsi->playback.handler           = &fsi_dma_push_handler;
+               fsi->playback.slave.shdma_slave.slave_id = fsi->info->tx_id;
+               fsi->playback.handler = &fsi_dma_push_handler;
        }
 }
 
@@ -1676,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev)
        master->fsia.master     = master;
        master->fsia.info       = &info->port_a;
        fsi_handler_init(&master->fsia);
-       ret = fsi_stream_probe(&master->fsia);
+       ret = fsi_stream_probe(&master->fsia, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIA stream probe failed\n");
                goto exit_iounmap;
@@ -1687,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev)
        master->fsib.master     = master;
        master->fsib.info       = &info->port_b;
        fsi_handler_init(&master->fsib);
-       ret = fsi_stream_probe(&master->fsib);
+       ret = fsi_stream_probe(&master->fsib, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIB stream probe failed\n");
                goto exit_fsia;
This page took 0.032614 seconds and 5 git commands to generate.