From f1c3f00c054f0e15f750b9c192da835c1d9c5826 Mon Sep 17 00:00:00 2001 From: Aditya Bavanari Date: Sun, 22 Dec 2019 17:14:15 +0530 Subject: [PATCH 1/2] soc: Vote or unvote core and audio hw based on count In order to synchronize the core and audio hw votes in SSR use cases, vote or unvote for these based on clock count. Change-Id: I0047e2cc689cc96b34992e5f6f59dae84d1d4e4b Signed-off-by: Aditya Bavanari --- soc/swr-mstr-ctrl.c | 134 ++++++++++++++++++++++++++++---------------- soc/swr-mstr-ctrl.h | 1 + 2 files changed, 88 insertions(+), 47 deletions(-) diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 830e8cd70862..58a77138ff7f 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -389,33 +389,77 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm, { int ret = 0; + mutex_lock(&swrm->devlock); if (core_type == LPASS_HW_CORE) { if (swrm->lpass_core_hw_vote) { if (enable) { - ret = - clk_prepare_enable(swrm->lpass_core_hw_vote); - if (ret < 0) - dev_err(swrm->dev, - "%s:lpass core hw enable failed\n", - __func__); - } else - clk_disable_unprepare(swrm->lpass_core_hw_vote); + if (!swrm->dev_up) { + dev_dbg(swrm->dev, "%s: device is down or SSR state\n", + __func__); + trace_printk("%s: device is down or SSR state\n", + __func__); + mutex_unlock(&swrm->devlock); + return -ENODEV; + } + if (++swrm->hw_core_clk_en == 1) { + ret = + clk_prepare_enable( + swrm->lpass_core_hw_vote); + if (ret < 0) { + dev_err(swrm->dev, + "%s:lpass core hw enable failed\n", + __func__); + --swrm->hw_core_clk_en; + } + } + } else { + --swrm->hw_core_clk_en; + if (swrm->hw_core_clk_en < 0) + swrm->hw_core_clk_en = 0; + else if (swrm->hw_core_clk_en == 0) + clk_disable_unprepare( + swrm->lpass_core_hw_vote); + } } } if (core_type == LPASS_AUDIO_CORE) { if (swrm->lpass_core_audio) { if (enable) { - ret = - clk_prepare_enable(swrm->lpass_core_audio); - if (ret < 0) - dev_err(swrm->dev, - "%s:lpass audio hw enable failed\n", - __func__); - } else - clk_disable_unprepare(swrm->lpass_core_audio); + if (!swrm->dev_up) { + dev_dbg(swrm->dev, "%s: device is down or SSR state\n", + __func__); + trace_printk("%s: device is down or SSR state\n", + __func__); + mutex_unlock(&swrm->devlock); + return -ENODEV; + } + if (++swrm->aud_core_clk_en == 1) { + ret = + clk_prepare_enable( + swrm->lpass_core_audio); + if (ret < 0) { + dev_err(swrm->dev, + "%s:lpass audio hw enable failed\n", + __func__); + --swrm->aud_core_clk_en; + } + } + } else { + --swrm->aud_core_clk_en; + if (swrm->aud_core_clk_en < 0) + swrm->aud_core_clk_en = 0; + else if (swrm->aud_core_clk_en == 0) + clk_disable_unprepare( + swrm->lpass_core_audio); + } } } + mutex_unlock(&swrm->devlock); + dev_dbg(swrm->dev, "%s: hw_clk_en: %d audio_core_clk_en: %d\n", + __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en); + trace_printk("%s: hw_clk_en: %d audio_core_clk_en: %d\n", + __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en); return ret; } @@ -1755,6 +1799,7 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev) return IRQ_NONE; } + mutex_lock(&swrm->ssr_lock); mutex_lock(&swrm->reslock); if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) { ret = IRQ_NONE; @@ -1979,6 +2024,7 @@ err_audio_hw_vote: swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); exit: mutex_unlock(&swrm->reslock); + mutex_unlock(&swrm->ssr_lock); swrm_unlock_sleep(swrm); trace_printk("%s exit\n", __func__); return ret; @@ -2155,22 +2201,15 @@ static void swrm_device_wakeup_vote(struct swr_master *mstr) dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__); return; } - if (++swrm->hw_core_clk_en == 1) - if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) { - dev_err(swrm->dev, "%s:lpass core hw enable failed\n", - __func__); - --swrm->hw_core_clk_en; - } - if ( ++swrm->aud_core_clk_en == 1) - if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) { - dev_err(swrm->dev, "%s:lpass audio hw enable failed\n", - __func__); - --swrm->aud_core_clk_en; - } - dev_dbg(swrm->dev, "%s: hw_clk_en: %d audio_core_clk_en: %d\n", - __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en); - trace_printk("%s: hw_clk_en: %d audio_core_clk_en: %d\n", - __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en); + mutex_lock(&swrm->reslock); + if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) + dev_err(swrm->dev, "%s:lpass core hw enable failed\n", + __func__); + if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) + dev_err(swrm->dev, "%s:lpass audio hw enable failed\n", + __func__); + mutex_unlock(&swrm->reslock); + pm_runtime_get_sync(swrm->dev); } @@ -2185,22 +2224,11 @@ static void swrm_device_wakeup_unvote(struct swr_master *mstr) } pm_runtime_mark_last_busy(swrm->dev); pm_runtime_put_autosuspend(swrm->dev); - dev_dbg(swrm->dev, "%s: hw_clk_en: %d audio_core_clk_en: %d\n", - __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en); - trace_printk("%s: hw_clk_en: %d audio_core_clk_en: %d\n", - __func__, swrm->hw_core_clk_en, swrm->aud_core_clk_en); - --swrm->aud_core_clk_en; - if (swrm->aud_core_clk_en < 0) - swrm->aud_core_clk_en = 0; - else if (swrm->aud_core_clk_en == 0) - swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false); - - --swrm->hw_core_clk_en; - if (swrm->hw_core_clk_en < 0) - swrm->hw_core_clk_en = 0; - else if (swrm->hw_core_clk_en == 0) - swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); + mutex_lock(&swrm->reslock); + swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false); + swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); + mutex_unlock(&swrm->reslock); swrm_unlock_sleep(swrm); } @@ -2536,6 +2564,7 @@ static int swrm_probe(struct platform_device *pdev) mutex_init(&swrm->clklock); mutex_init(&swrm->devlock); mutex_init(&swrm->pm_lock); + mutex_init(&swrm->ssr_lock); swrm->wlock_holders = 0; swrm->pm_state = SWRM_PM_SLEEPABLE; init_waitqueue_head(&swrm->pm_wq); @@ -2690,6 +2719,7 @@ err_irq_fail: mutex_destroy(&swrm->iolock); mutex_destroy(&swrm->clklock); mutex_destroy(&swrm->pm_lock); + mutex_destroy(&swrm->ssr_lock); pm_qos_remove_request(&swrm->pm_qos_req); err_pdata_fail: @@ -2723,6 +2753,7 @@ static int swrm_remove(struct platform_device *pdev) mutex_destroy(&swrm->clklock); mutex_destroy(&swrm->force_down_lock); mutex_destroy(&swrm->pm_lock); + mutex_destroy(&swrm->ssr_lock); pm_qos_remove_request(&swrm->pm_qos_req); devm_kfree(&pdev->dev, swrm); return 0; @@ -3200,12 +3231,21 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) break; case SWR_DEVICE_SSR_DOWN: trace_printk("%s: swr device down called\n", __func__); + mutex_lock(&swrm->ssr_lock); + mutex_lock(&swrm->mlock); + if (swrm->state == SWR_MSTR_DOWN) + dev_dbg(swrm->dev, "%s:SWR master is already Down:%d\n", + __func__, swrm->state); + else + swrm_device_down(&pdev->dev); mutex_lock(&swrm->devlock); swrm->dev_up = false; mutex_unlock(&swrm->devlock); mutex_lock(&swrm->reslock); swrm->state = SWR_MSTR_SSR; mutex_unlock(&swrm->reslock); + mutex_unlock(&swrm->mlock); + mutex_unlock(&swrm->ssr_lock); break; case SWR_DEVICE_SSR_UP: /* wait for clk voting to be zero */ diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index c8444032d8a3..c9f193c08eb6 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -133,6 +133,7 @@ struct swr_mstr_ctrl { struct mutex reslock; struct mutex pm_lock; struct mutex irq_lock; + struct mutex ssr_lock; u32 swrm_base_reg; char __iomem *swrm_dig_base; char __iomem *swrm_hctl_reg; From 56ac5b3acedafba922242b4d54b1d5b0e2bbf476 Mon Sep 17 00:00:00 2001 From: Aditya Bavanari Date: Thu, 5 Mar 2020 12:31:39 +0530 Subject: [PATCH 2/2] soc: swr-mstr-ctrl: Remove ssr_lock handling During SSR and headset detection/removal interrupt concurrencies, ssr_lock can lead to serv reg ack timeout issues. Remove this synchronization to avoid this issue. Change-Id: I242a013a7e9d833db21d737cbdfea2d84bbd29fa Signed-off-by: Aditya Bavanari Signed-off-by: Akhil Karuturi --- soc/swr-mstr-ctrl.c | 7 ------- soc/swr-mstr-ctrl.h | 1 - 2 files changed, 8 deletions(-) diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 58a77138ff7f..2964d3bc1e9c 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -1799,7 +1799,6 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev) return IRQ_NONE; } - mutex_lock(&swrm->ssr_lock); mutex_lock(&swrm->reslock); if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) { ret = IRQ_NONE; @@ -2024,7 +2023,6 @@ err_audio_hw_vote: swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); exit: mutex_unlock(&swrm->reslock); - mutex_unlock(&swrm->ssr_lock); swrm_unlock_sleep(swrm); trace_printk("%s exit\n", __func__); return ret; @@ -2564,7 +2562,6 @@ static int swrm_probe(struct platform_device *pdev) mutex_init(&swrm->clklock); mutex_init(&swrm->devlock); mutex_init(&swrm->pm_lock); - mutex_init(&swrm->ssr_lock); swrm->wlock_holders = 0; swrm->pm_state = SWRM_PM_SLEEPABLE; init_waitqueue_head(&swrm->pm_wq); @@ -2719,7 +2716,6 @@ err_irq_fail: mutex_destroy(&swrm->iolock); mutex_destroy(&swrm->clklock); mutex_destroy(&swrm->pm_lock); - mutex_destroy(&swrm->ssr_lock); pm_qos_remove_request(&swrm->pm_qos_req); err_pdata_fail: @@ -2753,7 +2749,6 @@ static int swrm_remove(struct platform_device *pdev) mutex_destroy(&swrm->clklock); mutex_destroy(&swrm->force_down_lock); mutex_destroy(&swrm->pm_lock); - mutex_destroy(&swrm->ssr_lock); pm_qos_remove_request(&swrm->pm_qos_req); devm_kfree(&pdev->dev, swrm); return 0; @@ -3231,7 +3226,6 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) break; case SWR_DEVICE_SSR_DOWN: trace_printk("%s: swr device down called\n", __func__); - mutex_lock(&swrm->ssr_lock); mutex_lock(&swrm->mlock); if (swrm->state == SWR_MSTR_DOWN) dev_dbg(swrm->dev, "%s:SWR master is already Down:%d\n", @@ -3245,7 +3239,6 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) swrm->state = SWR_MSTR_SSR; mutex_unlock(&swrm->reslock); mutex_unlock(&swrm->mlock); - mutex_unlock(&swrm->ssr_lock); break; case SWR_DEVICE_SSR_UP: /* wait for clk voting to be zero */ diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index c9f193c08eb6..c8444032d8a3 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -133,7 +133,6 @@ struct swr_mstr_ctrl { struct mutex reslock; struct mutex pm_lock; struct mutex irq_lock; - struct mutex ssr_lock; u32 swrm_base_reg; char __iomem *swrm_dig_base; char __iomem *swrm_hctl_reg;