Hi Tony,
Am 06.11.2018 um 16:47 schrieb Tony Lindgren tony@atomide.com:
- H. Nikolaus Schaller hns@goldelico.com [181029 18:12]:
So we face this situation:
- CONFIG_CPU_IDLE=y reduces idle current of OMAP3 by 10mA (important for power saving! also for Pyra)
- CONFIG_CPU_IDLE=y breaks audio on OMAP5 + twl6040 (but not on Pandaboard ES OMAP4 + twl6040)
What fix is needed to make mainline (does not include AESS) OMAP5+TWL6040 work in combination with CONFIG_CPU_IDLE=y?
The audio components do not block deeper idle states in the hardware. So the driver needs to use PM QoS to prevent glitches, see for example what was done in commit 9834ffd1ecc3 ("ASoC: omap-mcbsp: Add PM QoS support for McBSP to prevent glitches").
I guess you need to do it for mcpdm in this case?
I have sketched some hack for first experiments (only compile-tested but not for function). Is this the correct direction?
BR, Nikolaus
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 4c1be36c2207..fb479b76f112 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -70,6 +70,9 @@ struct omap_mcpdm { int pm_active_count;
struct snd_dmaengine_dai_dma_data dma_data[2]; + + struct pm_qos_request pm_qos_req; + };
/* @@ -289,6 +292,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, } }
+ /* FIXME: remove/update pm_qos */ + mutex_unlock(&mcpdm->mutex); }
@@ -359,6 +364,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
mcpdm->config[stream].link_mask = link_mask;
+ /* FIXME: handle latency calculations */ + return 0; }
@@ -367,6 +374,10 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+ #define latency 10 /* in usec https://www.kernel.org/doc/Documentation/power/pm_qos_interface.txt */ + + struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req; + if (!omap_mcpdm_active(mcpdm)) { omap_mcpdm_start(mcpdm); omap_mcpdm_reg_dump(mcpdm); @@ -377,6 +388,12 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, omap_mcpdm_reg_dump(mcpdm); }
+ /* FIXME: use different latencies for channels */ + if (pm_qos_request_active(pm_qos_req)) + pm_qos_update_request(pm_qos_req, latency); + else + pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency); + return 0; }
@@ -424,6 +441,9 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) { struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+ if (pm_qos_request_active(&mcpdm->pm_qos_req)) + pm_qos_remove_request(&mcpdm->pm_qos_req); + free_irq(mcpdm->irq, (void *)mcpdm); pm_runtime_disable(mcpdm->dev);