ASoC: tegra-alt: use regmap macros for timeout

Following print is seen while using regmap_read_poll_timeout() macro
in snd_soc_dai_ops trigger() callback in ADMAIF driver,
 *** BUG: scheduling while atomic ***
and kernel panic happens there after. This happens because above macro
is not atomic safe and trigger() is called in atomic context.

Earlier this addressed by using readx_poll_timeout_atomic() macro.
Though this works fine driver needs to keep a reference to base address.
To avoid this new macro was pushed and is accepted in upstream and
following is the commit - https://lkml.org/lkml/2020/1/9/985

This patch makes use of regmap macros where there is a need of timeout
functionality. Following is the guideline that can be followed.
 * use regmap_read_poll_timeout_atomic() where the caller is in atomic
   context.
   ex: trigger() etc.,
 * use regmap_read_poll_timeout() when the caller is known to be running
   in non-atomic context.
   ex: hw_param(), prepare() etc.,

Based on this audio drivers are updated. ASRC and ARAD drivers will be
taken up in a separate change.

Bug 200566596

Change-Id: Iea88adc60de5919e456a36a30152212652a8ecd3
Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2274874
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Sameer Pujar
2020-01-07 14:46:18 +05:30
parent 27008c3e63
commit f44cfefe5d
9 changed files with 152 additions and 227 deletions

View File

@@ -209,7 +209,6 @@ struct tegra210_i2s {
bool loopback;
unsigned int format;
unsigned int rx_fifo_th; /* should be programmed interms of frames */
void __iomem *base_addr;
};
#endif

View File

