diff options
Diffstat (limited to 'drivers/dma/stm32-dma.c')
| -rw-r--r-- | drivers/dma/stm32-dma.c | 96 | 
1 files changed, 67 insertions, 29 deletions
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 5989b0893521..0ddbaa4b4f0b 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -15,6 +15,7 @@  #include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/init.h> +#include <linux/iopoll.h>  #include <linux/jiffies.h>  #include <linux/list.h>  #include <linux/module.h> @@ -207,7 +208,6 @@ struct stm32_dma_device {  	struct dma_device ddev;  	void __iomem *base;  	struct clk *clk; -	struct reset_control *rst;  	bool mem2mem;  	struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS];  }; @@ -422,29 +422,19 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags)  static int stm32_dma_disable_chan(struct stm32_dma_chan *chan)  {  	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -	unsigned long timeout = jiffies + msecs_to_jiffies(5000); -	u32 dma_scr, id; +	u32 dma_scr, id, reg;  	id = chan->id; -	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); +	reg = STM32_DMA_SCR(id); +	dma_scr = stm32_dma_read(dmadev, reg);  	if (dma_scr & STM32_DMA_SCR_EN) {  		dma_scr &= ~STM32_DMA_SCR_EN; -		stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr); - -		do { -			dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); -			dma_scr &= STM32_DMA_SCR_EN; -			if (!dma_scr) -				break; - -			if (time_after_eq(jiffies, timeout)) { -				dev_err(chan2dev(chan), "%s: timeout!\n", -					__func__); -				return -EBUSY; -			} -			cond_resched(); -		} while (1); +		stm32_dma_write(dmadev, reg, dma_scr); + +		return readl_relaxed_poll_timeout_atomic(dmadev->base + reg, +					dma_scr, !(dma_scr & STM32_DMA_SCR_EN), +					10, 1000000);  	}  	return 0; @@ -488,8 +478,10 @@ static int stm32_dma_terminate_all(struct dma_chan *c)  	spin_lock_irqsave(&chan->vchan.lock, flags); -	if (chan->busy) { -		stm32_dma_stop(chan); +	if (chan->desc) { +		vchan_terminate_vdesc(&chan->desc->vdesc); +		if (chan->busy) +			stm32_dma_stop(chan);  		chan->desc = NULL;  	} @@ -545,6 +537,8 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan)  		if (!vdesc)  			return; +		list_del(&vdesc->node); +  		chan->desc = to_stm32_dma_desc(vdesc);  		chan->next_sg = 0;  	} @@ -555,6 +549,7 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan)  	sg_req = &chan->desc->sg_req[chan->next_sg];  	reg = &sg_req->chan_reg; +	reg->dma_scr &= ~STM32_DMA_SCR_EN;  	stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr);  	stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar);  	stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar); @@ -622,7 +617,6 @@ static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan)  		} else {  			chan->busy = false;  			if (chan->next_sg == chan->desc->num_sgs) { -				list_del(&chan->desc->vdesc.node);  				vchan_cookie_complete(&chan->desc->vdesc);  				chan->desc = NULL;  			} @@ -1275,6 +1269,7 @@ static int stm32_dma_probe(struct platform_device *pdev)  	struct dma_device *dd;  	const struct of_device_id *match;  	struct resource *res; +	struct reset_control *rst;  	int i, ret;  	match = of_match_device(stm32_dma_of_match, &pdev->dev); @@ -1296,8 +1291,10 @@ static int stm32_dma_probe(struct platform_device *pdev)  	dmadev->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(dmadev->clk)) { -		dev_err(&pdev->dev, "Error: Missing controller clock\n"); -		return PTR_ERR(dmadev->clk); +		ret = PTR_ERR(dmadev->clk); +		if (ret != -EPROBE_DEFER) +			dev_err(&pdev->dev, "Can't get clock\n"); +		return ret;  	}  	ret = clk_prepare_enable(dmadev->clk); @@ -1309,13 +1306,19 @@ static int stm32_dma_probe(struct platform_device *pdev)  	dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node,  						"st,mem2mem"); -	dmadev->rst = devm_reset_control_get(&pdev->dev, NULL); -	if (!IS_ERR(dmadev->rst)) { -		reset_control_assert(dmadev->rst); +	rst = devm_reset_control_get(&pdev->dev, NULL); +	if (IS_ERR(rst)) { +		ret = PTR_ERR(rst); +		if (ret == -EPROBE_DEFER) +			goto clk_free; +	} else { +		reset_control_assert(rst);  		udelay(2); -		reset_control_deassert(dmadev->rst); +		reset_control_deassert(rst);  	} +	dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); +  	dma_cap_set(DMA_SLAVE, dd->cap_mask);  	dma_cap_set(DMA_PRIVATE, dd->cap_mask);  	dma_cap_set(DMA_CYCLIC, dd->cap_mask); @@ -1336,7 +1339,9 @@ static int stm32_dma_probe(struct platform_device *pdev)  		BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);  	dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);  	dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; +	dd->copy_align = DMAENGINE_ALIGN_32_BYTES;  	dd->max_burst = STM32_DMA_MAX_BURST; +	dd->descriptor_reuse = true;  	dd->dev = &pdev->dev;  	INIT_LIST_HEAD(&dd->channels); @@ -1427,7 +1432,39 @@ static int stm32_dma_runtime_resume(struct device *dev)  }  #endif +#ifdef CONFIG_PM_SLEEP +static int stm32_dma_suspend(struct device *dev) +{ +	struct stm32_dma_device *dmadev = dev_get_drvdata(dev); +	int id, ret, scr; + +	ret = pm_runtime_get_sync(dev); +	if (ret < 0) +		return ret; + +	for (id = 0; id < STM32_DMA_MAX_CHANNELS; id++) { +		scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); +		if (scr & STM32_DMA_SCR_EN) { +			dev_warn(dev, "Suspend is prevented by Chan %i\n", id); +			return -EBUSY; +		} +	} + +	pm_runtime_put_sync(dev); + +	pm_runtime_force_suspend(dev); + +	return 0; +} + +static int stm32_dma_resume(struct device *dev) +{ +	return pm_runtime_force_resume(dev); +} +#endif +  static const struct dev_pm_ops stm32_dma_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_suspend, stm32_dma_resume)  	SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend,  			   stm32_dma_runtime_resume, NULL)  }; @@ -1438,10 +1475,11 @@ static struct platform_driver stm32_dma_driver = {  		.of_match_table = stm32_dma_of_match,  		.pm = &stm32_dma_pm_ops,  	}, +	.probe = stm32_dma_probe,  };  static int __init stm32_dma_init(void)  { -	return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe); +	return platform_driver_register(&stm32_dma_driver);  }  subsys_initcall(stm32_dma_init);  |