mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-01 02:21:16 +00:00
ASoC: msm8x16: fix the target crash due to dpm timeout
DPM timeout was happening due to the suspend call to the codec driver being blocked. This was due to a deadlock by acquiring the same mutex by the suspend call and the work queue. Fix by modifying the codeflow so that the deadlock is avoided. CRs-Fixed: 681986 Change-Id: I96f11ee968a0e9bd267a80d2d11f1fa49985f5a9 Signed-off-by: Aviral Gupta <aviralg@codeaurora.org>
This commit is contained in:
parent
e19940c9ea
commit
1d1b1f5e85
3 changed files with 45 additions and 84 deletions
|
@ -351,7 +351,7 @@ static int __msm8x16_wcd_reg_read(struct snd_soc_codec *codec,
|
|||
ret = msm8x16_wcd_spmi_read(reg, 1, &temp);
|
||||
else if (MSM8X16_WCD_IS_DIGITAL_REG(reg)) {
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if (atomic_read(&pdata->dis_work_mclk) == false) {
|
||||
if (atomic_read(&pdata->mclk_enabled) == false) {
|
||||
pdata->digital_cdc_clk.clk_val = pdata->mclk_freq;
|
||||
ret = afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
|
@ -363,8 +363,8 @@ static int __msm8x16_wcd_reg_read(struct snd_soc_codec *codec,
|
|||
pr_debug("%s: MCLK not enabled\n", __func__);
|
||||
ret = msm8x16_wcd_ahb_read_device(
|
||||
msm8x16_wcd, reg, 1, &temp);
|
||||
atomic_set(&pdata->dis_work_mclk, true);
|
||||
schedule_delayed_work(&pdata->enable_mclk_work, 50);
|
||||
atomic_set(&pdata->mclk_enabled, true);
|
||||
schedule_delayed_work(&pdata->disable_mclk_work, 50);
|
||||
err:
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
mutex_unlock(&msm8x16_wcd->io_lock);
|
||||
|
@ -401,7 +401,7 @@ static int __msm8x16_wcd_reg_write(struct snd_soc_codec *codec,
|
|||
ret = msm8x16_wcd_spmi_write(reg, 1, &val);
|
||||
else if (MSM8X16_WCD_IS_DIGITAL_REG(reg)) {
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if (atomic_read(&pdata->dis_work_mclk) == false) {
|
||||
if (atomic_read(&pdata->mclk_enabled) == false) {
|
||||
pr_debug("MCLK not enabled %s:\n", __func__);
|
||||
pdata->digital_cdc_clk.clk_val = pdata->mclk_freq;
|
||||
ret = afe_set_digital_codec_core_clock(
|
||||
|
@ -414,8 +414,8 @@ static int __msm8x16_wcd_reg_write(struct snd_soc_codec *codec,
|
|||
}
|
||||
ret = msm8x16_wcd_ahb_write_device(
|
||||
msm8x16_wcd, reg, &val, 1);
|
||||
atomic_set(&pdata->dis_work_mclk, true);
|
||||
schedule_delayed_work(&pdata->enable_mclk_work, 50);
|
||||
atomic_set(&pdata->mclk_enabled, true);
|
||||
schedule_delayed_work(&pdata->disable_mclk_work, 50);
|
||||
err:
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
mutex_unlock(&msm8x16_wcd->io_lock);
|
||||
|
@ -3324,37 +3324,23 @@ int msm8x16_wcd_suspend(struct snd_soc_codec *codec)
|
|||
struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data;
|
||||
|
||||
pdata = snd_soc_card_get_drvdata(codec->card);
|
||||
pr_debug("%s: mclk cnt = %d, dis_work_mclk = %d\n",
|
||||
pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n",
|
||||
__func__, atomic_read(&pdata->mclk_rsc_ref),
|
||||
atomic_read(&pdata->dis_work_mclk));
|
||||
pr_debug("%s: mclk_act = %d\n", __func__,
|
||||
atomic_read(&pdata->mclk_act));
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if ((atomic_read(&pdata->dis_work_mclk) == true) ||
|
||||
(atomic_read(&pdata->mclk_rsc_ref) > 0)) {
|
||||
pdata->digital_cdc_clk.clk_val = 0;
|
||||
afe_set_digital_codec_core_clock(
|
||||
atomic_read(&pdata->mclk_enabled));
|
||||
if (atomic_read(&pdata->mclk_enabled) == true) {
|
||||
cancel_delayed_work_sync(
|
||||
&pdata->disable_mclk_work);
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if (atomic_read(&pdata->mclk_enabled) == true) {
|
||||
pdata->digital_cdc_clk.clk_val = 0;
|
||||
afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
&pdata->digital_cdc_clk);
|
||||
/*
|
||||
* set mclk activity to resource as
|
||||
* it will get updated accordingly going further in this
|
||||
* function.
|
||||
*/
|
||||
atomic_set(&pdata->mclk_act, MCLK_SUS_RSC);
|
||||
if (atomic_read(&pdata->dis_work_mclk) == true) {
|
||||
cancel_delayed_work_sync(
|
||||
&pdata->enable_mclk_work);
|
||||
atomic_set(&pdata->mclk_act, MCLK_SUS_DIS);
|
||||
atomic_set(&pdata->dis_work_mclk, false);
|
||||
atomic_set(&pdata->mclk_enabled, false);
|
||||
}
|
||||
} else
|
||||
/*
|
||||
* mark no activity on mclk in this suspend
|
||||
*/
|
||||
atomic_set(&pdata->mclk_act, MCLK_SUS_NO_ACT);
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
}
|
||||
msm8x16_wcd_disable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3366,34 +3352,6 @@ int msm8x16_wcd_resume(struct snd_soc_codec *codec)
|
|||
|
||||
pdata = snd_soc_card_get_drvdata(codec->card);
|
||||
msm8x16_wcd_enable_static_supplies_to_optimum(msm8x16, msm8x16_pdata);
|
||||
pr_debug("%s: mclk cnt = %d, dis_work_mclk = %d\n",
|
||||
__func__, atomic_read(&pdata->mclk_rsc_ref),
|
||||
atomic_read(&pdata->dis_work_mclk));
|
||||
pr_debug("%s: mclk_act = %d\n", __func__,
|
||||
atomic_read(&pdata->mclk_act));
|
||||
if (atomic_read(&pdata->mclk_act) == MCLK_SUS_NO_ACT)
|
||||
/*
|
||||
* no activity in suspend just return
|
||||
*/
|
||||
return 0;
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if ((atomic_read(&pdata->dis_work_mclk) == false) ||
|
||||
(atomic_read(&pdata->mclk_rsc_ref) > 0)) {
|
||||
pdata->digital_cdc_clk.clk_val = pdata->mclk_freq;
|
||||
afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
&pdata->digital_cdc_clk);
|
||||
if (atomic_read(&pdata->mclk_act) == MCLK_SUS_DIS) {
|
||||
/*
|
||||
* MCLK activity marked as the disabled during suspend
|
||||
* this indicated MCLK was enabled to read and write the
|
||||
* AHB bus.
|
||||
*/
|
||||
atomic_set(&pdata->dis_work_mclk, true);
|
||||
schedule_delayed_work(&pdata->enable_mclk_work, 50);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,10 +130,9 @@ struct msm8916_asoc_mach_data {
|
|||
int us_euro_gpio;
|
||||
int mclk_freq;
|
||||
atomic_t mclk_rsc_ref;
|
||||
atomic_t dis_work_mclk;
|
||||
atomic_t mclk_act;
|
||||
atomic_t mclk_enabled;
|
||||
struct mutex cdc_mclk_mutex;
|
||||
struct delayed_work enable_mclk_work;
|
||||
struct delayed_work disable_mclk_work;
|
||||
struct afe_digital_clk_cfg digital_cdc_clk;
|
||||
};
|
||||
|
||||
|
|
|
@ -601,29 +601,29 @@ static int msm8x16_enable_codec_ext_clk(struct snd_soc_codec *codec,
|
|||
atomic_read(&pdata->mclk_rsc_ref));
|
||||
if (enable) {
|
||||
if (atomic_inc_return(&pdata->mclk_rsc_ref) == 1) {
|
||||
cancel_delayed_work_sync(
|
||||
&pdata->disable_mclk_work);
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if (atomic_read(&pdata->dis_work_mclk) == true) {
|
||||
cancel_delayed_work_sync(
|
||||
&pdata->enable_mclk_work);
|
||||
} else {
|
||||
if (atomic_read(&pdata->mclk_enabled) == false) {
|
||||
pdata->digital_cdc_clk.clk_val =
|
||||
pdata->mclk_freq;
|
||||
afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
&pdata->digital_cdc_clk);
|
||||
atomic_set(&pdata->dis_work_mclk, true);
|
||||
atomic_set(&pdata->mclk_enabled, true);
|
||||
}
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
}
|
||||
} else {
|
||||
cancel_delayed_work_sync(&pdata->disable_mclk_work);
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
atomic_set(&pdata->mclk_rsc_ref, 0);
|
||||
cancel_delayed_work_sync(&pdata->enable_mclk_work);
|
||||
pdata->digital_cdc_clk.clk_val = 0;
|
||||
afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
&pdata->digital_cdc_clk);
|
||||
atomic_set(&pdata->dis_work_mclk, false);
|
||||
if (atomic_read(&pdata->mclk_enabled) == true) {
|
||||
pdata->digital_cdc_clk.clk_val = 0;
|
||||
afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
&pdata->digital_cdc_clk);
|
||||
atomic_set(&pdata->mclk_enabled, false);
|
||||
}
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
}
|
||||
return ret;
|
||||
|
@ -1816,26 +1816,30 @@ static struct snd_soc_card bear_cards[MAX_SND_CARDS] = {
|
|||
},
|
||||
};
|
||||
|
||||
void enable_mclk(struct work_struct *work)
|
||||
void disable_mclk(struct work_struct *work)
|
||||
{
|
||||
struct msm8916_asoc_mach_data *pdata = NULL;
|
||||
struct delayed_work *dwork;
|
||||
int ret = 0;
|
||||
|
||||
pr_debug("%s:\n", __func__);
|
||||
dwork = to_delayed_work(work);
|
||||
pdata = container_of(dwork, struct msm8916_asoc_mach_data,
|
||||
enable_mclk_work);
|
||||
disable_mclk_work);
|
||||
mutex_lock(&pdata->cdc_mclk_mutex);
|
||||
if (atomic_read(&pdata->dis_work_mclk) == true) {
|
||||
pr_debug("clock enabled now disable\n");
|
||||
pr_debug("%s: mclk_enabled %d mclk_rsc_ref %d\n", __func__,
|
||||
atomic_read(&pdata->mclk_enabled),
|
||||
atomic_read(&pdata->mclk_rsc_ref));
|
||||
|
||||
if (atomic_read(&pdata->mclk_enabled) == true
|
||||
&& atomic_read(&pdata->mclk_rsc_ref) == 0) {
|
||||
pr_debug("Disable the mclk\n");
|
||||
pdata->digital_cdc_clk.clk_val = 0;
|
||||
ret = afe_set_digital_codec_core_clock(
|
||||
AFE_PORT_ID_PRIMARY_MI2S_RX,
|
||||
&pdata->digital_cdc_clk);
|
||||
if (ret < 0)
|
||||
pr_err("failed to disable the MCLK\n");
|
||||
atomic_set(&pdata->dis_work_mclk, false);
|
||||
pr_err("%s failed to disable the MCLK\n", __func__);
|
||||
atomic_set(&pdata->mclk_enabled, false);
|
||||
}
|
||||
mutex_unlock(&pdata->cdc_mclk_mutex);
|
||||
}
|
||||
|
@ -2170,10 +2174,10 @@ static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err;
|
||||
/* initialize timer */
|
||||
INIT_DELAYED_WORK(&pdata->enable_mclk_work, enable_mclk);
|
||||
INIT_DELAYED_WORK(&pdata->disable_mclk_work, disable_mclk);
|
||||
mutex_init(&pdata->cdc_mclk_mutex);
|
||||
atomic_set(&pdata->mclk_rsc_ref, 0);
|
||||
atomic_set(&pdata->dis_work_mclk, false);
|
||||
atomic_set(&pdata->mclk_enabled, false);
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(card,
|
||||
"qcom,audio-routing");
|
||||
|
|
Loading…
Reference in a new issue