From 29defcb5da1f15f261f56daebcba0e44d7d93721 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 21 Mar 2018 16:31:55 +0000 Subject: [PATCH] ASoC: tegra-alt: Fix restoration of PEQ settings On Tegra194 the PEQ gain and shift settings are not maintained across AUD powergate transitions. Simply by reading the gain/shift settings from userspace via amixer/tinymix continuously causing the AUD powergate to power cycle the settings can be seen to continuously change. Commit bc4166782c07 ("tegra-alt: Enable ahubram prog. in hw_params") partially fix the problem by re-configuring the gain/shift settings to their default settings each time the PEQ is in-use, however, even with this change, if the user changes the settings, they are not preserved. On Tegra186 the PEQ gain and shift settings are not preserved after transitioning to low power states such as SC7. There is a difference between the PMC on Tegra186 and Tegra194, such that Tegra194 no longer supports SRAM retention for the AUD powergate which explains why the device behave slightly differently. To ensure that the PEQ gain and shift settings are preserved for all devices add save and restore helpers and invoke them from the OPE runtime-pm handlers. Bug 2072802 Bug 200375657 Change-Id: Ic867bcfd355a50eba8ba538a9471722b824df3c5 Signed-off-by: Jon Hunter Reviewed-on: https://git-master.nvidia.com/r/1679636 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Asha Talambedu Reviewed-by: Sameer Pujar Reviewed-by: svc-mobile-coverity GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: mobile promotions Tested-by: mobile promotions --- .../soc/tegra-alt/include/tegra210_ope_alt.h | 9 +++- sound/soc/tegra-alt/tegra210_ope_alt.c | 8 ++-- sound/soc/tegra-alt/tegra210_peq_alt.c | 42 +++++++++++++------ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/sound/soc/tegra-alt/include/tegra210_ope_alt.h b/sound/soc/tegra-alt/include/tegra210_ope_alt.h index 38476a2e..a717e1a1 100644 --- a/sound/soc/tegra-alt/include/tegra210_ope_alt.h +++ b/sound/soc/tegra-alt/include/tegra210_ope_alt.h @@ -1,7 +1,7 @@ /* * tegra210_ope_alt.h - Definitions for Tegra210 OPE driver * - * Copyright (c) 2014-2017 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018 NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +19,8 @@ #ifndef __TEGRA210_OPE_ALT_H__ #define __TEGRA210_OPE_ALT_H__ +#include "tegra210_peq_alt.h" + /* Register offsets from TEGRA210_OPE*_BASE */ /* * OPE_AXBAR_RX registers are with respect to AXBAR. @@ -87,12 +89,15 @@ struct tegra210_ope { struct regmap *peq_regmap; struct regmap *mbdrc_regmap; const struct tegra210_ope_soc_data *soc_data; + u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH]; + u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH]; bool is_shutdown; }; extern int tegra210_peq_init(struct platform_device *pdev, int id); extern int tegra210_peq_codec_init(struct snd_soc_codec *codec); -extern int tegra210_peq_hw_params(struct snd_soc_codec *codec); +extern void tegra210_peq_restore(struct tegra210_ope *ope); +extern void tegra210_peq_save(struct tegra210_ope *ope); extern int tegra210_mbdrc_init(struct platform_device *pdev, int id); extern int tegra210_mbdrc_codec_init(struct snd_soc_codec *codec); extern int tegra210_mbdrc_hw_params(struct snd_soc_codec *codec); diff --git a/sound/soc/tegra-alt/tegra210_ope_alt.c b/sound/soc/tegra-alt/tegra210_ope_alt.c index 1a93b738..68221c88 100644 --- a/sound/soc/tegra-alt/tegra210_ope_alt.c +++ b/sound/soc/tegra-alt/tegra210_ope_alt.c @@ -1,7 +1,7 @@ /* * tegra210_ope_alt.c - Tegra210 OPE driver * - * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -49,6 +49,8 @@ static int tegra210_ope_runtime_suspend(struct device *dev) { struct tegra210_ope *ope = dev_get_drvdata(dev); + tegra210_peq_save(ope); + regcache_cache_only(ope->mbdrc_regmap, true); regcache_cache_only(ope->peq_regmap, true); regcache_cache_only(ope->regmap, true); @@ -71,6 +73,8 @@ static int tegra210_ope_runtime_resume(struct device *dev) regcache_sync(ope->regmap); regcache_sync(ope->peq_regmap); regcache_sync(ope->mbdrc_regmap); + + tegra210_peq_restore(ope); } return 0; @@ -151,7 +155,6 @@ static int tegra210_ope_hw_params(struct snd_pcm_substream *substream, return ret; } - ope->soc_data->peq_soc_data.hw_params(dai->codec); ope->soc_data->mbdrc_soc_data.hw_params(dai->codec); return ret; @@ -332,7 +335,6 @@ static const struct tegra210_ope_soc_data soc_data_tegra210 = { .peq_soc_data = { .init = tegra210_peq_init, .codec_init = tegra210_peq_codec_init, - .hw_params = tegra210_peq_hw_params, }, .mbdrc_soc_data = { .init = tegra210_mbdrc_init, diff --git a/sound/soc/tegra-alt/tegra210_peq_alt.c b/sound/soc/tegra-alt/tegra210_peq_alt.c index e328e474..d021ebe1 100644 --- a/sound/soc/tegra-alt/tegra210_peq_alt.c +++ b/sound/soc/tegra-alt/tegra210_peq_alt.c @@ -1,7 +1,7 @@ /* * tegra210_peq_alt.c - Tegra210 PEQ driver * - * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -281,35 +281,51 @@ static const struct regmap_config tegra210_peq_regmap_config = { .cache_type = REGCACHE_FLAT, }; -int tegra210_peq_hw_params(struct snd_soc_codec *codec) +void tegra210_peq_restore(struct tegra210_ope *ope) { - struct tegra210_ope *ope = snd_soc_codec_get_drvdata(codec); - u32 val = 0; - int i = 0; - - regmap_read(ope->peq_regmap, TEGRA210_PEQ_CONFIG, &val); - if (!(val & TEGRA210_PEQ_CONFIG_MODE_ACTIVE)) - return 0; + unsigned int i; for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) { tegra210_xbar_write_ahubram(ope->peq_regmap, TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL, TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA, (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH), - (u32 *)&biquad_init_gains, + (u32 *)&ope->peq_biquad_gains, TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH); tegra210_xbar_write_ahubram(ope->peq_regmap, TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL, TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA, (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH), - (u32 *)&biquad_init_shifts, + (u32 *)&ope->peq_biquad_shifts, TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH); } - return 0; } -EXPORT_SYMBOL_GPL(tegra210_peq_hw_params); +EXPORT_SYMBOL_GPL(tegra210_peq_restore); + +void tegra210_peq_save(struct tegra210_ope *ope) +{ + unsigned int i; + + for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) { + tegra210_xbar_read_ahubram(ope->peq_regmap, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_CTRL, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_DATA, + (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH), + (u32 *)&ope->peq_biquad_gains, + TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH); + + tegra210_xbar_read_ahubram(ope->peq_regmap, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_CTRL, + TEGRA210_PEQ_AHUBRAMCTL_CONFIG_RAM_SHIFT_DATA, + (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH), + (u32 *)&ope->peq_biquad_shifts, + TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH); + + } +} +EXPORT_SYMBOL_GPL(tegra210_peq_save); int tegra210_peq_codec_init(struct snd_soc_codec *codec) {