summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/dma/fsl-edma-v3.txt11
-rw-r--r--drivers/dma/fsl-edma-v3.c58
2 files changed, 67 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
index a8d05427f954..8fe82ce63632 100644
--- a/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-edma-v3.txt
@@ -30,6 +30,8 @@ Required properties:
0: not dual fifo case, 1: dualfifo case.
See the SoC's reference manual for all the supported request sources.
- dma-channels : Number of channels supported by the controller
+- power-domains: Power domains for edma channel used.
+- power-domain-names: Power domains name for edma channel used.
Examples:
edma0: dma-controller@40018000 {
@@ -46,6 +48,12 @@ edma0: dma-controller@40018000 {
<GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "edma0-chan12-rx", "edma0-chan13-tx",
"edma0-chan14-rx", "edma0-chan15-tx";
+ power-domains = <&pd IMX_SC_R_DMA_0_CH12>,
+ <&pd IMX_SC_R_DMA_0_CH13>,
+ <&pd IMX_SC_R_DMA_0_CH14>,
+ <&pd IMX_SC_R_DMA_0_CH15>;
+ power-domain-names = "edma0-chan12", "edma0-chan13",
+ "edma0-chan14", "edma0-chan15";
status = "okay";
};
@@ -65,7 +73,8 @@ lpuart1: serial@5a070000 {
clock-names = "ipg";
assigned-clock-names = <&clk IMX8QM_UART1_CLK>;
assigned-clock-rates = <80000000>;
- power-domains = <&pd_dma_lpuart1>;
+ power-domains = <&pd IMX_SC_R_UART_1>,
+ power-domain-names = "uart";
dma-names = "tx","rx";
dmas = <&edma0 15 0 0>,
<&edma0 14 0 1>;
diff --git a/drivers/dma/fsl-edma-v3.c b/drivers/dma/fsl-edma-v3.c
index d74e4d46b907..bc6192bb234e 100644
--- a/drivers/dma/fsl-edma-v3.c
+++ b/drivers/dma/fsl-edma-v3.c
@@ -27,6 +27,8 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
#include "virt-dma.h"
@@ -164,6 +166,7 @@ struct fsl_edma3_chan {
u32 chn_real_count;
char txirq_name[32];
struct platform_device *pdev;
+ struct device *dev;
};
struct fsl_edma3_desc {
@@ -798,8 +801,10 @@ static int fsl_edma3_alloc_chan_resources(struct dma_chan *chan)
fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
sizeof(struct fsl_edma3_hw_tcd),
32, 0);
+ pm_runtime_get_sync(fsl_chan->dev);
/* clear meaningless pending irq anyway */
writel(1, fsl_chan->membase + EDMA_CH_INT);
+
ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
fsl_edma3_tx_handler, fsl_chan->edma3->irqflag,
fsl_chan->txirq_name, fsl_chan);
@@ -830,6 +835,7 @@ static void fsl_edma3_free_chan_resources(struct dma_chan *chan)
dma_pool_destroy(fsl_chan->tcd_pool);
fsl_chan->tcd_pool = NULL;
fsl_chan->used = false;
+ pm_runtime_put_sync(fsl_chan->dev);
}
static void fsl_edma3_synchronize(struct dma_chan *chan)
@@ -839,6 +845,37 @@ static void fsl_edma3_synchronize(struct dma_chan *chan)
vchan_synchronize(&fsl_chan->vchan);
}
+static struct device *fsl_edma3_attach_pd(struct device *dev,
+ struct device_node *np, int index)
+{
+ const char *domn = "edma0-chan01";
+ struct device *pd_chan;
+ struct device_link *link;
+ int ret;
+
+ ret = of_property_read_string_index(np, "power-domain-names", index,
+ &domn);
+ if (ret) {
+ dev_err(dev, "parse power-domain-names error.(%d)\n", ret);
+ return NULL;
+ }
+
+ pd_chan = dev_pm_domain_attach_by_name(dev, domn);
+ if (!pd_chan)
+ return NULL;
+
+ link = device_link_add(dev, pd_chan, DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (IS_ERR(link)) {
+ dev_err(dev, "Failed to add device_link to %s: %ld\n", domn,
+ PTR_ERR(link));
+ return NULL;
+ }
+
+ return pd_chan;
+}
+
static int fsl_edma3_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -962,6 +999,22 @@ static int fsl_edma3_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
return ret;
}
+ /* Attach power domains from dts for each dma chanel device */
+ for (i = 0; i < fsl_edma3->n_chans; i++) {
+ struct fsl_edma3_chan *fsl_chan = &fsl_edma3->chans[i];
+ struct device *dev;
+
+ dev = fsl_edma3_attach_pd(&pdev->dev, np, i);
+ if (!dev) {
+ dev_err(dev, "edma channel attach failed.\n");
+ return -EINVAL;
+ }
+
+ fsl_chan->dev = dev;
+ /* clear meaningless pending irq anyway */
+ writel(1, fsl_chan->membase + EDMA_CH_INT);
+ pm_runtime_put_sync(dev);
+ }
ret = of_dma_controller_register(np, fsl_edma3_xlate, fsl_edma3);
if (ret) {
@@ -970,6 +1023,9 @@ static int fsl_edma3_probe(struct platform_device *pdev)
return ret;
}
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;
}
@@ -1068,7 +1124,7 @@ static int __init fsl_edma3_init(void)
{
return platform_driver_register(&fsl_edma3_driver);
}
-subsys_initcall(fsl_edma3_init);
+fs_initcall(fsl_edma3_init);
static void __exit fsl_edma3_exit(void)
{