From 384addde09c350bba491ea5e0c5ac7e7a215c1a8 Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Fri, 14 Jun 2019 02:26:52 +0530 Subject: [PATCH] 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 --- soc/swr-mstr-ctrl.c | 157 +++++++++++++++++++++++++++++++++++--------- soc/swr-mstr-ctrl.h | 3 + 2 files changed, 128 insertions(+), 32 deletions(-) diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 6d1858bf69..f5e503efd1 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -65,6 +65,12 @@ enum { ENABLE_PENDING, DISABLE_PENDING }; + +enum { + LPASS_HW_CORE, + LPASS_AUDIO_CORE, +}; + #define TRUE 1 #define FALSE 0 @@ -242,6 +248,41 @@ static void swrm_reg_dump(struct swr_mstr_ctrl *swrm, 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) { int ret = 0; @@ -1480,14 +1521,13 @@ static irqreturn_t swr_mstr_interrupt_v2(int irq, void *dev) } mutex_lock(&swrm->reslock); - if (swrm->lpass_core_hw_vote) { - ret = clk_prepare_enable(swrm->lpass_core_hw_vote); - if (ret < 0) { - dev_err(dev, "%s:lpass core hw enable failed\n", - __func__); - ret = IRQ_NONE; - goto exit; - } + if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) { + ret = IRQ_NONE; + goto exit; + } + if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) { + ret = IRQ_NONE; + goto exit; } swrm_clk_request(swrm, true); mutex_unlock(&swrm->reslock); @@ -1656,8 +1696,8 @@ handle_irq: mutex_lock(&swrm->reslock); swrm_clk_request(swrm, false); - if (swrm->lpass_core_hw_vote) - clk_disable_unprepare(swrm->lpass_core_hw_vote); + swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false); + swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); exit: mutex_unlock(&swrm->reslock); 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__); 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); } @@ -1825,6 +1879,21 @@ 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); + + --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); } @@ -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; int ret = 0; struct clk *lpass_core_hw_vote = NULL; + struct clk *lpass_core_audio = NULL; /* Allocate soundwire master driver structure */ 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; + /* 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; debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0); 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 swr_mstr_ctrl *swrm = platform_get_drvdata(pdev); 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_device *swr_dev; @@ -2321,14 +2403,15 @@ static int swrm_runtime_resume(struct device *dev) __func__, swrm->state); mutex_lock(&swrm->reslock); - if (swrm->lpass_core_hw_vote) { - ret = clk_prepare_enable(swrm->lpass_core_hw_vote); - if (ret < 0) { - dev_err(dev, "%s:lpass core hw enable failed\n", - __func__); - ret = 0; - clk_err = true; - } + if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) { + dev_err(dev, "%s:lpass core hw enable failed\n", + __func__); + hw_core_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 ((swrm->state == SWR_MSTR_DOWN) || @@ -2375,10 +2458,13 @@ static int swrm_runtime_resume(struct device *dev) swrm->state = SWR_MSTR_UP; } exit: - if (swrm->lpass_core_hw_vote && !clk_err) - clk_disable_unprepare(swrm->lpass_core_hw_vote); + if (!aud_core_err) + 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); mutex_unlock(&swrm->reslock); + return ret; } @@ -2387,7 +2473,8 @@ static int swrm_runtime_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev); 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_device *swr_dev; int current_state = 0; @@ -2398,14 +2485,16 @@ static int swrm_runtime_suspend(struct device *dev) mutex_lock(&swrm->force_down_lock); current_state = swrm->state; mutex_unlock(&swrm->force_down_lock); - if (swrm->lpass_core_hw_vote) { - ret = clk_prepare_enable(swrm->lpass_core_hw_vote); - if (ret < 0) { - dev_err(dev, "%s:lpass core hw enable failed\n", - __func__); - ret = 0; - clk_err = true; - } + + if (swrm_request_hw_vote(swrm, LPASS_HW_CORE, true)) { + dev_err(dev, "%s:lpass core hw enable failed\n", + __func__); + hw_core_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) || @@ -2436,9 +2525,11 @@ static int swrm_runtime_suspend(struct device *dev) } } } else { + mutex_unlock(&swrm->reslock); /* clock stop sequence */ swrm_cmd_fifo_wr_cmd(swrm, 0x2, 0xF, 0xF, SWRS_SCP_CONTROL); + mutex_lock(&swrm->reslock); usleep_range(100, 105); } swrm_clk_request(swrm, false); @@ -2458,8 +2549,10 @@ static int swrm_runtime_suspend(struct device *dev) if (current_state != SWR_MSTR_SSR) swrm->state = SWR_MSTR_DOWN; exit: - if (swrm->lpass_core_hw_vote && !clk_err) - clk_disable_unprepare(swrm->lpass_core_hw_vote); + if (!aud_core_err) + 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); return ret; } diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index 4a48571e90..e05ede258d 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -155,8 +155,11 @@ struct swr_mstr_ctrl { u32 intr_mask; struct port_params **port_param; struct clk *lpass_core_hw_vote; + struct clk *lpass_core_audio; u8 num_usecase; u32 swr_irq_wakeup_capable; + int hw_core_clk_en; + int aud_core_clk_en; }; #endif /* _SWR_WCD_CTRL_H */