audio-kernel: Synchronize hw vote and unvote requests
HW vote and unvote is currently called from multiple clients leading to synchronization issues during SSR/PDR scenarios. Synchronize all the vote requests by using digital codec resource manager. Change-Id: I7e63f69ab5d761a3bb4c7ce70bbef2e8bfd76cfb Signed-off-by: Aditya Bavanari <abavanar@codeaurora.org>
This commit is contained in:
parent
9e8e0f6d80
commit
bb981b707e
9 changed files with 192 additions and 18 deletions
|
@ -14,6 +14,7 @@
|
|||
#include <soc/snd_event.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <soc/swr-common.h>
|
||||
#include <dsp/digital-cdc-rsc-mgr.h>
|
||||
#include "bolero-cdc.h"
|
||||
#include "internal.h"
|
||||
#include "bolero-clk-rsc.h"
|
||||
|
@ -1379,7 +1380,7 @@ int bolero_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
if (priv->core_hw_vote_count == 0) {
|
||||
ret = clk_prepare_enable(priv->lpass_core_hw_vote);
|
||||
ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_core_hw_vote);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s:lpass core hw enable failed\n",
|
||||
__func__);
|
||||
|
@ -1397,7 +1398,7 @@ int bolero_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
if (priv->core_audio_vote_count == 0) {
|
||||
ret = clk_prepare_enable(priv->lpass_audio_hw_vote);
|
||||
ret = digital_cdc_rsc_mgr_hw_vote_enable(priv->lpass_audio_hw_vote);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s:lpass audio hw enable failed\n",
|
||||
__func__);
|
||||
|
@ -1422,7 +1423,8 @@ int bolero_runtime_suspend(struct device *dev)
|
|||
mutex_lock(&priv->vote_lock);
|
||||
if (priv->lpass_core_hw_vote != NULL) {
|
||||
if (--priv->core_hw_vote_count == 0)
|
||||
clk_disable_unprepare(priv->lpass_core_hw_vote);
|
||||
digital_cdc_rsc_mgr_hw_vote_disable(
|
||||
priv->lpass_core_hw_vote);
|
||||
if (priv->core_hw_vote_count < 0)
|
||||
priv->core_hw_vote_count = 0;
|
||||
} else {
|
||||
|
@ -1434,7 +1436,8 @@ int bolero_runtime_suspend(struct device *dev)
|
|||
|
||||
if (priv->lpass_audio_hw_vote != NULL) {
|
||||
if (--priv->core_audio_vote_count == 0)
|
||||
clk_disable_unprepare(priv->lpass_audio_hw_vote);
|
||||
digital_cdc_rsc_mgr_hw_vote_disable(
|
||||
priv->lpass_audio_hw_vote);
|
||||
if (priv->core_audio_vote_count < 0)
|
||||
priv->core_audio_vote_count = 0;
|
||||
} else {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <asoc/msm-cdc-pinctrl.h>
|
||||
#include <soc/swr-common.h>
|
||||
#include <soc/swr-wcd.h>
|
||||
#include <dsp/digital-cdc-rsc-mgr.h>
|
||||
#include "bolero-cdc.h"
|
||||
#include "bolero-cdc-registers.h"
|
||||
#include "bolero-clk-rsc.h"
|
||||
|
@ -444,7 +445,8 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
|
|||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (va_priv->lpass_audio_hw_vote) {
|
||||
ret = clk_prepare_enable(va_priv->lpass_audio_hw_vote);
|
||||
ret = digital_cdc_rsc_mgr_hw_vote_enable(
|
||||
va_priv->lpass_audio_hw_vote);
|
||||
if (ret)
|
||||
dev_err(va_dev,
|
||||
"%s: lpass audio hw enable failed\n",
|
||||
|
@ -467,7 +469,8 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w,
|
|||
if (bolero_tx_clk_switch(component, CLK_SRC_TX_RCG))
|
||||
dev_dbg(va_dev, "%s: clock switch failed\n",__func__);
|
||||
if (va_priv->lpass_audio_hw_vote)
|
||||
clk_disable_unprepare(va_priv->lpass_audio_hw_vote);
|
||||
digital_cdc_rsc_mgr_hw_vote_disable(
|
||||
va_priv->lpass_audio_hw_vote);
|
||||
break;
|
||||
default:
|
||||
dev_err(va_priv->dev,
|
||||
|
|
|
@ -184,6 +184,10 @@ ifdef CONFIG_VOICE_MHI
|
|||
Q6_OBJS += voice_mhi.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DIGITAL_CDC_RSC_MGR
|
||||
Q6_OBJS += digital-cdc-rsc-mgr.o
|
||||
endif
|
||||
|
||||
LINUX_INC += -Iinclude/linux
|
||||
|
||||
INCS += $(COMMON_INC) \
|
||||
|
|
100
dsp/digital-cdc-rsc-mgr.c
Normal file
100
dsp/digital-cdc-rsc-mgr.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <dsp/digital-cdc-rsc-mgr.h>
|
||||
|
||||
struct mutex hw_vote_lock;
|
||||
static bool is_init_done;
|
||||
|
||||
/**
|
||||
* digital_cdc_rsc_mgr_hw_vote_enable - Enables hw vote in DSP
|
||||
*
|
||||
* @vote_handle: vote handle for which voting needs to be done
|
||||
*
|
||||
* Returns 0 on success or -EINVAL/error code on failure
|
||||
*/
|
||||
int digital_cdc_rsc_mgr_hw_vote_enable(struct clk* vote_handle)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!is_init_done || vote_handle == NULL) {
|
||||
pr_err_ratelimited("%s: init failed or vote handle NULL\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&hw_vote_lock);
|
||||
ret = clk_prepare_enable(vote_handle);
|
||||
mutex_unlock(&hw_vote_lock);
|
||||
|
||||
pr_debug("%s: return %d\n", __func__, ret);
|
||||
trace_printk("%s: return %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_enable);
|
||||
|
||||
/**
|
||||
* digital_cdc_rsc_mgr_hw_vote_disable - Disables hw vote in DSP
|
||||
*
|
||||
* @vote_handle: vote handle for which voting needs to be disabled
|
||||
*
|
||||
*/
|
||||
void digital_cdc_rsc_mgr_hw_vote_disable(struct clk* vote_handle)
|
||||
{
|
||||
if (!is_init_done || vote_handle == NULL) {
|
||||
pr_err_ratelimited("%s: init failed or vote handle NULL\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&hw_vote_lock);
|
||||
clk_disable_unprepare(vote_handle);
|
||||
mutex_unlock(&hw_vote_lock);
|
||||
trace_printk("%s\n", __func__);
|
||||
}
|
||||
EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_disable);
|
||||
|
||||
/**
|
||||
* digital_cdc_rsc_mgr_hw_vote_reset - Resets hw vote count
|
||||
*
|
||||
*/
|
||||
void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (!is_init_done || vote_handle == NULL) {
|
||||
pr_err_ratelimited("%s: init failed or vote handle NULL\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&hw_vote_lock);
|
||||
while (__clk_is_enabled(vote_handle)) {
|
||||
clk_disable_unprepare(vote_handle);
|
||||
count++;
|
||||
}
|
||||
pr_debug("%s: Vote count after SSR: %d\n", __func__, count);
|
||||
trace_printk("%s: Vote count after SSR: %d\n", __func__, count);
|
||||
|
||||
while (count--)
|
||||
clk_prepare_enable(vote_handle);
|
||||
mutex_unlock(&hw_vote_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_reset);
|
||||
|
||||
void digital_cdc_rsc_mgr_init()
|
||||
{
|
||||
mutex_init(&hw_vote_lock);
|
||||
is_init_done = true;
|
||||
}
|
||||
|
||||
void digital_cdc_rsc_mgr_exit()
|
||||
{
|
||||
mutex_destroy(&hw_vote_lock);
|
||||
is_init_done = false;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017, 2019-2020 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -24,11 +24,13 @@ static int __init audio_q6_init(void)
|
|||
avtimer_init();
|
||||
msm_mdf_init();
|
||||
voice_mhi_init();
|
||||
digital_cdc_rsc_mgr_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit audio_q6_exit(void)
|
||||
{
|
||||
digital_cdc_rsc_mgr_exit();
|
||||
msm_mdf_exit();
|
||||
avtimer_exit();
|
||||
audio_slimslave_exit();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __Q6_INIT_H__
|
||||
|
@ -80,5 +80,19 @@ static inline void voice_mhi_exit(void)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DIGITAL_CDC_RSC_MGR
|
||||
void digital_cdc_rsc_mgr_init(void);
|
||||
void digital_cdc_rsc_mgr_exit(void);
|
||||
#else
|
||||
static inline void digital_cdc_rsc_mgr_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void digital_cdc_rsc_mgr_exit(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_DIGITAL_CDC_RSC_MGR */
|
||||
|
||||
#endif
|
||||
|
||||
|
|
32
include/dsp/digital-cdc-rsc-mgr.h
Normal file
32
include/dsp/digital-cdc-rsc-mgr.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef DIGITAL_CDC_RSC_MGR_H
|
||||
#define DIGITAL_CDC_RSC_MGR_H
|
||||
|
||||
#ifdef CONFIG_DIGITAL_CDC_RSC_MGR
|
||||
|
||||
int digital_cdc_rsc_mgr_hw_vote_enable(struct clk* vote_handle);
|
||||
void digital_cdc_rsc_mgr_hw_vote_disable(struct clk* vote_handle);
|
||||
void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle);
|
||||
|
||||
#else
|
||||
|
||||
static inline int digital_cdc_rsc_mgr_hw_vote_enable(struct clk* vote_handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void digital_cdc_rsc_mgr_hw_vote_disable(struct clk* vote_handle)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DIGITAL_CDC_RSC_MGR */
|
||||
|
||||
#endif /* DIGITAL_CDC_RSC_MGR_H */
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <soc/snd_event.h>
|
||||
#include <dsp/digital-cdc-rsc-mgr.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <dsp/audio_notifier.h>
|
||||
|
||||
|
@ -469,6 +470,7 @@ static int lpi_notifier_service_cb(struct notifier_block *this,
|
|||
unsigned long opcode, void *ptr)
|
||||
{
|
||||
static bool initial_boot = true;
|
||||
struct lpi_gpio_state *state = dev_get_drvdata(lpi_dev);
|
||||
|
||||
pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
|
||||
|
||||
|
@ -484,6 +486,17 @@ static int lpi_notifier_service_cb(struct notifier_block *this,
|
|||
case AUDIO_NOTIFIER_SERVICE_UP:
|
||||
if (initial_boot)
|
||||
initial_boot = false;
|
||||
|
||||
/* Reset HW votes after SSR */
|
||||
if (!lpi_dev_up) {
|
||||
if (state->lpass_core_hw_vote)
|
||||
digital_cdc_rsc_mgr_hw_vote_reset(
|
||||
state->lpass_core_hw_vote);
|
||||
if (state->lpass_audio_hw_vote)
|
||||
digital_cdc_rsc_mgr_hw_vote_reset(
|
||||
state->lpass_audio_hw_vote);
|
||||
}
|
||||
|
||||
lpi_dev_up = true;
|
||||
snd_event_notify(lpi_dev, SND_EVENT_UP);
|
||||
break;
|
||||
|
@ -870,7 +883,7 @@ int lpi_pinctrl_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
mutex_lock(&state->core_hw_vote_lock);
|
||||
ret = clk_prepare_enable(hw_vote);
|
||||
ret = digital_cdc_rsc_mgr_hw_vote_enable(hw_vote);
|
||||
if (ret < 0) {
|
||||
pm_runtime_set_autosuspend_delay(dev,
|
||||
LPI_AUTO_SUSPEND_DELAY_ERROR);
|
||||
|
@ -906,7 +919,7 @@ int lpi_pinctrl_runtime_suspend(struct device *dev)
|
|||
|
||||
mutex_lock(&state->core_hw_vote_lock);
|
||||
if (state->core_hw_vote_status) {
|
||||
clk_disable_unprepare(hw_vote);
|
||||
digital_cdc_rsc_mgr_hw_vote_disable(hw_vote);
|
||||
state->core_hw_vote_status = false;
|
||||
}
|
||||
mutex_unlock(&state->core_hw_vote_lock);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <soc/swr-common.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <dsp/msm-audio-event-notify.h>
|
||||
#include <dsp/digital-cdc-rsc-mgr.h>
|
||||
#include "swrm_registers.h"
|
||||
#include "swr-mstr-ctrl.h"
|
||||
|
||||
|
@ -378,8 +379,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
|
|||
}
|
||||
if (++swrm->hw_core_clk_en == 1) {
|
||||
ret =
|
||||
clk_prepare_enable(
|
||||
swrm->lpass_core_hw_vote);
|
||||
digital_cdc_rsc_mgr_hw_vote_enable(
|
||||
swrm->lpass_core_hw_vote);
|
||||
if (ret < 0) {
|
||||
dev_err(swrm->dev,
|
||||
"%s:lpass core hw enable failed\n",
|
||||
|
@ -392,8 +393,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
|
|||
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);
|
||||
digital_cdc_rsc_mgr_hw_vote_disable(
|
||||
swrm->lpass_core_hw_vote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -410,8 +411,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
|
|||
}
|
||||
if (++swrm->aud_core_clk_en == 1) {
|
||||
ret =
|
||||
clk_prepare_enable(
|
||||
swrm->lpass_core_audio);
|
||||
digital_cdc_rsc_mgr_hw_vote_enable(
|
||||
swrm->lpass_core_audio);
|
||||
if (ret < 0) {
|
||||
dev_err(swrm->dev,
|
||||
"%s:lpass audio hw enable failed\n",
|
||||
|
@ -424,8 +425,8 @@ static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
|
|||
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);
|
||||
digital_cdc_rsc_mgr_hw_vote_disable(
|
||||
swrm->lpass_core_audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3334,6 +3335,8 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
|
|||
swrm_device_down(&pdev->dev);
|
||||
mutex_lock(&swrm->devlock);
|
||||
swrm->dev_up = false;
|
||||
swrm->hw_core_clk_en = 0;
|
||||
swrm->aud_core_clk_en = 0;
|
||||
mutex_unlock(&swrm->devlock);
|
||||
mutex_lock(&swrm->reslock);
|
||||
swrm->state = SWR_MSTR_SSR;
|
||||
|
|
Loading…
Add table
Reference in a new issue