diff options
Diffstat (limited to 'drivers/dma/sa11x0-dma.c')
-rw-r--r-- | drivers/dma/sa11x0-dma.c | 157 |
1 files changed, 82 insertions, 75 deletions
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index 96bb62c39c4..5adf5407a8c 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -669,8 +669,10 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic( return vchan_tx_prep(&c->vc, &txd->vd, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } -static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg) +static int sa11x0_dma_device_config(struct dma_chan *chan, + struct dma_slave_config *cfg) { + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW); dma_addr_t addr; enum dma_slave_buswidth width; @@ -704,99 +706,101 @@ static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_c return 0; } -static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, - unsigned long arg) +static int sa11x0_dma_device_pause(struct dma_chan *chan) { struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); struct sa11x0_dma_phy *p; LIST_HEAD(head); unsigned long flags; - int ret; - switch (cmd) { - case DMA_SLAVE_CONFIG: - return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg); - - case DMA_TERMINATE_ALL: - dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc); - /* Clear the tx descriptor lists */ - spin_lock_irqsave(&c->vc.lock, flags); - vchan_get_all_descriptors(&c->vc, &head); + dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc); + spin_lock_irqsave(&c->vc.lock, flags); + if (c->status == DMA_IN_PROGRESS) { + c->status = DMA_PAUSED; p = c->phy; if (p) { - dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num); - /* vchan is assigned to a pchan - stop the channel */ - writel(DCSR_RUN | DCSR_IE | - DCSR_STRTA | DCSR_DONEA | - DCSR_STRTB | DCSR_DONEB, - p->base + DMA_DCSR_C); - - if (p->txd_load) { - if (p->txd_load != p->txd_done) - list_add_tail(&p->txd_load->vd.node, &head); - p->txd_load = NULL; - } - if (p->txd_done) { - list_add_tail(&p->txd_done->vd.node, &head); - p->txd_done = NULL; - } - c->phy = NULL; + writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C); + } else { spin_lock(&d->lock); - p->vchan = NULL; + list_del_init(&c->node); spin_unlock(&d->lock); - tasklet_schedule(&d->task); } - spin_unlock_irqrestore(&c->vc.lock, flags); - vchan_dma_desc_free_list(&c->vc, &head); - ret = 0; - break; + } + spin_unlock_irqrestore(&c->vc.lock, flags); - case DMA_PAUSE: - dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc); - spin_lock_irqsave(&c->vc.lock, flags); - if (c->status == DMA_IN_PROGRESS) { - c->status = DMA_PAUSED; + return 0; +} - p = c->phy; - if (p) { - writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C); - } else { - spin_lock(&d->lock); - list_del_init(&c->node); - spin_unlock(&d->lock); - } - } - spin_unlock_irqrestore(&c->vc.lock, flags); - ret = 0; - break; +static int sa11x0_dma_device_resume(struct dma_chan *chan) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); + struct sa11x0_dma_phy *p; + LIST_HEAD(head); + unsigned long flags; - case DMA_RESUME: - dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc); - spin_lock_irqsave(&c->vc.lock, flags); - if (c->status == DMA_PAUSED) { - c->status = DMA_IN_PROGRESS; - - p = c->phy; - if (p) { - writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S); - } else if (!list_empty(&c->vc.desc_issued)) { - spin_lock(&d->lock); - list_add_tail(&c->node, &d->chan_pending); - spin_unlock(&d->lock); - } + dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc); + spin_lock_irqsave(&c->vc.lock, flags); + if (c->status == DMA_PAUSED) { + c->status = DMA_IN_PROGRESS; + + p = c->phy; + if (p) { + writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S); + } else if (!list_empty(&c->vc.desc_issued)) { + spin_lock(&d->lock); + list_add_tail(&c->node, &d->chan_pending); + spin_unlock(&d->lock); } - spin_unlock_irqrestore(&c->vc.lock, flags); - ret = 0; - break; + } + spin_unlock_irqrestore(&c->vc.lock, flags); - default: - ret = -ENXIO; - break; + return 0; +} + +static int sa11x0_dma_device_terminate_all(struct dma_chan *chan) +{ + struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); + struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); + struct sa11x0_dma_phy *p; + LIST_HEAD(head); + unsigned long flags; + + dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc); + /* Clear the tx descriptor lists */ + spin_lock_irqsave(&c->vc.lock, flags); + vchan_get_all_descriptors(&c->vc, &head); + + p = c->phy; + if (p) { + dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num); + /* vchan is assigned to a pchan - stop the channel */ + writel(DCSR_RUN | DCSR_IE | + DCSR_STRTA | DCSR_DONEA | + DCSR_STRTB | DCSR_DONEB, + p->base + DMA_DCSR_C); + + if (p->txd_load) { + if (p->txd_load != p->txd_done) + list_add_tail(&p->txd_load->vd.node, &head); + p->txd_load = NULL; + } + if (p->txd_done) { + list_add_tail(&p->txd_done->vd.node, &head); + p->txd_done = NULL; + } + c->phy = NULL; + spin_lock(&d->lock); + p->vchan = NULL; + spin_unlock(&d->lock); + tasklet_schedule(&d->task); } + spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_dma_desc_free_list(&c->vc, &head); - return ret; + return 0; } struct sa11x0_dma_channel_desc { @@ -833,7 +837,10 @@ static int sa11x0_dma_init_dmadev(struct dma_device *dmadev, dmadev->dev = dev; dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources; dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources; - dmadev->device_control = sa11x0_dma_control; + dmadev->device_config = sa11x0_dma_device_config; + dmadev->device_pause = sa11x0_dma_device_pause; + dmadev->device_resume = sa11x0_dma_device_resume; + dmadev->device_terminate_all = sa11x0_dma_device_terminate_all; dmadev->device_tx_status = sa11x0_dma_tx_status; dmadev->device_issue_pending = sa11x0_dma_issue_pending; |