diff options
Diffstat (limited to 'drivers/dma/s3c24xx-dma.c')
-rw-r--r-- | drivers/dma/s3c24xx-dma.c | 73 |
1 files changed, 36 insertions, 37 deletions
diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index 6941a77521c3..2f91da3db836 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c | |||
@@ -384,20 +384,30 @@ static u32 s3c24xx_dma_getbytes_chan(struct s3c24xx_dma_chan *s3cchan) | |||
384 | return tc * txd->width; | 384 | return tc * txd->width; |
385 | } | 385 | } |
386 | 386 | ||
387 | static int s3c24xx_dma_set_runtime_config(struct s3c24xx_dma_chan *s3cchan, | 387 | static int s3c24xx_dma_set_runtime_config(struct dma_chan *chan, |
388 | struct dma_slave_config *config) | 388 | struct dma_slave_config *config) |
389 | { | 389 | { |
390 | if (!s3cchan->slave) | 390 | struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); |
391 | return -EINVAL; | 391 | unsigned long flags; |
392 | int ret = 0; | ||
392 | 393 | ||
393 | /* Reject definitely invalid configurations */ | 394 | /* Reject definitely invalid configurations */ |
394 | if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || | 395 | if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || |
395 | config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) | 396 | config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) |
396 | return -EINVAL; | 397 | return -EINVAL; |
397 | 398 | ||
399 | spin_lock_irqsave(&s3cchan->vc.lock, flags); | ||
400 | |||
401 | if (!s3cchan->slave) { | ||
402 | ret = -EINVAL; | ||
403 | goto out; | ||
404 | } | ||
405 | |||
398 | s3cchan->cfg = *config; | 406 | s3cchan->cfg = *config; |
399 | 407 | ||
400 | return 0; | 408 | out: |
409 | spin_unlock_irqrestore(&s3cchan->vc.lock, flags); | ||
410 | return ret; | ||
401 | } | 411 | } |
402 | 412 | ||
403 | /* | 413 | /* |
@@ -703,8 +713,7 @@ static irqreturn_t s3c24xx_dma_irq(int irq, void *data) | |||
703 | * The DMA ENGINE API | 713 | * The DMA ENGINE API |
704 | */ | 714 | */ |
705 | 715 | ||
706 | static int s3c24xx_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 716 | static int s3c24xx_dma_terminate_all(struct dma_chan *chan) |
707 | unsigned long arg) | ||
708 | { | 717 | { |
709 | struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); | 718 | struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); |
710 | struct s3c24xx_dma_engine *s3cdma = s3cchan->host; | 719 | struct s3c24xx_dma_engine *s3cdma = s3cchan->host; |
@@ -713,40 +722,28 @@ static int s3c24xx_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | |||
713 | 722 | ||
714 | spin_lock_irqsave(&s3cchan->vc.lock, flags); | 723 | spin_lock_irqsave(&s3cchan->vc.lock, flags); |
715 | 724 | ||
716 | switch (cmd) { | 725 | if (!s3cchan->phy && !s3cchan->at) { |
717 | case DMA_SLAVE_CONFIG: | 726 | dev_err(&s3cdma->pdev->dev, "trying to terminate already stopped channel %d\n", |
718 | ret = s3c24xx_dma_set_runtime_config(s3cchan, | 727 | s3cchan->id); |
719 | (struct dma_slave_config *)arg); | 728 | ret = -EINVAL; |
720 | break; | 729 | goto unlock; |
721 | case DMA_TERMINATE_ALL: | 730 | } |
722 | if (!s3cchan->phy && !s3cchan->at) { | ||
723 | dev_err(&s3cdma->pdev->dev, "trying to terminate already stopped channel %d\n", | ||
724 | s3cchan->id); | ||
725 | ret = -EINVAL; | ||
726 | break; | ||
727 | } | ||
728 | 731 | ||
729 | s3cchan->state = S3C24XX_DMA_CHAN_IDLE; | 732 | s3cchan->state = S3C24XX_DMA_CHAN_IDLE; |
730 | 733 | ||
731 | /* Mark physical channel as free */ | 734 | /* Mark physical channel as free */ |
732 | if (s3cchan->phy) | 735 | if (s3cchan->phy) |
733 | s3c24xx_dma_phy_free(s3cchan); | 736 | s3c24xx_dma_phy_free(s3cchan); |
734 | 737 | ||
735 | /* Dequeue current job */ | 738 | /* Dequeue current job */ |
736 | if (s3cchan->at) { | 739 | if (s3cchan->at) { |
737 | s3c24xx_dma_desc_free(&s3cchan->at->vd); | 740 | s3c24xx_dma_desc_free(&s3cchan->at->vd); |
738 | s3cchan->at = NULL; | 741 | s3cchan->at = NULL; |
739 | } | ||
740 | |||
741 | /* Dequeue jobs not yet fired as well */ | ||
742 | s3c24xx_dma_free_txd_list(s3cdma, s3cchan); | ||
743 | break; | ||
744 | default: | ||
745 | /* Unknown command */ | ||
746 | ret = -ENXIO; | ||
747 | break; | ||
748 | } | 742 | } |
749 | 743 | ||
744 | /* Dequeue jobs not yet fired as well */ | ||
745 | s3c24xx_dma_free_txd_list(s3cdma, s3cchan); | ||
746 | unlock: | ||
750 | spin_unlock_irqrestore(&s3cchan->vc.lock, flags); | 747 | spin_unlock_irqrestore(&s3cchan->vc.lock, flags); |
751 | 748 | ||
752 | return ret; | 749 | return ret; |
@@ -1300,7 +1297,8 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) | |||
1300 | s3cdma->memcpy.device_prep_dma_memcpy = s3c24xx_dma_prep_memcpy; | 1297 | s3cdma->memcpy.device_prep_dma_memcpy = s3c24xx_dma_prep_memcpy; |
1301 | s3cdma->memcpy.device_tx_status = s3c24xx_dma_tx_status; | 1298 | s3cdma->memcpy.device_tx_status = s3c24xx_dma_tx_status; |
1302 | s3cdma->memcpy.device_issue_pending = s3c24xx_dma_issue_pending; | 1299 | s3cdma->memcpy.device_issue_pending = s3c24xx_dma_issue_pending; |
1303 | s3cdma->memcpy.device_control = s3c24xx_dma_control; | 1300 | s3cdma->memcpy.device_config = s3c24xx_dma_set_runtime_config; |
1301 | s3cdma->memcpy.device_terminate_all = s3c24xx_dma_terminate_all; | ||
1304 | 1302 | ||
1305 | /* Initialize slave engine for SoC internal dedicated peripherals */ | 1303 | /* Initialize slave engine for SoC internal dedicated peripherals */ |
1306 | dma_cap_set(DMA_SLAVE, s3cdma->slave.cap_mask); | 1304 | dma_cap_set(DMA_SLAVE, s3cdma->slave.cap_mask); |
@@ -1315,7 +1313,8 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) | |||
1315 | s3cdma->slave.device_issue_pending = s3c24xx_dma_issue_pending; | 1313 | s3cdma->slave.device_issue_pending = s3c24xx_dma_issue_pending; |
1316 | s3cdma->slave.device_prep_slave_sg = s3c24xx_dma_prep_slave_sg; | 1314 | s3cdma->slave.device_prep_slave_sg = s3c24xx_dma_prep_slave_sg; |
1317 | s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic; | 1315 | s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic; |
1318 | s3cdma->slave.device_control = s3c24xx_dma_control; | 1316 | s3cdma->slave.device_config = s3c24xx_dma_set_runtime_config; |
1317 | s3cdma->slave.device_terminate_all = s3c24xx_dma_terminate_all; | ||
1319 | 1318 | ||
1320 | /* Register as many memcpy channels as there are physical channels */ | 1319 | /* Register as many memcpy channels as there are physical channels */ |
1321 | ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->memcpy, | 1320 | ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->memcpy, |