soc: soundwire: request lpass core and audio votes

Soundwire requires lpass core and lpass audio core to be enabled
to receive interrupts and soundwire register read/writes. Change
enables lpass core and lpass audio core in interrrupt service
routine and during register read/writes.

Change-Id: I56da2fc6efe7dfb1a7d59937b123b3972f633448
Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
This commit is contained in:
Sudheer Papothi
2019-06-14 02:26:52 +05:30
committed by Gerrit - the friendly Code Review server
parent 45d02bcf0b
commit 384addde09
2 changed files with 128 additions and 32 deletions

View File

@@ -65,6 +65,12 @@ enum {
ENABLE_PENDING, ENABLE_PENDING,
DISABLE_PENDING DISABLE_PENDING
}; };
enum {
LPASS_HW_CORE,
LPASS_AUDIO_CORE,
};
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
@@ -242,6 +248,41 @@ static void swrm_reg_dump(struct swr_mstr_ctrl *swrm,
func, reg[i], val[i]); func, reg[i], val[i]);
} }
static int swrm_request_hw_vote(struct swr_mstr_ctrl *swrm,
int core_type, bool enable)
{
int ret = 0;
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 (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);
}
}
return ret;
}
static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable) static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable)
{ {
int ret = 0; int ret = 0;
@@ -1480,14 +1521,13 @@ static irqreturn_t swr_mstr_interrupt_v2(int irq, void *dev)
} }
mutex_lock(&swrm->reslock); mutex_lock(&swrm->reslock);
if (swrm->lpass_core_hw_vote) { if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) {
ret = clk_prepare_enable(swrm->lpass_core_hw_vote); ret = IRQ_NONE;
if (ret < 0) { goto exit;
dev_err(dev, "%s:lpass core hw enable failed\n", }
__func__); if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) {
ret = IRQ_NONE; ret = IRQ_NONE;
goto exit; goto exit;
}
} }
swrm_clk_request(swrm, true); swrm_clk_request(swrm, true);
mutex_unlock(&swrm->reslock); mutex_unlock(&swrm->reslock);
@@ -1656,8 +1696,8 @@ handle_irq:
mutex_lock(&swrm->reslock); mutex_lock(&swrm->reslock);
swrm_clk_request(swrm, false); swrm_clk_request(swrm, false);
if (swrm->lpass_core_hw_vote) swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
clk_disable_unprepare(swrm->lpass_core_hw_vote); swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
exit: exit:
mutex_unlock(&swrm->reslock); mutex_unlock(&swrm->reslock);
swrm_unlock_sleep(swrm); swrm_unlock_sleep(swrm);
@@ -1811,6 +1851,20 @@ static void swrm_device_wakeup_vote(struct swr_master *mstr)
dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__); dev_err(swrm->dev, "%s Failed to hold suspend\n", __func__);
return; 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);
pm_runtime_get_sync(swrm->dev); pm_runtime_get_sync(swrm->dev);
} }
@@ -1825,6 +1879,21 @@ static void swrm_device_wakeup_unvote(struct swr_master *mstr)
} }
pm_runtime_mark_last_busy(swrm->dev); pm_runtime_mark_last_busy(swrm->dev);
pm_runtime_put_autosuspend(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);
--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);
swrm_unlock_sleep(swrm); swrm_unlock_sleep(swrm);
} }
@@ -1949,6 +2018,7 @@ static int swrm_probe(struct platform_device *pdev)
u32 *temp, map_size, map_length, ch_iter = 0, old_port_num = 0; u32 *temp, map_size, map_length, ch_iter = 0, old_port_num = 0;
int ret = 0; int ret = 0;
struct clk *lpass_core_hw_vote = NULL; struct clk *lpass_core_hw_vote = NULL;
struct clk *lpass_core_audio = NULL;
/* Allocate soundwire master driver structure */ /* Allocate soundwire master driver structure */
swrm = devm_kzalloc(&pdev->dev, sizeof(struct swr_mstr_ctrl), swrm = devm_kzalloc(&pdev->dev, sizeof(struct swr_mstr_ctrl),
@@ -2208,6 +2278,17 @@ static int swrm_probe(struct platform_device *pdev)
} }
swrm->lpass_core_hw_vote = lpass_core_hw_vote; swrm->lpass_core_hw_vote = lpass_core_hw_vote;
/* Register LPASS audio core vote */
lpass_core_audio = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote");
if (IS_ERR(lpass_core_audio)) {
ret = PTR_ERR(lpass_core_audio);
dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
__func__, "lpass_core_audio", ret);
lpass_core_audio = NULL;
ret = 0;
}
swrm->lpass_core_audio = lpass_core_audio;
dbgswrm = swrm; dbgswrm = swrm;
debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0); debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
if (!IS_ERR(debugfs_swrm_dent)) { if (!IS_ERR(debugfs_swrm_dent)) {
@@ -2313,7 +2394,8 @@ static int swrm_runtime_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev); struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
int ret = 0; int ret = 0;
bool clk_err = false; bool hw_core_err = false;
bool aud_core_err = false;
struct swr_master *mstr = &swrm->master; struct swr_master *mstr = &swrm->master;
struct swr_device *swr_dev; struct swr_device *swr_dev;
@@ -2321,14 +2403,15 @@ static int swrm_runtime_resume(struct device *dev)
__func__, swrm->state); __func__, swrm->state);
mutex_lock(&swrm->reslock); mutex_lock(&swrm->reslock);
if (swrm->lpass_core_hw_vote) { if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) {
ret = clk_prepare_enable(swrm->lpass_core_hw_vote); dev_err(dev, "%s:lpass core hw enable failed\n",
if (ret < 0) { __func__);
dev_err(dev, "%s:lpass core hw enable failed\n", hw_core_err = true;
__func__); }
ret = 0; if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) {
clk_err = true; dev_err(dev, "%s:lpass audio hw enable failed\n",
} __func__);
aud_core_err = true;
} }
if ((swrm->state == SWR_MSTR_DOWN) || if ((swrm->state == SWR_MSTR_DOWN) ||
@@ -2375,10 +2458,13 @@ static int swrm_runtime_resume(struct device *dev)
swrm->state = SWR_MSTR_UP; swrm->state = SWR_MSTR_UP;
} }
exit: exit:
if (swrm->lpass_core_hw_vote && !clk_err) if (!aud_core_err)
clk_disable_unprepare(swrm->lpass_core_hw_vote); swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
if (!hw_core_err)
swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer); pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
mutex_unlock(&swrm->reslock); mutex_unlock(&swrm->reslock);
return ret; return ret;
} }
@@ -2387,7 +2473,8 @@ static int swrm_runtime_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev); struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev);
int ret = 0; int ret = 0;
bool clk_err = false; bool hw_core_err = false;
bool aud_core_err = false;
struct swr_master *mstr = &swrm->master; struct swr_master *mstr = &swrm->master;
struct swr_device *swr_dev; struct swr_device *swr_dev;
int current_state = 0; int current_state = 0;
@@ -2398,14 +2485,16 @@ static int swrm_runtime_suspend(struct device *dev)
mutex_lock(&swrm->force_down_lock); mutex_lock(&swrm->force_down_lock);
current_state = swrm->state; current_state = swrm->state;
mutex_unlock(&swrm->force_down_lock); mutex_unlock(&swrm->force_down_lock);
if (swrm->lpass_core_hw_vote) {
ret = clk_prepare_enable(swrm->lpass_core_hw_vote); if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) {
if (ret < 0) { dev_err(dev, "%s:lpass core hw enable failed\n",
dev_err(dev, "%s:lpass core hw enable failed\n", __func__);
__func__); hw_core_err = true;
ret = 0; }
clk_err = true; if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) {
} dev_err(dev, "%s:lpass audio hw enable failed\n",
__func__);
aud_core_err = true;
} }
if ((current_state == SWR_MSTR_UP) || if ((current_state == SWR_MSTR_UP) ||
@@ -2436,9 +2525,11 @@ static int swrm_runtime_suspend(struct device *dev)
} }
} }
} else { } else {
mutex_unlock(&swrm->reslock);
/* clock stop sequence */ /* clock stop sequence */
swrm_cmd_fifo_wr_cmd(swrm, 0x2, 0xF, 0xF, swrm_cmd_fifo_wr_cmd(swrm, 0x2, 0xF, 0xF,
SWRS_SCP_CONTROL); SWRS_SCP_CONTROL);
mutex_lock(&swrm->reslock);
usleep_range(100, 105); usleep_range(100, 105);
} }
swrm_clk_request(swrm, false); swrm_clk_request(swrm, false);
@@ -2458,8 +2549,10 @@ static int swrm_runtime_suspend(struct device *dev)
if (current_state != SWR_MSTR_SSR) if (current_state != SWR_MSTR_SSR)
swrm->state = SWR_MSTR_DOWN; swrm->state = SWR_MSTR_DOWN;
exit: exit:
if (swrm->lpass_core_hw_vote && !clk_err) if (!aud_core_err)
clk_disable_unprepare(swrm->lpass_core_hw_vote); swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false);
if (!hw_core_err)
swrm_request_hw_vote(swrm, LPASS_HW_CORE, false);
mutex_unlock(&swrm->reslock); mutex_unlock(&swrm->reslock);
return ret; return ret;
} }

View File

@@ -155,8 +155,11 @@ struct swr_mstr_ctrl {
u32 intr_mask; u32 intr_mask;
struct port_params **port_param; struct port_params **port_param;
struct clk *lpass_core_hw_vote; struct clk *lpass_core_hw_vote;
struct clk *lpass_core_audio;
u8 num_usecase; u8 num_usecase;
u32 swr_irq_wakeup_capable; u32 swr_irq_wakeup_capable;
int hw_core_clk_en;
int aud_core_clk_en;
}; };
#endif /* _SWR_WCD_CTRL_H */ #endif /* _SWR_WCD_CTRL_H */