aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/mmp_tdma.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index 70c2fa9963cd..b6f4e1fc9c78 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -110,7 +110,7 @@ struct mmp_tdma_chan {
110 struct tasklet_struct tasklet; 110 struct tasklet_struct tasklet;
111 111
112 struct mmp_tdma_desc *desc_arr; 112 struct mmp_tdma_desc *desc_arr;
113 phys_addr_t desc_arr_phys; 113 dma_addr_t desc_arr_phys;
114 int desc_num; 114 int desc_num;
115 enum dma_transfer_direction dir; 115 enum dma_transfer_direction dir;
116 dma_addr_t dev_addr; 116 dma_addr_t dev_addr;
@@ -166,9 +166,12 @@ static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
166static int mmp_tdma_disable_chan(struct dma_chan *chan) 166static int mmp_tdma_disable_chan(struct dma_chan *chan)
167{ 167{
168 struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan); 168 struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
169 u32 tdcr;
169 170
170 writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN, 171 tdcr = readl(tdmac->reg_base + TDCR);
171 tdmac->reg_base + TDCR); 172 tdcr |= TDCR_ABR;
173 tdcr &= ~TDCR_CHANEN;
174 writel(tdcr, tdmac->reg_base + TDCR);
172 175
173 tdmac->status = DMA_COMPLETE; 176 tdmac->status = DMA_COMPLETE;
174 177
@@ -296,12 +299,27 @@ static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
296 return -EAGAIN; 299 return -EAGAIN;
297} 300}
298 301
302static size_t mmp_tdma_get_pos(struct mmp_tdma_chan *tdmac)
303{
304 size_t reg;
305
306 if (tdmac->idx == 0) {
307 reg = __raw_readl(tdmac->reg_base + TDSAR);
308 reg -= tdmac->desc_arr[0].src_addr;
309 } else if (tdmac->idx == 1) {
310 reg = __raw_readl(tdmac->reg_base + TDDAR);
311 reg -= tdmac->desc_arr[0].dst_addr;
312 } else
313 return -EINVAL;
314
315 return reg;
316}
317
299static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id) 318static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
300{ 319{
301 struct mmp_tdma_chan *tdmac = dev_id; 320 struct mmp_tdma_chan *tdmac = dev_id;
302 321
303 if (mmp_tdma_clear_chan_irq(tdmac) == 0) { 322 if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
304 tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
305 tasklet_schedule(&tdmac->tasklet); 323 tasklet_schedule(&tdmac->tasklet);
306 return IRQ_HANDLED; 324 return IRQ_HANDLED;
307 } else 325 } else
@@ -343,7 +361,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
343 int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc); 361 int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
344 362
345 gpool = tdmac->pool; 363 gpool = tdmac->pool;
346 if (tdmac->desc_arr) 364 if (gpool && tdmac->desc_arr)
347 gen_pool_free(gpool, (unsigned long)tdmac->desc_arr, 365 gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
348 size); 366 size);
349 tdmac->desc_arr = NULL; 367 tdmac->desc_arr = NULL;
@@ -499,6 +517,7 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
499{ 517{
500 struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan); 518 struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
501 519
520 tdmac->pos = mmp_tdma_get_pos(tdmac);
502 dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 521 dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
503 tdmac->buf_len - tdmac->pos); 522 tdmac->buf_len - tdmac->pos);
504 523
@@ -610,7 +629,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
610 int i, ret; 629 int i, ret;
611 int irq = 0, irq_num = 0; 630 int irq = 0, irq_num = 0;
612 int chan_num = TDMA_CHANNEL_NUM; 631 int chan_num = TDMA_CHANNEL_NUM;
613 struct gen_pool *pool; 632 struct gen_pool *pool = NULL;
614 633
615 of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev); 634 of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
616 if (of_id) 635 if (of_id)