On Thu, 2012-10-18 at 13:32 +0800, Huang Shijie wrote: > From: Huang Shijie <shijie8@xxxxxxxxx> > > [1] Why add these new DMA control commands? > In mx6q, the gpmi-nand driver is the only user of the APBH-DMA. The dma clock > is enabled when we have successfully requested a DMA channel. So even when > the gpmi-nand driver does not work, the dma clock(apbh-dma) still runs > in high speed (198MHz). To save some power, it is better to disable the dma > clock when the dma device, such as gpmi-nand, is not working anymore. > When the dma device becomes work again, enable the dma clock again. > > [2] add new DMA control commands: DMA_START/DMA_END > DMA_START: do some preprations to start the DMA engine, such as enable the > necessary clocks. > DMA_END: do some works to end the DMA engine, such as disable the > necessary clocks. > > [3] This patch does not change any logic in i2c-mxs driver and mxs-pcm driver. > But for gpmi-nand driver, we will enable the the clock only when we select > the nand chip, and want to do some real jobs with the nand chip. > For mxs-mmc driver, disable the dma clock in the suspend; and enable the > dma clock in the resume. > Why cant you do start (prepare clock etc) when you submit the descriptor to dmaengine. Can be done in tx_submit callback. Similarly remove the clock when dma transaction gets completed. I don't think we need a new API for this, it needs to be handled by driver on its own. > Signed-off-by: Huang Shijie <b32955@xxxxxxxxxxxxx> > --- > drivers/dma/mxs-dma.c | 17 +++++++++++++++++ > drivers/i2c/busses/i2c-mxs.c | 10 +++++++++- > drivers/mmc/host/mxs-mmc.c | 19 ++++++++++++++++--- > drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 10 ++++++++++ > drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 10 ++++++---- > include/linux/dmaengine.h | 6 ++++++ > sound/soc/mxs/mxs-pcm.c | 12 ++++++++++++ > 7 files changed, 76 insertions(+), 8 deletions(-) > > diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c > index 9f02e79..89286f4 100644 > --- a/drivers/dma/mxs-dma.c > +++ b/drivers/dma/mxs-dma.c > @@ -384,6 +384,8 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) > /* the descriptor is ready */ > async_tx_ack(&mxs_chan->desc); > > + clk_disable_unprepare(mxs_dma->clk); > + > return 0; > > err_clk: > @@ -399,6 +401,14 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan) > { > struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); > struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; > + int ret; > + > + ret = clk_prepare_enable(mxs_dma->clk); > + if (ret) { > + dev_err(mxs_dma->dma_device.dev, > + "failed in enabling the dma clock\n"); > + return; > + } > > mxs_dma_disable_chan(mxs_chan); > > @@ -597,9 +607,13 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, > unsigned long arg) > { > struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); > + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; > int ret = 0; > > switch (cmd) { > + case DMA_START: > + ret = clk_prepare_enable(mxs_dma->clk); > + break; > case DMA_TERMINATE_ALL: > mxs_dma_reset_chan(mxs_chan); > mxs_dma_disable_chan(mxs_chan); > @@ -610,6 +624,9 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, > case DMA_RESUME: > mxs_dma_resume_chan(mxs_chan); > break; > + case DMA_END: > + clk_disable_unprepare(mxs_dma->clk); > + break; > default: > ret = -ENOSYS; > } > diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c > index 1f58197..da1e881 100644 > --- a/drivers/i2c/busses/i2c-mxs.c > +++ b/drivers/i2c/busses/i2c-mxs.c > @@ -643,6 +643,12 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) > dev_err(dev, "Failed to request dma\n"); > return -ENODEV; > } > + err = dmaengine_device_control(i2c->dmach, DMA_START, 0); > + if (err) { > + dma_release_channel(i2c->dmach); > + dev_err(dev, "Failed to start dma\n"); > + return err; > + } > } > > platform_set_drvdata(pdev, i2c); > @@ -680,8 +686,10 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev) > if (ret) > return -EBUSY; > > - if (i2c->dmach) > + if (i2c->dmach) { > + dmaengine_device_control(i2c->dmach, DMA_END, 0); > dma_release_channel(i2c->dmach); > + } > > writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); > > diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c > index 80d1e6d..aa91830 100644 > --- a/drivers/mmc/host/mxs-mmc.c > +++ b/drivers/mmc/host/mxs-mmc.c > @@ -676,6 +676,9 @@ static int mxs_mmc_probe(struct platform_device *pdev) > "%s: failed to request dma\n", __func__); > goto out_clk_put; > } > + ret = dmaengine_device_control(ssp->dmach, DMA_START, 0); > + if (ret) > + goto out_free_dma; > > /* set mmc core parameters */ > mmc->ops = &mxs_mmc_ops; > @@ -717,18 +720,20 @@ static int mxs_mmc_probe(struct platform_device *pdev) > ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, > DRIVER_NAME, host); > if (ret) > - goto out_free_dma; > + goto out_end_free_dma; > > spin_lock_init(&host->lock); > > ret = mmc_add_host(mmc); > if (ret) > - goto out_free_dma; > + goto out_end_free_dma; > > dev_info(mmc_dev(host->mmc), "initialized\n"); > > return 0; > > +out_end_free_dma: > + dmaengine_device_control(ssp->dmach, DMA_END, 0); > out_free_dma: > if (ssp->dmach) > dma_release_channel(ssp->dmach); > @@ -750,8 +755,10 @@ static int mxs_mmc_remove(struct platform_device *pdev) > > platform_set_drvdata(pdev, NULL); > > - if (ssp->dmach) > + if (ssp->dmach) { > + dmaengine_device_control(ssp->dmach, DMA_END, 0); > dma_release_channel(ssp->dmach); > + } > > clk_disable_unprepare(ssp->clk); > clk_put(ssp->clk); > @@ -772,6 +779,7 @@ static int mxs_mmc_suspend(struct device *dev) > ret = mmc_suspend_host(mmc); > > clk_disable_unprepare(ssp->clk); > + dmaengine_device_control(ssp->dmach, DMA_END, 0); > > return ret; > } > @@ -784,8 +792,13 @@ static int mxs_mmc_resume(struct device *dev) > int ret = 0; > > clk_prepare_enable(ssp->clk); > + ret = dmaengine_device_control(ssp->dmach, DMA_START, 0); > + if (ret) > + return ret; > > ret = mmc_resume_host(mmc); > + if (ret) > + dmaengine_device_control(ssp->dmach, DMA_END, 0); > > return ret; > } > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > index 3502acc..20ed3f3 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > @@ -958,6 +958,7 @@ void gpmi_begin(struct gpmi_nand_data *this) > uint32_t reg; > unsigned int dll_wait_time_in_us; > struct gpmi_nfc_hardware_timing hw; > + struct dma_chan *channel = get_dma_chan(this); > int ret; > > /* Enable the clock. */ > @@ -967,6 +968,12 @@ void gpmi_begin(struct gpmi_nand_data *this) > goto err_out; > } > > + ret = dmaengine_device_control(channel, DMA_START, 0); > + if (ret) { > + gpmi_disable_clk(this); > + goto err_out; > + } > + > /* Only initialize the timing once */ > if (this->flags & GPMI_TIMING_INIT_OK) > return; > @@ -1035,7 +1042,10 @@ err_out: > > void gpmi_end(struct gpmi_nand_data *this) > { > + struct dma_chan *channel = get_dma_chan(this); > + > gpmi_disable_clk(this); > + dmaengine_device_control(channel, DMA_END, 0); > } > > /* Clears a BCH interrupt. */ > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > index e2c56fc..5694d03 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > @@ -815,12 +815,14 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) > struct nand_chip *chip = mtd->priv; > struct gpmi_nand_data *this = chip->priv; > > - if ((this->current_chip < 0) && (chipnr >= 0)) > + if ((this->current_chip < 0) && (chipnr >= 0)) { > + /* set the current_chip before we call gpmi_begin(). */ > + this->current_chip = chipnr; > gpmi_begin(this); > - else if ((this->current_chip >= 0) && (chipnr < 0)) > + } else if ((this->current_chip >= 0) && (chipnr < 0)) { > gpmi_end(this); > - > - this->current_chip = chipnr; > + this->current_chip = chipnr; > + } > } > > static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h > index d3201e4..79f864a 100644 > --- a/include/linux/dmaengine.h > +++ b/include/linux/dmaengine.h > @@ -199,6 +199,8 @@ enum dma_ctrl_flags { > /** > * enum dma_ctrl_cmd - DMA operations that can optionally be exercised > * on a running channel. > + * @DMA_START: do some preprations to start the DMA engine, such as enable the > + * necessary clocks. > * @DMA_TERMINATE_ALL: terminate all ongoing transfers > * @DMA_PAUSE: pause ongoing transfers > * @DMA_RESUME: resume paused transfer > @@ -209,13 +211,17 @@ enum dma_ctrl_flags { > * command. > * @FSLDMA_EXTERNAL_START: this command will put the Freescale DMA controller > * into external start mode. > + * @DMA_END: do some works to end the DMA engine, such as disable the > + * necessary clocks. > */ > enum dma_ctrl_cmd { > + DMA_START, > DMA_TERMINATE_ALL, > DMA_PAUSE, > DMA_RESUME, > DMA_SLAVE_CONFIG, > FSLDMA_EXTERNAL_START, > + DMA_END, > }; > > /** > diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c > index f82d766..cfcc30f 100644 > --- a/sound/soc/mxs/mxs-pcm.c > +++ b/sound/soc/mxs/mxs-pcm.c > @@ -92,6 +92,7 @@ static int snd_mxs_open(struct snd_pcm_substream *substream) > { > struct snd_soc_pcm_runtime *rtd = substream->private_data; > struct mxs_pcm_dma_data *pcm_dma_data; > + struct dma_chan *chan; > int ret; > > pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL); > @@ -107,6 +108,14 @@ static int snd_mxs_open(struct snd_pcm_substream *substream) > return ret; > } > > + chan = snd_dmaengine_pcm_get_chan(substream); > + ret = dmaengine_device_control(chan, DMA_START, (unsigned long)0); > + if (ret) { > + snd_dmaengine_pcm_close(substream); > + kfree(pcm_dma_data); > + return ret; > + } > + > snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); > > snd_dmaengine_pcm_set_data(substream, pcm_dma_data); > @@ -117,7 +126,10 @@ static int snd_mxs_open(struct snd_pcm_substream *substream) > static int snd_mxs_close(struct snd_pcm_substream *substream) > { > struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream); > + struct dma_chan *chan; > > + chan = snd_dmaengine_pcm_get_chan(substream); > + dmaengine_device_control(chan, DMA_END, 0); > snd_dmaengine_pcm_close(substream); > kfree(pcm_dma_data); > -- ~Vinod -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html