bool prevent_refactor = !!FIELD_GET(STM32_DMA3_DT_NOPACK, chan->dt_config.tr_conf) ||
!!FIELD_GET(STM32_DMA3_DT_NOREFACT, chan->dt_config.tr_conf);
+ /* Semaphore could be lost during suspend/resume */
+ if (chan->semaphore_mode && !chan->semaphore_taken)
+ return NULL;
+
count = stm32_dma3_get_ll_count(chan, len, prevent_refactor);
swdesc = stm32_dma3_chan_desc_alloc(chan, count);
!!FIELD_GET(STM32_DMA3_DT_NOREFACT, chan->dt_config.tr_conf);
int ret;
+ /* Semaphore could be lost during suspend/resume */
+ if (chan->semaphore_mode && !chan->semaphore_taken)
+ return NULL;
+
count = 0;
for_each_sg(sgl, sg, sg_len, i)
count += stm32_dma3_get_ll_count(chan, sg_dma_len(sg), prevent_refactor);
u32 count, i, ctr1, ctr2;
int ret;
+ /* Semaphore could be lost during suspend/resume */
+ if (chan->semaphore_mode && !chan->semaphore_taken)
+ return NULL;
+
if (!buf_len || !period_len || period_len > STM32_DMA3_MAX_BLOCK_SIZE) {
dev_err(chan2dev(chan), "Invalid buffer/period length\n");
return NULL;
return ret;
}
+static int stm32_dma3_pm_suspend(struct device *dev)
+{
+ struct stm32_dma3_ddata *ddata = dev_get_drvdata(dev);
+ struct dma_device *dma_dev = &ddata->dma_dev;
+ struct dma_chan *c;
+ int ccr, ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ list_for_each_entry(c, &dma_dev->channels, device_node) {
+ struct stm32_dma3_chan *chan = to_stm32_dma3_chan(c);
+
+ ccr = readl_relaxed(ddata->base + STM32_DMA3_CCR(chan->id));
+ if (ccr & CCR_EN) {
+ dev_warn(dev, "Suspend is prevented: %s still in use by %s\n",
+ dma_chan_name(c), dev_name(c->slave));
+ pm_runtime_put_sync(dev);
+ return -EBUSY;
+ }
+ }
+
+ pm_runtime_put_sync(dev);
+
+ pm_runtime_force_suspend(dev);
+
+ return 0;
+}
+
+static int stm32_dma3_pm_resume(struct device *dev)
+{
+ struct stm32_dma3_ddata *ddata = dev_get_drvdata(dev);
+ struct dma_device *dma_dev = &ddata->dma_dev;
+ struct dma_chan *c;
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Channel semaphores need to be restored in case of registers reset during low power.
+ * stm32_dma3_get_chan_sem() will prior check the semaphore status.
+ */
+ list_for_each_entry(c, &dma_dev->channels, device_node) {
+ struct stm32_dma3_chan *chan = to_stm32_dma3_chan(c);
+
+ if (chan->semaphore_mode && chan->semaphore_taken)
+ stm32_dma3_get_chan_sem(chan);
+ }
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
static const struct dev_pm_ops stm32_dma3_pm_ops = {
- SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ SYSTEM_SLEEP_PM_OPS(stm32_dma3_pm_suspend, stm32_dma3_pm_resume)
RUNTIME_PM_OPS(stm32_dma3_runtime_suspend, stm32_dma3_runtime_resume, NULL)
};