@@ -16,10 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -431,7 +429,7 @@ static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
/* wait until ADMAIF TX/RX status is disabled */
ret = readl_poll_timeout_atomic(REG_IOVA(status_reg), val,
ret = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
!(val & enable), 10, 10000);
/* Timeout may be hit if sink gets closed/blocked ahead of source */
@@ -443,7 +441,7 @@ static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
/* wait till SW reset is complete */
ret = readl_poll_timeout_atomic(REG_IOVA(reset_reg), val,
ret = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
!(val & SW_RESET_MASK & SW_RESET),
10, 10000);
if (ret < 0) {

View File

@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -155,22 +154,34 @@ static void tegra210_adx_update_map_ram(struct tegra210_adx *adx)
tegra210_adx_write_map_ram(adx, i, adx->map[i]);
}
static int tegra210_adx_sw_reset(struct tegra210_adx *adx,
int timeout)
static int tegra210_adx_stop(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct device *dev = codec->dev;
struct tegra210_adx *adx = dev_get_drvdata(dev);
unsigned int val;
int wait = timeout;
int ret;
/* ensure if ADX status is disabled */
ret = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS,
val, !(val & 0x1), 10, 10000);
if (ret < 0) {
dev_err(dev, "failed to stop ADX, err = %d\n", ret);
return ret;
}
/* SW reset */
regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET,
TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK,
TEGRA210_ADX_SOFT_RESET_SOFT_EN);
do {
regmap_read(adx->regmap, TEGRA210_ADX_SOFT_RESET, &val);
wait--;
if (!wait)
return -EINVAL;
} while (val & 0x00000001);
ret = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_SOFT_RESET,
val, !(val & 0x1), 10, 10000);
if (ret < 0) {
dev_err(dev, "failed to reset ADX, err = %d\n", ret);
return ret;
}
regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET,
TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK,
@@ -179,44 +190,11 @@ static int tegra210_adx_sw_reset(struct tegra210_adx *adx,
return 0;
}
static int tegra210_adx_get_status(struct tegra210_adx *adx)
static unsigned int __maybe_unused
tegra210_adx_read_map_ram(struct tegra210_adx *adx, unsigned int addr)
{
unsigned int val;
regmap_read(adx->regmap, TEGRA210_ADX_STATUS, &val);
val = (val & 0x00000001);
return val;
}
static int tegra210_adx_stop(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct device *dev = codec->dev;
struct tegra210_adx *adx = dev_get_drvdata(dev);
int dcnt = 10, ret = 0;
/* wait until ADX status is disabled */
while (tegra210_adx_get_status(adx) && dcnt--)
udelay(100);
/* HW needs sw reset to make sure previous transaction be clean */
ret = tegra210_adx_sw_reset(adx, 0xffff);
if (ret) {
dev_err(dev, "Failed at ADX%d sw reset\n", dev->id);
return ret;
}
return (dcnt < 0) ? -ETIMEDOUT : 0;
}
static unsigned int __maybe_unused tegra210_adx_read_map_ram(
struct tegra210_adx *adx,
unsigned int addr)
{
unsigned int val, wait;
wait = 0xffff;
int ret;
regmap_write(adx->regmap, TEGRA210_ADX_AHUBRAMCTL_ADX_CTRL,
(addr << TEGRA210_ADX_AHUBRAMCTL_ADX_CTRL_RAM_ADDR_SHIFT));
@@ -228,12 +206,11 @@ static unsigned int __maybe_unused tegra210_adx_read_map_ram(
val &= ~(TEGRA210_ADX_AHUBRAMCTL_ADX_CTRL_RW_WRITE);
regmap_write(adx->regmap, TEGRA210_ADX_AHUBRAMCTL_ADX_CTRL, val);
do {
regmap_read(adx->regmap, TEGRA210_ADX_AHUBRAMCTL_ADX_CTRL, &val);
wait--;
if (!wait)
return -EINVAL;
} while (val & 0x80000000);
ret = regmap_read_poll_timeout(adx->regmap,
TEGRA210_ADX_AHUBRAMCTL_ADX_CTRL,
val, !(val & 0x80000000), 10, 10000);
if (ret < 0)
return ret;
regmap_read(adx->regmap, TEGRA210_ADX_AHUBRAMCTL_ADX_DATA, &val);

View File

@@ -1,7 +1,7 @@
/*
* tegra210_afc_alt.c - Tegra210 AFC driver
*
* Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2014-2020 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,
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>

View File

@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -179,60 +178,40 @@ static void tegra210_amx_update_map_ram(struct tegra210_amx *amx)
tegra210_amx_write_map_ram(amx, i, amx->map[i]);
}
static int tegra210_amx_sw_reset(struct tegra210_amx *amx,
int timeout)
{
unsigned int val;
int wait = timeout;
regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
TEGRA210_AMX_SOFT_RESET_SOFT_EN);
do {
regmap_read(amx->regmap, TEGRA210_AMX_SOFT_RESET, &val);
wait--;
if (!wait)
return -EINVAL;
} while (val & 0x00000001);
regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
TEGRA210_AMX_SOFT_RESET_SOFT_DEFAULT);
return 0;
}
static int tegra210_amx_get_status(struct tegra210_amx *amx)
{
unsigned int val;
regmap_read(amx->regmap, TEGRA210_AMX_STATUS, &val);
val = (val & 0x00000001);
return val;
}
static int tegra210_amx_stop(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct device *dev = codec->dev;
struct tegra210_amx *amx = dev_get_drvdata(dev);
int dcnt = 10, ret = 0;
unsigned int val;
int ret;
/* wait until AMX status is disabled */
while (tegra210_amx_get_status(amx) && dcnt--)
udelay(100);
/* HW needs sw reset to make sure previous transaction be clean */
ret = tegra210_amx_sw_reset(amx, 0xffff);
if (ret) {
dev_err(dev, "Failed at AMX%d sw reset\n", dev->id);
/* Ensure if AMX is disabled */
ret = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val,
!(val & 0x1), 10, 10000);
if (ret < 0) {
dev_err(dev, "failed to stop AMX, err = %d\n", ret);
return ret;
}
return (dcnt < 0) ? -ETIMEDOUT : 0;
/* SW reset */
regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
TEGRA210_AMX_SOFT_RESET_SOFT_EN);
ret = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET,
val, !(val & 0x1), 10, 10000);
if (ret < 0) {
dev_err(dev, "failed to reset AMX, err = %d\n", ret);
return ret;
}
regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
TEGRA210_AMX_SOFT_RESET_SOFT_DEFAULT);
return 0;
}
static int tegra210_amx_runtime_suspend(struct device *dev)
@@ -245,12 +224,11 @@ static int tegra210_amx_runtime_suspend(struct device *dev)
return 0;
}
static unsigned int __maybe_unused tegra210_amx_read_map_ram(
struct tegra210_amx *amx,
unsigned int addr)
static unsigned int __maybe_unused
tegra210_amx_read_map_ram(struct tegra210_amx *amx, unsigned int addr)
{
unsigned int val, wait;
wait = 0xffff;
unsigned int val;
int ret;
regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL,
(addr << TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_RAM_ADDR_SHIFT));
@@ -262,13 +240,11 @@ static unsigned int __maybe_unused tegra210_amx_read_map_ram(
val &= ~(TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL_RW_WRITE);
regmap_write(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, val);
do {
regmap_read(amx->regmap,
TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL, &val);
wait--;
if (!wait)
return -EINVAL;
} while (val & 0x80000000);
ret = regmap_read_poll_timeout(amx->regmap,
TEGRA210_AMX_AHUBRAMCTL_AMX_CTRL,
val, !(val & 0x80000000), 10, 10000);
if (ret < 0)
return ret;
regmap_read(amx->regmap, TEGRA210_AMX_AHUBRAMCTL_AMX_DATA, &val);

View File

@@ -16,11 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -33,7 +31,6 @@
#include <linux/pinctrl/pinconf-tegra.h>
#include <linux/regulator/consumer.h>
#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/tegra-powergate.h>
#include <soc/tegra/chip-id.h>
#include <linux/pm_domain.h>
@@ -43,8 +40,6 @@
#define DRV_NAME "tegra210-i2s"
#define REG_IOVA(reg) (i2s->base_addr + (reg))
static const struct reg_default tegra210_i2s_reg_defaults[] = {
{ TEGRA210_I2S_AXBAR_RX_INT_MASK, 0x00000003},
{ TEGRA210_I2S_AXBAR_RX_CIF_CTRL, 0x00007700},
@@ -144,7 +139,7 @@ static int tegra210_i2s_sw_reset(struct snd_soc_codec *codec, bool is_playback)
/* SW reset */
regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
ret = readl_poll_timeout_atomic(REG_IOVA(reset_reg), val,
ret = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
!(val & reset_mask & reset_en),
10, 10000);
if (ret < 0) {
@@ -185,7 +180,7 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
}
/* ensure I2S is in disabled state before new session */
ret = readl_poll_timeout_atomic(REG_IOVA(status_reg), val,
ret = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
!(val & TEGRA210_I2S_EN_MASK & TEGRA210_I2S_EN),
10, 10000);
if (ret < 0) {
@@ -1100,8 +1095,6 @@ static int tegra210_i2s_platform_probe(struct platform_device *pdev)
if (IS_ERR(regs))
return PTR_ERR(regs);
i2s->base_addr = regs;
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
&tegra210_i2s_regmap_config);
if (IS_ERR(i2s->regmap)) {

View File

@@ -96,19 +96,17 @@ static int tegra210_mixer_runtime_resume(struct device *dev)
static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
unsigned int addr,
unsigned int val)
unsigned int coef)
{
unsigned int reg, value, wait = 0xffff;
unsigned int reg, val;
int ret;
/* check if busy */
do {
regmap_read(mixer->regmap,
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL, &value);
wait--;
if (!wait)
return -EINVAL;
} while (value & 0x80000000);
value = 0;
ret = regmap_read_poll_timeout(mixer->regmap,
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL,
val, !(val & 0x80000000), 10, 10000);
if (ret < 0)
return ret;
reg = (addr << TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_RAM_ADDR_SHIFT) &
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_RAM_ADDR_MASK;
@@ -117,9 +115,11 @@ static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer,
reg |= TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL_SEQ_ACCESS_EN;
regmap_write(mixer->regmap,
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL, reg);
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_CTRL,
reg);
regmap_write(mixer->regmap,
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA, val);
TEGRA210_MIXER_AHUBRAMCTL_GAIN_CONFIG_RAM_DATA,
coef);
return 0;
}

