From f2d64a30f08b6fa9927bc45dfb308c77258dae9f Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 1 May 2018 18:12:14 +0100 Subject: [PATCH] ASoC: tegra-alt: Fix xrun during playback/capture across suspend If audio playback/capture is running when the system suspends, then an xrun event is reported by the kernel on entering suspend. The problem is that userspace tasks are frozen before the kernel space sound core is suspended. This means that the DMA is still running after userspace has been frozen and hence the CPU has stopped updating the DMA audio buffer. Hence, when the DMA reaches the end of the buffer an XRUN event occurs. Depending on the sample rate the length of time before this XRUN event occurs will vary and the worse case would be around 5ms (for 192kHz with 16 channels @ 16-bits). There is no way to ensure that the sound core is stopped within 5ms of freezing userspace and so the only solution is to ensure that the sound core is suspend before userspace by calling snd_soc_suspend() from the Linux PM prepare handler. Bug 2113333 Change-Id: Ie9da77ee99f74fded4b34cb4ba665da26e9c5e94 Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/1719611 Reviewed-by: mobile promotions Tested-by: mobile promotions --- .../tegra_machine_driver_mobile.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c b/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c index 8ab9197e..971b58a4 100644 --- a/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c +++ b/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c @@ -1435,11 +1435,26 @@ static int tegra_machine_driver_remove(struct platform_device *pdev) return 0; } +#if CONFIG_PM +static void tegra_asoc_machine_resume(struct device *dev) +{ + WARN_ON(snd_soc_resume(dev)); +} +#else +#define tegra_asoc_machine_resume NULL +#endif + +static const struct dev_pm_ops tegra_asoc_machine_pm_ops = { + .prepare = snd_soc_suspend, + .complete = tegra_asoc_machine_resume, + .poweroff = snd_soc_poweroff, +}; + static struct platform_driver tegra_asoc_machine_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, + .pm = &tegra_asoc_machine_pm_ops, .of_match_table = tegra_machine_of_match, }, .probe = tegra_machine_driver_probe,