dmaengine: dw: fix regression in dw_probe() function
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Thu, 8 May 2014 09:01:49 +0000 (12:01 +0300)
committerVinod Koul <vinod.koul@intel.com>
Thu, 22 May 2014 10:07:24 +0000 (15:37 +0530)
The commit dbde5c29 "dw_dmac: use devm_* functions to simplify code" turns
probe function to use devm_* helpers and simultaneously brings a regression.

We have to 1) call clk_disable_unprepare() on error path, and 2) check error
code of clk_enable_prepare(). First part was done in the original code, second
one is an update.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/dw/core.c

index 009dc62f94377ce5956e8cbdc60841b029016116..d539019fbe6059fcc7b5296375dffe5aa611998a 100644 (file)
@@ -1496,7 +1496,9 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        dw->clk = devm_clk_get(chip->dev, "hclk");
        if (IS_ERR(dw->clk))
                return PTR_ERR(dw->clk);
-       clk_prepare_enable(dw->clk);
+       err = clk_prepare_enable(dw->clk);
+       if (err)
+               return err;
 
        dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
        autocfg = dw_params >> DW_PARAMS_EN & 0x1;
@@ -1505,15 +1507,19 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
 
        if (!pdata && autocfg) {
                pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
+               if (!pdata) {
+                       err = -ENOMEM;
+                       goto err_pdata;
+               }
 
                /* Fill platform data with the default values */
                pdata->is_private = true;
                pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING;
                pdata->chan_priority = CHAN_PRIORITY_ASCENDING;
-       } else if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS)
-               return -EINVAL;
+       } else if (!pdata || pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
+               err = -EINVAL;
+               goto err_pdata;
+       }
 
        if (autocfg)
                nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 0x7) + 1;
@@ -1522,8 +1528,10 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
 
        dw->chan = devm_kcalloc(chip->dev, nr_channels, sizeof(*dw->chan),
                                GFP_KERNEL);
-       if (!dw->chan)
-               return -ENOMEM;
+       if (!dw->chan) {
+               err = -ENOMEM;
+               goto err_pdata;
+       }
 
        /* Get hardware configuration parameters */
        if (autocfg) {
@@ -1553,7 +1561,8 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
                                         sizeof(struct dw_desc), 4, 0);
        if (!dw->desc_pool) {
                dev_err(chip->dev, "No memory for descriptors dma pool\n");
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_pdata;
        }
 
        tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
@@ -1561,7 +1570,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED,
                          "dw_dmac", dw);
        if (err)
-               return err;
+               goto err_pdata;
 
        INIT_LIST_HEAD(&dw->dma.channels);
        for (i = 0; i < nr_channels; i++) {
@@ -1656,6 +1665,10 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        dma_async_device_register(&dw->dma);
 
        return 0;
+
+err_pdata:
+       clk_disable_unprepare(dw->clk);
+       return err;
 }
 EXPORT_SYMBOL_GPL(dw_dma_probe);
 
@@ -1676,6 +1689,8 @@ int dw_dma_remove(struct dw_dma_chip *chip)
                channel_clear_bit(dw, CH_EN, dwc->mask);
        }
 
+       clk_disable_unprepare(dw->clk);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(dw_dma_remove);