View File

@@ -28,7 +28,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/of_device.h>
#include <linux/delay.h>
#include "tegra210_xbar_alt.h"
#include "tegra210_mvc_alt.h"
@@ -75,40 +74,17 @@ static int tegra210_mvc_runtime_resume(struct device *dev)
return 0;
}
static int tegra210_mvc_soft_reset(struct tegra210_mvc *mvc)
{
int value;
int dcnt = 10;
/* issue soft reset */
regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
/* wait for soft reset bit to clear */
do {
udelay(10);
regmap_read(mvc->regmap, TEGRA210_MVC_SOFT_RESET, &value);
dcnt--;
if (dcnt < 0)
return -EINVAL;
} while (value);
return 0;
}
static int tegra210_mvc_write_ram(struct tegra210_mvc *mvc,
unsigned int addr,
unsigned int val)
unsigned int addr, unsigned int coef)
{
unsigned int reg, value, wait = 0xffff;
unsigned int reg, val;
int ret;
/* check if busy */
do {
regmap_read(mvc->regmap,
ret = regmap_read_poll_timeout(mvc->regmap,
TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL,
&value);
wait--;
if (!wait)
return -EINVAL;
} while (value & 0x80000000);
value = 0;
val, !(val & 0x80000000), 10, 10000);
if (ret < 0)
return ret;
reg = (addr << TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_RAM_ADDR_SHIFT) &
TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_RAM_ADDR_MASK;
@@ -116,10 +92,9 @@ static int tegra210_mvc_write_ram(struct tegra210_mvc *mvc,
reg |= TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_RW_WRITE;
reg |= TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL_SEQ_ACCESS_EN;
regmap_write(mvc->regmap,
TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL, reg);
regmap_write(mvc->regmap,
TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_DATA, val);
regmap_write(mvc->regmap, TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_CTRL, reg);
regmap_write(mvc->regmap, TEGRA210_MVC_AHUBRAMCTL_CONFIG_RAM_DATA,
coef);
return 0;
}
@@ -161,21 +136,18 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tegra210_mvc *mvc = snd_soc_codec_get_drvdata(codec);
unsigned int reg = mc->reg;
unsigned int value, wait = 0xffff;
unsigned int value;
int ret = 0;
s32 val;
pm_runtime_get_sync(codec->dev);
/* check if VOLUME_SWITCH is triggered */
do {
regmap_read(mvc->regmap,
TEGRA210_MVC_SWITCH, &value);
wait--;
if (!wait) {
ret = -EINVAL;
ret = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH,
value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK),
10, 10000);
if (ret < 0)
goto end;
}
} while (value & TEGRA210_MVC_VOLUME_SWITCH_MASK);
if (reg == TEGRA210_MVC_TARGET_VOL) {
/* Volume control read from mixer ctl is with */
@@ -357,11 +329,15 @@ static int tegra210_mvc_hw_params(struct snd_pcm_substream *substream,
{
struct device *dev = dai->dev;
struct tegra210_mvc *mvc = snd_soc_dai_get_drvdata(dai);
int i, ret;
int i, ret, val;
ret = tegra210_mvc_soft_reset(mvc);
/* SW reset */
regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
ret = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SOFT_RESET,
val, !val, 10, 10000);
if (ret < 0) {
dev_err(dev, "SOFT_RESET error: %d\n", ret);
dev_err(dev, "SW reset failed, err = %d\n", ret);
return ret;
}
@@ -396,8 +372,14 @@ static int tegra210_mvc_hw_params(struct snd_pcm_substream *substream,
regmap_write(mvc->regmap, TEGRA210_MVC_TARGET_VOL, mvc->volume);
/* program the poly coefficients */
for (i = 0; i < 9; i++)
tegra210_mvc_write_ram(mvc, i, mvc->poly_coeff[i]);
for (i = 0; i < 9; i++) {
ret = tegra210_mvc_write_ram(mvc, i, mvc->poly_coeff[i]);
if (ret < 0) {
dev_err(dai->dev, "failed to write coefs, err = %d\n",
ret);
return ret;
}
}
/* program poly_n1, poly_n2, duration */
regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N1, mvc->poly_n1);

View File

@@ -28,7 +28,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/of_device.h>
#include <linux/delay.h>
#include "tegra210_xbar_alt.h"
#include "tegra210_sfc_alt.h"
@@ -3015,20 +3014,19 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc,
static int tegra210_sfc_soft_reset(struct tegra210_sfc *sfc)
{
u32 val;
int cnt = 10;
int ret = 0;
int ret;
regmap_update_bits(sfc->regmap,
TEGRA210_SFC_SOFT_RESET,
TEGRA210_SFC_SOFT_RESET_EN,
1);
do {
udelay(100);
regmap_read(sfc->regmap, TEGRA210_SFC_SOFT_RESET, &val);
} while ((val & TEGRA210_SFC_SOFT_RESET_EN) && cnt--);
if (!cnt)
ret = -ETIMEDOUT;
/* SW reset */
regmap_update_bits(sfc->regmap, TEGRA210_SFC_SOFT_RESET,
TEGRA210_SFC_SOFT_RESET_EN, 1);
ret = regmap_read_poll_timeout(sfc->regmap, TEGRA210_SFC_SOFT_RESET,
val, !(val & TEGRA210_SFC_SOFT_RESET_EN),
10, 10000);
if (ret < 0)
return ret;
return 0;
}
static int tegra210_sfc_in_hw_params(struct snd_pcm_substream *substream,
@@ -3045,8 +3043,10 @@ static int tegra210_sfc_in_hw_params(struct snd_pcm_substream *substream,
0);
ret = tegra210_sfc_soft_reset(sfc);
if (ret) {
dev_err(dev, "SOFT_RESET error: %d\n", ret);
if (ret < 0) {
dev_err(dev, "failed to reset SFC in %s, err = %d\n",
__func__, ret);
return ret;
}
@@ -3200,27 +3200,28 @@ static int tegra210_sfc_init_put(struct snd_kcontrol *kcontrol,
if (is_enabled) {
u32 val;
int cnt = 100;
regmap_write(sfc->regmap, TEGRA210_SFC_ENABLE, 0);
regmap_read(sfc->regmap, TEGRA210_SFC_STATUS, &val);
while ((val & 1) && cnt--) {
udelay(100);
regmap_read(sfc->regmap, TEGRA210_SFC_STATUS, &val);
ret = regmap_read_poll_timeout(sfc->regmap,
TEGRA210_SFC_STATUS, val,
!(val & 0x1), 10, 10000);
if (ret < 0) {
dev_err(codec->dev,
"failed to disable SFC, err = %d\n", ret);
return ret;
}
if (!cnt)
dev_warn(codec->dev, "SFC disable timeout\n");
regmap_update_bits(sfc->regmap,
TEGRA210_SFC_COEF_RAM,
TEGRA210_SFC_COEF_RAM_COEF_RAM_EN,
0);
ret = tegra210_sfc_soft_reset(sfc);
if (ret) {
dev_err(codec->dev, "SOFT_RESET error: %d\n", ret);
if (ret < 0) {
dev_err(codec->dev,
"failed to reset SFC in %s, err = %d\n",
__func__, ret);
goto exit;
}