From 6013969c2fda99b02e6b71985b34926eeaf7a9d7 Mon Sep 17 00:00:00 2001 From: Aviral Gupta Date: Fri, 20 Jun 2014 19:40:46 +0530 Subject: 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 --- sound/soc/codecs/msm8x16-wcd.c | 78 ++++++++++-------------------------------- sound/soc/codecs/msm8x16-wcd.h | 5 ++- sound/soc/msm/msm8x16.c | 49 ++++++++++++++------------ 3 files changed, 47 insertions(+), 85 deletions(-) diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c index dda668bf5fdb..c88cc472e7b8 100644 --- a/sound/soc/codecs/msm8x16-wcd.c +++ b/sound/soc/codecs/msm8x16-wcd.c @@ -347,7 +347,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, @@ -359,8 +359,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); @@ -397,7 +397,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( @@ -410,8 +410,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); @@ -3323,37 +3323,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" - "mclk_act = %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), - 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; } @@ -3365,34 +3351,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" - "mclk_act = %d\n", - __func__, atomic_read(&pdata->mclk_rsc_ref), - atomic_read(&pdata->dis_work_mclk), - 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; } diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h index 7d497299264e..3cceb0a37fca 100644 --- a/sound/soc/codecs/msm8x16-wcd.h +++ b/sound/soc/codecs/msm8x16-wcd.h @@ -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; }; diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index a17cdfe1a6ef..18381a28d46e 100644 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -593,28 +593,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 { - pdata->digital_cdc_clk.clk_val = pdata->mclk_freq; + 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; @@ -1820,26 +1821,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); } @@ -2171,10 +2176,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"); -- cgit v1.2.3