diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2020-03-19 19:30:57 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2020-03-19 19:30:57 -0700 |
commit | 3b497dc42c40b14bd740efa7dc023a9c87f14176 (patch) | |
tree | c5fd5048f1fa30abc2c95ad16055c786e7030d3f | |
parent | ac42fe0d68e839d0240031ae0d91ff3975b9bc5c (diff) | |
parent | b51434354d9c6d47fd5cfa04eb71353cbd9aac0b (diff) | |
download | msm-extra-3b497dc42c40b14bd740efa7dc023a9c87f14176.tar.gz |
Merge b51434354d9c6d47fd5cfa04eb71353cbd9aac0b on remote branch
Change-Id: Iee7de7e9ab5fa01478b68a82bb2d77b22e3f21dc
32 files changed, 805 insertions, 258 deletions
diff --git a/4.0/asoc/codecs/bolero/bolero-cdc.c b/4.0/asoc/codecs/bolero/bolero-cdc.c index ce646fcc..5ddc674e 100644 --- a/4.0/asoc/codecs/bolero/bolero-cdc.c +++ b/4.0/asoc/codecs/bolero/bolero-cdc.c @@ -99,24 +99,32 @@ static int __bolero_reg_read(struct bolero_priv *priv, goto ssr_err; } - if (priv->macro_params[VA_MACRO].dev) + if (priv->macro_params[VA_MACRO].dev) { pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev); + if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev)) + goto ssr_err; + } - /* Request Clk before register access */ - ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + if (priv->version < BOLERO_VERSION_2_0) { + /* Request Clk before register access */ + ret = bolero_clk_rsc_request_clock( + priv->macro_params[macro_id].dev, priv->macro_params[macro_id].default_clk_id, priv->macro_params[macro_id].clk_id_req, true); - if (ret < 0) { - dev_err_ratelimited(priv->dev, - "%s: Failed to enable clock, ret:%d\n", __func__, ret); - goto err; + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: Failed to enable clock, ret:%d\n", + __func__, ret); + goto err; + } } bolero_ahb_read_device( priv->macro_params[macro_id].io_base, reg, val); - bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + if (priv->version < BOLERO_VERSION_2_0) + bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, priv->macro_params[macro_id].default_clk_id, priv->macro_params[macro_id].clk_id_req, false); @@ -143,24 +151,32 @@ static int __bolero_reg_write(struct bolero_priv *priv, ret = -EINVAL; goto ssr_err; } - if (priv->macro_params[VA_MACRO].dev) + if (priv->macro_params[VA_MACRO].dev) { pm_runtime_get_sync(priv->macro_params[VA_MACRO].dev); + if (!bolero_check_core_votes(priv->macro_params[VA_MACRO].dev)) + goto ssr_err; + } - /* Request Clk before register access */ - ret = bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + if (priv->version < BOLERO_VERSION_2_0) { + /* Request Clk before register access */ + ret = bolero_clk_rsc_request_clock( + priv->macro_params[macro_id].dev, priv->macro_params[macro_id].default_clk_id, priv->macro_params[macro_id].clk_id_req, true); - if (ret < 0) { - dev_err_ratelimited(priv->dev, - "%s: Failed to enable clock, ret:%d\n", __func__, ret); - goto err; + if (ret < 0) { + dev_err_ratelimited(priv->dev, + "%s: Failed to enable clock, ret:%d\n", + __func__, ret); + goto err; + } } bolero_ahb_write_device( priv->macro_params[macro_id].io_base, reg, val); - bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, + if (priv->version < BOLERO_VERSION_2_0) + bolero_clk_rsc_request_clock(priv->macro_params[macro_id].dev, priv->macro_params[macro_id].default_clk_id, priv->macro_params[macro_id].clk_id_req, false); @@ -1078,6 +1094,7 @@ int bolero_register_event_listener(struct snd_soc_codec *codec, return ret; } EXPORT_SYMBOL(bolero_register_event_listener); + static int bolero_soc_codec_probe(struct snd_soc_codec *codec) { struct bolero_priv *priv = dev_get_drvdata(codec->dev); @@ -1276,6 +1293,13 @@ static int bolero_probe(struct platform_device *pdev) __func__); ret = 0; } + if (priv->version == BOLERO_VERSION_2_1) { + bolero_reg_access[TX_MACRO] = bolero_tx_reg_access_v2; + bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v2; + } else if (priv->version == BOLERO_VERSION_2_0) { + bolero_reg_access[VA_MACRO] = bolero_va_reg_access_v3; + } + priv->dev = &pdev->dev; priv->dev_up = true; priv->initial_boot = true; @@ -1342,6 +1366,7 @@ static int bolero_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM int bolero_runtime_resume(struct device *dev) { struct bolero_priv *priv = dev_get_drvdata(dev->parent); @@ -1423,6 +1448,7 @@ int bolero_runtime_suspend(struct device *dev) return 0; } EXPORT_SYMBOL(bolero_runtime_suspend); +#endif /* CONFIG_PM */ bool bolero_check_core_votes(struct device *dev) { diff --git a/4.0/asoc/codecs/bolero/rx-macro.c b/4.0/asoc/codecs/bolero/rx-macro.c index aaf39dd9..cfba3d5b 100644 --- a/4.0/asoc/codecs/bolero/rx-macro.c +++ b/4.0/asoc/codecs/bolero/rx-macro.c @@ -1367,9 +1367,6 @@ static int rx_macro_event_handler(struct snd_soc_codec *codec, u16 event, if (rx_priv->swr_ctrl_data) { swrm_wcd_notify( rx_priv->swr_ctrl_data[0].rx_swr_pdev, - SWR_DEVICE_DOWN, NULL); - swrm_wcd_notify( - rx_priv->swr_ctrl_data[0].rx_swr_pdev, SWR_DEVICE_SSR_DOWN, NULL); } if ((!pm_runtime_enabled(rx_dev) || @@ -4048,6 +4045,10 @@ static const struct of_device_id rx_macro_dt_match[] = { }; static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) SET_RUNTIME_PM_OPS( bolero_runtime_suspend, bolero_runtime_resume, diff --git a/4.0/asoc/codecs/bolero/tx-macro.c b/4.0/asoc/codecs/bolero/tx-macro.c index 4da74cce..8acb6405 100644 --- a/4.0/asoc/codecs/bolero/tx-macro.c +++ b/4.0/asoc/codecs/bolero/tx-macro.c @@ -376,9 +376,6 @@ static int tx_macro_event_handler(struct snd_soc_codec *codec, u16 event, if (tx_priv->swr_ctrl_data) { swrm_wcd_notify( tx_priv->swr_ctrl_data[0].tx_swr_pdev, - SWR_DEVICE_DOWN, NULL); - swrm_wcd_notify( - tx_priv->swr_ctrl_data[0].tx_swr_pdev, SWR_DEVICE_SSR_DOWN, NULL); } if ((!pm_runtime_enabled(tx_dev) || @@ -439,19 +436,26 @@ static int is_amic_enabled(struct snd_soc_codec *codec, int decimator) { u16 adc_mux_reg = 0, adc_reg = 0; u16 adc_n = BOLERO_ADC_MAX; + bool ret = false; + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + if (!tx_macro_get_data(codec, &tx_dev, &tx_priv, __func__)) + return ret; adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; if (snd_soc_read(codec, adc_mux_reg) & SWR_MIC) { + if (tx_priv->version == BOLERO_VERSION_2_1) + return true; adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; adc_n = snd_soc_read(codec, adc_reg) & TX_MACRO_SWR_MIC_MUX_SEL_MASK; - if (adc_n >= BOLERO_ADC_MAX) - adc_n = BOLERO_ADC_MAX; + if (adc_n < BOLERO_ADC_MAX) + return true; } - return adc_n; + return ret; } static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) @@ -462,7 +466,7 @@ static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) struct snd_soc_codec *codec = NULL; u16 dec_cfg_reg = 0, hpf_gate_reg = 0; u8 hpf_cut_off_freq = 0; - u16 adc_n = 0; + u16 adc_reg = 0, adc_n = 0; hpf_delayed_work = to_delayed_work(work); hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); @@ -478,8 +482,11 @@ static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) dev_dbg(codec->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", __func__, hpf_work->decimator, hpf_cut_off_freq); - adc_n = is_amic_enabled(codec, hpf_work->decimator); - if (adc_n < BOLERO_ADC_MAX) { + if (is_amic_enabled(codec, hpf_work->decimator)) { + adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + TX_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator; + adc_n = snd_soc_read(codec, adc_reg) & + TX_MACRO_SWR_MIC_MUX_SEL_MASK; /* analog mic clear TX hold */ bolero_clear_amic_tx_hold(codec->dev, adc_n); snd_soc_update_bits(codec, @@ -829,6 +836,8 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, int unmute_delay = TX_MACRO_DMIC_UNMUTE_DELAY_MS; struct device *tx_dev = NULL; struct tx_macro_priv *tx_priv = NULL; + u16 adc_mux_reg = 0, adc_reg = 0, adc_n = 0; + u16 dmic_clk_reg = 0; if (!tx_macro_get_data(codec, &tx_dev, &tx_priv, __func__)) return -EINVAL; @@ -849,6 +858,22 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + if (snd_soc_read(codec, adc_mux_reg) & SWR_MIC) { + adc_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + adc_n = snd_soc_read(codec, adc_reg) & + TX_MACRO_SWR_MIC_MUX_SEL_MASK; + if (adc_n >= BOLERO_ADC_MAX) { + dmic_clk_reg = + BOLERO_CDC_TX_TOP_CSR_SWR_DMIC0_CTL + + ((adc_n - 5) / 2) * 4; + snd_soc_update_bits(codec, + dmic_clk_reg, + 0x0E, tx_priv->dmic_clk_div << 0x1); + } + } snd_soc_update_bits(codec, dec_cfg_reg, 0x06, tx_priv->dec_mode[decimator] << TX_MACRO_ADC_MODE_CFG0_SHIFT); @@ -857,12 +882,14 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x20, 0x20); - snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x00); - /* - * Minimum 1 clk cycle delay is required as per HW spec - */ - usleep_range(1000, 1010); - + if (!(is_amic_enabled(codec, decimator) < BOLERO_ADC_MAX)) { + snd_soc_update_bits(codec, + hpf_gate_reg, 0x01, 0x00); + /* + * Minimum 1 clk cycle delay is required as per HW spec + */ + usleep_range(1000, 1010); + } hpf_cut_off_freq = (snd_soc_read(codec, dec_cfg_reg) & TX_HPF_CUT_OFF_FREQ_MASK) >> 5; tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq = @@ -873,26 +900,30 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, TX_HPF_CUT_OFF_FREQ_MASK, CF_MIN_3DB_150HZ << 5); - if (is_amic_enabled(codec, decimator) < BOLERO_ADC_MAX) { + if (is_amic_enabled(codec, decimator)) { hpf_delay = TX_MACRO_AMIC_HPF_DELAY_MS; unmute_delay = TX_MACRO_AMIC_UNMUTE_DELAY_MS; } if (tx_unmute_delay < unmute_delay) tx_unmute_delay = unmute_delay; /* schedule work queue to Remove Mute */ - schedule_delayed_work(&tx_priv->tx_mute_dwork[decimator].dwork, - msecs_to_jiffies(tx_unmute_delay)); + queue_delayed_work(system_freezable_wq, + &tx_priv->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); if (tx_priv->tx_hpf_work[decimator].hpf_cut_off_freq != CF_MIN_3DB_150HZ) { schedule_delayed_work( &tx_priv->tx_hpf_work[decimator].dwork, msecs_to_jiffies(hpf_delay)); - snd_soc_update_bits(codec, hpf_gate_reg, 0x02, 0x02); + snd_soc_update_bits(codec, + hpf_gate_reg, 0x03, 0x02); + if (!is_amic_enabled(codec, decimator)) + snd_soc_update_bits(codec, + hpf_gate_reg, 0x03, 0x00); /* * Minimum 1 clk cycle delay is required as per HW spec */ usleep_range(1000, 1010); - snd_soc_update_bits(codec, hpf_gate_reg, 0x02, 0x00); snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x01); /* @@ -923,15 +954,21 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, hpf_cut_off_freq << 5); - snd_soc_update_bits(codec, hpf_gate_reg, - 0x02, 0x02); + if (is_amic_enabled(codec, decimator)) + snd_soc_update_bits(codec, + hpf_gate_reg, + 0x03, 0x02); + else + snd_soc_update_bits(codec, + hpf_gate_reg, + 0x03, 0x03); /* * Minimum 1 clk cycle delay is required * as per HW spec */ usleep_range(1000, 1010); snd_soc_update_bits(codec, hpf_gate_reg, - 0x02, 0x00); + 0x03, 0x01); } } cancel_delayed_work_sync( @@ -2292,7 +2329,8 @@ static int tx_macro_register_event_listener(struct snd_soc_codec *codec, "%s: priv is null for macro!\n", __func__); return -EINVAL; } - if (tx_priv->swr_ctrl_data && !tx_priv->tx_swr_clk_cnt) { + if (tx_priv->swr_ctrl_data && + (!tx_priv->tx_swr_clk_cnt || !tx_priv->va_swr_clk_cnt)) { if (enable) { ret = swrm_wcd_notify( tx_priv->swr_ctrl_data[0].tx_swr_pdev, @@ -2377,11 +2415,11 @@ static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv, BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK, 0x01, 0x01); regmap_update_bits(regmap, - BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, 0x01, 0x01); regmap_update_bits(regmap, - BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, - 0x01, 0x01); + BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); } tx_priv->tx_mclk_users++; } @@ -2437,14 +2475,15 @@ static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv, tx_priv->tx_mclk_users--; if (tx_priv->tx_mclk_users == 0) { regmap_update_bits(regmap, - BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, - 0x01, 0x00); + BOLERO_CDC_TX_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x00); regmap_update_bits(regmap, - BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, + BOLERO_CDC_TX_CLK_RST_CTRL_MCLK_CONTROL, 0x01, 0x00); } + bolero_clk_rsc_fs_gen_request(tx_priv->dev, - false); + false); ret = bolero_clk_rsc_request_clock(tx_priv->dev, TX_CORE_CLK, VA_CORE_CLK, @@ -3172,6 +3211,10 @@ static const struct of_device_id tx_macro_dt_match[] = { }; static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) SET_RUNTIME_PM_OPS( bolero_runtime_suspend, bolero_runtime_resume, diff --git a/4.0/asoc/codecs/bolero/va-macro.c b/4.0/asoc/codecs/bolero/va-macro.c index f5aad258..dba081e7 100644 --- a/4.0/asoc/codecs/bolero/va-macro.c +++ b/4.0/asoc/codecs/bolero/va-macro.c @@ -201,6 +201,10 @@ static int va_macro_clk_div_get(struct snd_soc_codec *codec) if (!va_macro_get_data(codec, &va_dev, &va_priv, __func__)) return -EINVAL; + if ((va_priv->version == BOLERO_VERSION_2_1) + && !va_priv->lpi_enable + && (va_priv->dmic_clk_div == VA_MACRO_CLK_DIV_16)) + return VA_MACRO_CLK_DIV_8; return va_priv->dmic_clk_div; } @@ -221,19 +225,19 @@ static int va_macro_mclk_enable(struct va_macro_priv *va_priv, mutex_lock(&va_priv->mclk_lock); if (mclk_enable) { + ret = bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, + true); + if (ret < 0) { + dev_err(va_priv->dev, + "%s: va request clock en failed\n", + __func__); + goto exit; + } + bolero_clk_rsc_fs_gen_request(va_priv->dev, + true); if (va_priv->va_mclk_users == 0) { - ret = bolero_clk_rsc_request_clock(va_priv->dev, - va_priv->default_clk_id, - va_priv->clk_id, - true); - if (ret < 0) { - dev_err(va_priv->dev, - "%s: va request clock en failed\n", - __func__); - goto exit; - } - bolero_clk_rsc_fs_gen_request(va_priv->dev, - true); regcache_mark_dirty(regmap); regcache_sync_region(regmap, VA_START_OFFSET, @@ -248,14 +252,12 @@ static int va_macro_mclk_enable(struct va_macro_priv *va_priv, goto exit; } va_priv->va_mclk_users--; - if (va_priv->va_mclk_users == 0) { - bolero_clk_rsc_fs_gen_request(va_priv->dev, - false); - bolero_clk_rsc_request_clock(va_priv->dev, - va_priv->default_clk_id, - va_priv->clk_id, - false); - } + bolero_clk_rsc_fs_gen_request(va_priv->dev, + false); + bolero_clk_rsc_request_clock(va_priv->dev, + va_priv->default_clk_id, + va_priv->clk_id, + false); } exit: mutex_unlock(&va_priv->mclk_lock); @@ -322,9 +324,6 @@ static int va_macro_event_handler(struct snd_soc_codec *codec, u16 event, if (va_priv->swr_ctrl_data) { swrm_wcd_notify( va_priv->swr_ctrl_data[0].va_swr_pdev, - SWR_DEVICE_DOWN, NULL); - swrm_wcd_notify( - va_priv->swr_ctrl_data[0].va_swr_pdev, SWR_DEVICE_SSR_DOWN, NULL); } if ((!pm_runtime_enabled(va_dev) || @@ -343,12 +342,11 @@ static int va_macro_event_handler(struct snd_soc_codec *codec, u16 event, return 0; } -static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, +static int va_macro_swr_clk_event_v2(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - int ret = 0; struct device *va_dev = NULL; struct va_macro_priv *va_priv = NULL; @@ -356,13 +354,46 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, return -EINVAL; dev_dbg(va_dev, "%s: event = %d\n", __func__, event); + switch (event) { case SND_SOC_DAPM_PRE_PMU: va_priv->va_swr_clk_cnt++; + break; + case SND_SOC_DAPM_POST_PMD: + va_priv->va_swr_clk_cnt--; + break; + default: + break; + } + return 0; +} + +static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = + snd_soc_dapm_to_codec(w->dapm); + int ret = 0; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + int clk_src = 0; + + if (!va_macro_get_data(codec, &va_dev, &va_priv, __func__)) + return -EINVAL; + + dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n", + __func__, event, va_priv->lpi_enable); + + if (!va_priv->lpi_enable) + return ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: if (va_priv->swr_ctrl_data) { + clk_src = CLK_SRC_VA_RCG; ret = swrm_wcd_notify( va_priv->swr_ctrl_data[0].va_swr_pdev, - SWR_REQ_CLK_SWITCH, NULL); + SWR_REQ_CLK_SWITCH, &clk_src); if (ret) dev_dbg(va_dev, "%s: clock switch failed\n", __func__); @@ -374,14 +405,14 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, msm_cdc_pinctrl_set_wakeup_capable( va_priv->va_swr_gpio_p, true); if (va_priv->swr_ctrl_data) { + clk_src = CLK_SRC_TX_RCG; ret = swrm_wcd_notify( va_priv->swr_ctrl_data[0].va_swr_pdev, - SWR_REQ_CLK_SWITCH, NULL); + SWR_REQ_CLK_SWITCH, &clk_src); if (ret) dev_dbg(va_dev, "%s: clock switch failed\n", __func__); } - va_priv->va_swr_clk_cnt--; break; default: dev_err(va_priv->dev, @@ -404,8 +435,10 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w, dev_dbg(va_dev, "%s: event = %d, lpi_enable = %d\n", __func__, event, va_priv->lpi_enable); + if (!va_priv->lpi_enable) return ret; + switch (event) { case SND_SOC_DAPM_PRE_PMU: if (va_priv->lpass_audio_hw_vote) { @@ -469,6 +502,7 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, int ret = 0; struct device *va_dev = NULL; struct va_macro_priv *va_priv = NULL; + int clk_src = 0; if (!va_macro_get_data(codec, &va_dev, &va_priv, __func__)) return -EINVAL; @@ -490,9 +524,22 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: if (va_priv->lpi_enable) { - if (bolero_tx_clk_switch(codec, CLK_SRC_TX_RCG)) + if (va_priv->version == BOLERO_VERSION_2_1) { + if (va_priv->swr_ctrl_data) { + clk_src = CLK_SRC_TX_RCG; + ret = swrm_wcd_notify( + va_priv->swr_ctrl_data[0].va_swr_pdev, + SWR_REQ_CLK_SWITCH, &clk_src); + if (ret) + dev_dbg(va_dev, + "%s: clock switch failed\n", + __func__); + } + } else if (bolero_tx_clk_switch(codec, + CLK_SRC_TX_RCG)) { dev_dbg(va_dev, "%s: clock switch failed\n", __func__); + } va_macro_mclk_enable(va_priv, 0, true); } else { bolero_tx_mclk_enable(codec, 0); @@ -736,19 +783,26 @@ static int is_amic_enabled(struct snd_soc_codec *codec, int decimator) { u16 adc_mux_reg = 0, adc_reg = 0; u16 adc_n = BOLERO_ADC_MAX; + bool ret = false; + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + if (!va_macro_get_data(codec, &va_dev, &va_priv, __func__)) + return ret; adc_mux_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG1 + VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; if (snd_soc_read(codec, adc_mux_reg) & SWR_MIC) { + if (va_priv->version == BOLERO_VERSION_2_1) + return true; adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 + VA_MACRO_ADC_MUX_CFG_OFFSET * decimator; adc_n = snd_soc_read(codec, adc_reg) & VA_MACRO_SWR_MIC_MUX_SEL_MASK; - if (adc_n >= BOLERO_ADC_MAX) - adc_n = BOLERO_ADC_MAX; + if (adc_n < BOLERO_ADC_MAX) + return true; } - return adc_n; + return ret; } static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work) @@ -759,7 +813,7 @@ static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work) struct snd_soc_codec *codec; u16 dec_cfg_reg, hpf_gate_reg; u8 hpf_cut_off_freq; - u16 adc_n = 0; + u16 adc_reg = 0, adc_n = 0; hpf_delayed_work = to_delayed_work(work); hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); @@ -775,8 +829,11 @@ static void va_macro_tx_hpf_corner_freq_callback(struct work_struct *work) dev_dbg(va_priv->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", __func__, hpf_work->decimator, hpf_cut_off_freq); - adc_n = is_amic_enabled(codec, hpf_work->decimator); - if (adc_n < BOLERO_ADC_MAX) { + if (is_amic_enabled(codec, hpf_work->decimator)) { + adc_reg = BOLERO_CDC_VA_INP_MUX_ADC_MUX0_CFG0 + + VA_MACRO_ADC_MUX_CFG_OFFSET * hpf_work->decimator; + adc_n = snd_soc_read(codec, adc_reg) & + VA_MACRO_SWR_MIC_MUX_SEL_MASK; /* analog mic clear TX hold */ bolero_clear_amic_tx_hold(codec->dev, adc_n); snd_soc_update_bits(codec, @@ -1070,48 +1127,52 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* Enable TX CLK */ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x20, 0x20); - snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x00); + if (!(is_amic_enabled(codec, decimator) < BOLERO_ADC_MAX)) { + snd_soc_update_bits(codec, + hpf_gate_reg, 0x01, 0x00); /* * Minimum 1 clk cycle delay is required as per HW spec */ usleep_range(1000, 1010); - - hpf_cut_off_freq = (snd_soc_read(codec, dec_cfg_reg) & + } + hpf_cut_off_freq = (snd_soc_read( + codec, dec_cfg_reg) & TX_HPF_CUT_OFF_FREQ_MASK) >> 5; va_priv->va_hpf_work[decimator].hpf_cut_off_freq = hpf_cut_off_freq; - if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) snd_soc_update_bits(codec, dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, CF_MIN_3DB_150HZ << 5); - } - if (is_amic_enabled(codec, decimator) < BOLERO_ADC_MAX) { + if (is_amic_enabled(codec, decimator)) { hpf_delay = BOLERO_CDC_VA_TX_AMIC_HPF_DELAY_MS; unmute_delay = BOLERO_CDC_VA_TX_AMIC_UNMUTE_DELAY_MS; if (va_tx_unmute_delay < unmute_delay) va_tx_unmute_delay = unmute_delay; } snd_soc_update_bits(codec, - hpf_gate_reg, 0x03, 0x03); + hpf_gate_reg, 0x03, 0x02); + if (!is_amic_enabled(codec, decimator)) + snd_soc_update_bits(codec, + hpf_gate_reg, 0x03, 0x00); /* * Minimum 1 clk cycle delay is required as per HW spec */ usleep_range(1000, 1010); snd_soc_update_bits(codec, - hpf_gate_reg, 0x02, 0x00); - snd_soc_update_bits(codec, - hpf_gate_reg, 0x01, 0x01); + hpf_gate_reg, 0x03, 0x01); /* * 6ms delay is required as per HW spec */ usleep_range(6000, 6010); /* schedule work queue to Remove Mute */ - schedule_delayed_work(&va_priv->va_mute_dwork[decimator].dwork, - msecs_to_jiffies(va_tx_unmute_delay)); + queue_delayed_work(system_freezable_wq, + &va_priv->va_mute_dwork[decimator].dwork, + msecs_to_jiffies(va_tx_unmute_delay)); if (va_priv->va_hpf_work[decimator].hpf_cut_off_freq != CF_MIN_3DB_150HZ) - schedule_delayed_work( + queue_delayed_work(system_freezable_wq, &va_priv->va_hpf_work[decimator].dwork, msecs_to_jiffies(hpf_delay)); /* apply gain after decimator is enabled */ @@ -1125,18 +1186,25 @@ static int va_macro_enable_dec(struct snd_soc_dapm_widget *w, if (cancel_delayed_work_sync( &va_priv->va_hpf_work[decimator].dwork)) { if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { - snd_soc_update_bits(codec, dec_cfg_reg, - TX_HPF_CUT_OFF_FREQ_MASK, - hpf_cut_off_freq << 5); - snd_soc_update_bits(codec, hpf_gate_reg, - 0x02, 0x02); + snd_soc_update_bits(codec, + dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + if (is_amic_enabled(codec, decimator)) + snd_soc_update_bits(codec, + hpf_gate_reg, + 0x03, 0x02); + else + snd_soc_update_bits(codec, + hpf_gate_reg, + 0x03, 0x03); /* * Minimum 1 clk cycle delay is required * as per HW spec */ usleep_range(1000, 1010); snd_soc_update_bits(codec, hpf_gate_reg, - 0x02, 0x00); + 0x03, 0x01); } } cancel_delayed_work_sync( @@ -1831,6 +1899,10 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v2[] = { SND_SOC_DAPM_SUPPLY_S("VA_TX_SWR_CLK", 0, SND_SOC_NOPM, 0, 0, va_macro_tx_swr_clk_event_v2, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("VA_SWR_CLK", 0, SND_SOC_NOPM, 0, 0, + va_macro_swr_clk_event_v2, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_widget va_macro_dapm_widgets_v3[] = { @@ -2157,6 +2229,12 @@ static const struct snd_soc_dapm_route va_audio_map_v3[] = { {"VA SMIC MUX3", "SWR_MIC11", "VA SWR_MIC11"}, }; +static const struct snd_soc_dapm_route va_audio_map_v2[] = { + {"VA_AIF1 CAP", NULL, "VA_SWR_CLK"}, + {"VA_AIF2 CAP", NULL, "VA_SWR_CLK"}, + {"VA_AIF3 CAP", NULL, "VA_SWR_CLK"}, +}; + static const struct snd_soc_dapm_route va_audio_map[] = { {"VA_AIF1 CAP", NULL, "VA_MCLK"}, {"VA_AIF2 CAP", NULL, "VA_MCLK"}, @@ -2455,6 +2533,8 @@ static const struct snd_kcontrol_new va_macro_snd_controls_common[] = { SOC_SINGLE_SX_TLV("VA_DEC1 Volume", BOLERO_CDC_VA_TX1_TX_VOL_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0, + va_macro_lpi_get, va_macro_lpi_put), }; static const struct snd_kcontrol_new va_macro_snd_controls_v3[] = { @@ -2594,14 +2674,25 @@ static int va_macro_init(struct snd_soc_codec *codec) __func__); return ret; } - if (va_priv->version == BOLERO_VERSION_2_0) + if (va_priv->version == BOLERO_VERSION_2_0) { ret = snd_soc_dapm_add_routes(dapm, va_audio_map_v3, ARRAY_SIZE(va_audio_map_v3)); - if (ret < 0) { - dev_err(va_dev, "%s: Failed to add routes\n", - __func__); - return ret; + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } + } + if (va_priv->version == BOLERO_VERSION_2_1) { + ret = snd_soc_dapm_add_routes(dapm, + va_audio_map_v2, + ARRAY_SIZE(va_audio_map_v2)); + if (ret < 0) { + dev_err(va_dev, "%s: Failed to add routes\n", + __func__); + return ret; + } } } else { ret = snd_soc_dapm_add_routes(dapm, va_audio_map, @@ -3095,6 +3186,10 @@ static const struct of_device_id va_macro_dt_match[] = { }; static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) SET_RUNTIME_PM_OPS( bolero_runtime_suspend, bolero_runtime_resume, diff --git a/4.0/asoc/codecs/bolero/wsa-macro.c b/4.0/asoc/codecs/bolero/wsa-macro.c index a524a0a8..18f78e23 100644 --- a/4.0/asoc/codecs/bolero/wsa-macro.c +++ b/4.0/asoc/codecs/bolero/wsa-macro.c @@ -991,9 +991,6 @@ static int wsa_macro_event_handler(struct snd_soc_codec *codec, u16 event, if (wsa_priv->swr_ctrl_data) { swrm_wcd_notify( wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, - SWR_DEVICE_DOWN, NULL); - swrm_wcd_notify( - wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, SWR_DEVICE_SSR_DOWN, NULL); } if ((!pm_runtime_enabled(wsa_dev) || @@ -3173,6 +3170,10 @@ static const struct of_device_id wsa_macro_dt_match[] = { }; static const struct dev_pm_ops bolero_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + pm_runtime_force_suspend, + pm_runtime_force_resume + ) SET_RUNTIME_PM_OPS( bolero_runtime_suspend, bolero_runtime_resume, diff --git a/4.0/asoc/codecs/wcd-mbhc-adc.c b/4.0/asoc/codecs/wcd-mbhc-adc.c index 9eb5ed0f..eb2d9431 100644 --- a/4.0/asoc/codecs/wcd-mbhc-adc.c +++ b/4.0/asoc/codecs/wcd-mbhc-adc.c @@ -1111,6 +1111,7 @@ static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0); mbhc->is_extn_cable = true; mbhc->btn_press_intr = false; + mbhc->force_linein = false; wcd_mbhc_adc_detect_plug_type(mbhc); WCD_MBHC_RSC_UNLOCK(mbhc); pr_debug("%s: leave\n", __func__); diff --git a/4.0/asoc/codecs/wcd-mbhc-v2.c b/4.0/asoc/codecs/wcd-mbhc-v2.c index 94dc5436..0f3d74bd 100644 --- a/4.0/asoc/codecs/wcd-mbhc-v2.c +++ b/4.0/asoc/codecs/wcd-mbhc-v2.c @@ -630,11 +630,12 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, } mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->zl = mbhc->zr = 0; - pr_debug("%s: Reporting removal (%x)\n", - __func__, mbhc->hph_status); - wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, - 0, WCD_MBHC_JACK_MASK); - + if (!mbhc->force_linein) { + pr_debug("%s: Reporting removal (%x)\n", + __func__, mbhc->hph_status); + wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, + 0, WCD_MBHC_JACK_MASK); + } if (mbhc->hph_status == SND_JACK_LINEOUT) { pr_debug("%s: Enable micbias\n", __func__); @@ -728,6 +729,10 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->hph_status |= jack_type; + if (jack_type == SND_JACK_HEADPHONE && + mbhc->mbhc_cb->mbhc_micb_ramp_control) + mbhc->mbhc_cb->mbhc_micb_ramp_control(codec, false); + pr_debug("%s: Reporting insertion %d(%x)\n", __func__, jack_type, mbhc->hph_status); wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack, @@ -918,6 +923,10 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) else pr_info("%s: hs_detect_plug work not cancelled\n", __func__); + /* Enable micbias ramp */ + if (mbhc->mbhc_cb->mbhc_micb_ramp_control) + mbhc->mbhc_cb->mbhc_micb_ramp_control(codec, true); + if (mbhc->mbhc_cb->micbias_enable_status) micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_1); @@ -1411,9 +1420,6 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) /* Button Debounce set to 16ms */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2); - /* Enable micbias ramp */ - if (mbhc->mbhc_cb->mbhc_micb_ramp_control) - mbhc->mbhc_cb->mbhc_micb_ramp_control(codec, true); /* enable bias */ mbhc->mbhc_cb->mbhc_bias(codec, true); /* enable MBHC clock */ diff --git a/4.0/asoc/codecs/wcd937x/wcd937x-mbhc.h b/4.0/asoc/codecs/wcd937x/wcd937x-mbhc.h index 34a73585..e70d4b61 100644 --- a/4.0/asoc/codecs/wcd937x/wcd937x-mbhc.h +++ b/4.0/asoc/codecs/wcd937x/wcd937x-mbhc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef __WCD937X_MBHC_H__ #define __WCD937X_MBHC_H__ @@ -51,7 +51,6 @@ static inline int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc, static inline void wcd937x_mbhc_ssr_down(struct wcd937x_mbhc *mbhc, struct snd_soc_component *component) { - return 0; } static inline int wcd937x_mbhc_get_impedance(struct wcd937x_mbhc *wcd937x_mbhc, uint32_t *zl, uint32_t *zr) diff --git a/4.0/asoc/codecs/wcd937x/wcd937x.c b/4.0/asoc/codecs/wcd937x/wcd937x.c index b6c7757f..47d5e16d 100644 --- a/4.0/asoc/codecs/wcd937x/wcd937x.c +++ b/4.0/asoc/codecs/wcd937x/wcd937x.c @@ -1396,7 +1396,7 @@ int wcd937x_micbias_control(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WCD937X_MICB2_TEST_CTL_2, 0x01, 0x01); snd_soc_update_bits(codec, WCD937X_MICB3_TEST_CTL_2, 0x01, 0x01); snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40); - if (post_on_event && wcd937x->mbhc) + if (post_on_event) blocking_notifier_call_chain( &wcd937x->mbhc->notifier, post_on_event, &wcd937x->mbhc->wcd_mbhc); @@ -1520,14 +1520,13 @@ static int wcd937x_event_notify(struct notifier_block *block, break; case BOLERO_WCD_EVT_SSR_UP: wcd937x_reset(wcd937x->dev); + /* allow reset to take effect */ + usleep_range(10000, 10010); wcd937x_get_logical_addr(wcd937x->tx_swr_dev); wcd937x_get_logical_addr(wcd937x->rx_swr_dev); + wcd937x_init_reg(codec); regcache_mark_dirty(wcd937x->regmap); regcache_sync(wcd937x->regmap); - /* Enable surge protection */ - snd_soc_update_bits(codec, - WCD937X_HPH_SURGE_HPHLR_SURGE_EN, - 0xFF, 0xD9); /* Initialize MBHC module */ mbhc = &wcd937x->mbhc->wcd_mbhc; ret = wcd937x_mbhc_post_ssr_init(wcd937x->mbhc, codec); @@ -1630,6 +1629,7 @@ static int wcd937x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, { return __wcd937x_codec_enable_micbias_pullup(w, event); } + static int wcd937x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2379,7 +2379,8 @@ static int wcd937x_soc_codec_probe(struct snd_soc_codec *codec) wcd937x->codec = codec; snd_soc_codec_init_regmap(codec, wcd937x->regmap); - variant = (snd_soc_read(codec, WCD937X_DIGITAL_EFUSE_REG_0) & 0x0E) >> 1; + variant = (snd_soc_read(codec, WCD937X_DIGITAL_EFUSE_REG_0) & 0x1E) + >> 1; wcd937x->variant = variant; wcd937x->fw_data = devm_kzalloc(codec->dev, diff --git a/4.0/asoc/codecs/wcd938x/internal.h b/4.0/asoc/codecs/wcd938x/internal.h index f3563fff..a1c0fa78 100644 --- a/4.0/asoc/codecs/wcd938x/internal.h +++ b/4.0/asoc/codecs/wcd938x/internal.h @@ -70,6 +70,7 @@ struct wcd938x_priv { bool comp1_enable; bool comp2_enable; bool ldoh; + bool bcs_dis; struct irq_domain *virq; struct wcd_irq_info irq_info; u32 rx_clk_cnt; diff --git a/4.0/asoc/codecs/wcd938x/wcd938x.c b/4.0/asoc/codecs/wcd938x/wcd938x.c index 94c3aa54..c60028ca 100644 --- a/4.0/asoc/codecs/wcd938x/wcd938x.c +++ b/4.0/asoc/codecs/wcd938x/wcd938x.c @@ -68,6 +68,16 @@ enum { ADC_MODE_ULP2, }; +static u8 tx_mode_bit[] = { + [ADC_MODE_INVALID] = 0x00, + [ADC_MODE_HIFI] = 0x01, + [ADC_MODE_LO_HIF] = 0x02, + [ADC_MODE_NORMAL] = 0x04, + [ADC_MODE_LP] = 0x08, + [ADC_MODE_ULP1] = 0x10, + [ADC_MODE_ULP2] = 0x20, +}; + static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -140,31 +150,63 @@ static int wcd938x_swr_slv_get_current_bank(struct swr_device *dev, u8 devnum) return ((bank & 0x40) ? 1: 0); } -static int wcd938x_swr_slv_set_host_clk_div2(struct swr_device *dev, - u8 devnum, int bank) +static int wcd938x_get_clk_rate(int mode) { - u8 val = (bank ? 1 : 0); + int rate; - return (swr_write(dev, devnum, - (SWR_SCP_HOST_CLK_DIV2_CTL_BANK + (0x10 * bank)), &val)); + switch (mode) { + case ADC_MODE_ULP2: + rate = SWR_CLK_RATE_0P6MHZ; + break; + case ADC_MODE_ULP1: + rate = SWR_CLK_RATE_1P2MHZ; + break; + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_NORMAL: + case ADC_MODE_LO_HIF: + case ADC_MODE_HIFI: + case ADC_MODE_INVALID: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + return rate; } static int wcd938x_set_swr_clk_rate(struct snd_soc_codec *codec, - int mode, int bank) + int rate, int bank) { u8 mask = (bank ? 0xF0 : 0x0F); u8 val = 0; - if ((mode == ADC_MODE_ULP1) || (mode == ADC_MODE_ULP2)) + switch (rate) { + case SWR_CLK_RATE_0P6MHZ: val = (bank ? 0x60 : 0x06); - else + break; + case SWR_CLK_RATE_1P2MHZ: + val = (bank ? 0x50 : 0x05); + break; + case SWR_CLK_RATE_2P4MHZ: + val = (bank ? 0x30 : 0x03); + break; + case SWR_CLK_RATE_4P8MHZ: + val = (bank ? 0x10 : 0x01); + break; + case SWR_CLK_RATE_9P6MHZ: + default: val = 0x00; - - snd_soc_update_bits(codec, WCD938X_DIGITAL_SWR_TX_CLK_RATE, + break; + } + snd_soc_update_bits(codec, + WCD938X_DIGITAL_SWR_TX_CLK_RATE, mask, val); return 0; } + static int wcd938x_init_reg(struct snd_soc_codec *codec) { snd_soc_update_bits(codec, WCD938X_SLEEP_CTL, 0x0E, 0x0E); @@ -222,6 +264,11 @@ static int wcd938x_init_reg(struct snd_soc_codec *codec) WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0); snd_soc_update_bits(codec, WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00); + snd_soc_update_bits(codec, WCD938X_SLEEP_CTL, 0x0E, + ((snd_soc_read(codec, + WCD938X_DIGITAL_EFUSE_REG_30) & 0x07) << 1)); + snd_soc_update_bits(codec, + WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); return 0; } @@ -351,7 +398,8 @@ err_port_map: } static int wcd938x_tx_connect_port(struct snd_soc_codec *codec, - u8 slv_port_type, u8 enable) + u8 slv_port_type, int clk_rate, + u8 enable) { struct wcd938x_priv *wcd938x = snd_soc_codec_get_drvdata(codec); u8 port_id, num_ch, ch_mask, port_type; @@ -362,6 +410,8 @@ static int wcd938x_tx_connect_port(struct snd_soc_codec *codec, ret = wcd938x_set_port_params(codec, slv_port_type, &port_id, &num_ch, &ch_mask, &ch_rate, &port_type, CODEC_TX); + if (clk_rate) + ch_rate = clk_rate; if (ret) return ret; @@ -1299,10 +1349,12 @@ static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w, /* enable clock scaling */ snd_soc_update_bits(codec, WCD938X_DIGITAL_CDC_DMIC_CTL, 0x06, 0x06); - wcd938x_tx_connect_port(codec, DMIC0 + (w->shift), true); + wcd938x_tx_connect_port(codec, DMIC0 + (w->shift), + SWR_CLK_RATE_2P4MHZ, true); break; case SND_SOC_DAPM_POST_PMD: - wcd938x_tx_connect_port(codec, DMIC0 + (w->shift), false); + wcd938x_tx_connect_port(codec, DMIC0 + (w->shift), 0, + false); snd_soc_update_bits(codec, WCD938X_DIGITAL_CDC_AMIC_CTL, (0x01 << dmic_ctl_shift), @@ -1423,32 +1475,54 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, struct wcd938x_priv *wcd938x = snd_soc_codec_get_drvdata(codec); int ret = 0; int bank = 0; - int mode = 0; + u8 mode = 0; + int i = 0; + int rate = 0; + + bank = (wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num) ? 0 : 1); - bank = wcd938x_swr_slv_get_current_bank(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num); - wcd938x_swr_slv_set_host_clk_div2(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num, bank); switch (event) { case SND_SOC_DAPM_PRE_PMU: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + if (test_bit(WCD_ADC1, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + rate = wcd938x_get_clk_rate(i); + wcd938x_set_swr_clk_rate(codec, mode, bank); + } ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, wcd938x->tx_swr_dev->dev_num, true); - if (test_bit(WCD_ADC1, &wcd938x->status_mask)) - mode |= wcd938x->tx_mode[WCD_ADC1]; - if (test_bit(WCD_ADC2, &wcd938x->status_mask)) - mode |= wcd938x->tx_mode[WCD_ADC2]; - if (test_bit(WCD_ADC3, &wcd938x->status_mask)) - mode |= wcd938x->tx_mode[WCD_ADC3]; - if (test_bit(WCD_ADC4, &wcd938x->status_mask)) - mode |= wcd938x->tx_mode[WCD_ADC4]; - wcd938x_set_swr_clk_rate(codec, mode, bank); + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + /* Copy clk settings to active bank */ + wcd938x_set_swr_clk_rate(codec, rate, !bank); + } break; case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + rate = wcd938x_get_clk_rate(ADC_MODE_INVALID); + wcd938x_set_swr_clk_rate(codec, rate, !bank); + } ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, wcd938x->tx_swr_dev->dev_num, false); - wcd938x_set_swr_clk_rate(codec, ADC_MODE_INVALID, bank); + if (strnstr(w->name, "ADC", sizeof("ADC"))) + wcd938x_set_swr_clk_rate(codec, rate, bank); break; }; @@ -1495,6 +1569,7 @@ static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wcd938x_priv *wcd938x = snd_soc_codec_get_drvdata(codec); + int clk_rate = 0; dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -1505,21 +1580,26 @@ static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08); snd_soc_update_bits(codec, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); - set_bit(w->shift, &wcd938x->status_mask); - /* Enable BCS for Headset mic */ + clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]); + /* Enable BCS for Headset mic */ if (w->shift == 1 && !(snd_soc_read(codec, WCD938X_TX_NEW_AMIC_MUX_CFG) & 0x80)) { - wcd938x_tx_connect_port(codec, MBHC, true); + if (!wcd938x->bcs_dis) + wcd938x_tx_connect_port(codec, MBHC, + SWR_CLK_RATE_4P8MHZ, true); set_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); } - wcd938x_tx_connect_port(codec, ADC1 + (w->shift), true); + wcd938x_tx_connect_port(codec, ADC1 + (w->shift), clk_rate, + true); break; case SND_SOC_DAPM_POST_PMD: - wcd938x_tx_connect_port(codec, ADC1 + (w->shift), false); + wcd938x_tx_connect_port(codec, ADC1 + (w->shift), 0, false); if (w->shift == 1 && test_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask)) { - wcd938x_tx_connect_port(codec, MBHC, false); + if (!wcd938x->bcs_dis) + wcd938x_tx_connect_port(codec, MBHC, 0, + false); clear_bit(AMIC2_BCS_ENABLE, &wcd938x->status_mask); } snd_soc_update_bits(codec, @@ -2334,6 +2414,30 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, return 0; } +static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = + snd_soc_kcontrol_codec(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = wcd938x->bcs_dis; + + return 0; +} + +static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = + snd_soc_kcontrol_codec(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_codec_get_drvdata(codec); + + wcd938x->bcs_dis = ucontrol->value.integer.value[0]; + + return 0; +} + static const char * const tx_mode_mux_text_wcd9380[] = { "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", }; @@ -2417,10 +2521,12 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = { wcd938x_get_compander, wcd938x_set_compander), SOC_SINGLE_EXT("HPHR_COMP Switch", SND_SOC_NOPM, 1, 1, 0, wcd938x_get_compander, wcd938x_set_compander), - SOC_SINGLE_EXT("LDOH Enable", SND_SOC_NOPM, 0, 1, 0, wcd938x_ldoh_get, wcd938x_ldoh_put), + SOC_SINGLE_EXT("ADC2_BCS Disable", SND_SOC_NOPM, 0, 1, 0, + wcd938x_bcs_get, wcd938x_bcs_put), + SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 20, 1, line_gain), SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 20, 1, line_gain), SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, diff --git a/4.0/asoc/msm-dai-q6-v2.c b/4.0/asoc/msm-dai-q6-v2.c index e9d354b8..bf9c4c5b 100644 --- a/4.0/asoc/msm-dai-q6-v2.c +++ b/4.0/asoc/msm-dai-q6-v2.c @@ -1285,6 +1285,7 @@ static int msm_dai_q6_island_mode_put(struct snd_kcontrol *kcontrol, u16 port_id = (u16)kcontrol->private_value; pr_debug("%s: island mode = %d\n", __func__, value); + trace_printk("%s: island mode = %d\n", __func__, value); afe_set_island_mode_cfg(port_id, value); return 0; diff --git a/4.0/asoc/msm-lsm-client.c b/4.0/asoc/msm-lsm-client.c index 208a8a63..d6fd86cc 100644 --- a/4.0/asoc/msm-lsm-client.c +++ b/4.0/asoc/msm-lsm-client.c @@ -25,12 +25,15 @@ #include <dsp/q6lsm.h> #include "msm-pcm-routing-v2.h" + #define CAPTURE_MIN_NUM_PERIODS 2 #define CAPTURE_MAX_NUM_PERIODS 8 #define CAPTURE_MAX_PERIOD_SIZE 61440 #define CAPTURE_MIN_PERIOD_SIZE 320 #define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256 +#define WAKELOCK_TIMEOUT 2000 + #define LAB_BUFFER_ALLOC 1 #define LAB_BUFFER_DEALLOC 0 @@ -88,6 +91,7 @@ struct lsm_priv { int xrun_count; int xrun_index; spinlock_t xrun_lock; + struct wakeup_source ws; }; enum { /* lsm session states */ @@ -215,6 +219,8 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, } rtd = substream->private_data; + pm_wakeup_ws_event(&prtd->ws, WAKELOCK_TIMEOUT, true); + dev_dbg(rtd->dev, "%s: opcode %x\n", __func__, opcode); switch (opcode) { case LSM_DATA_EVENT_READ_DONE: { int rc; @@ -228,11 +234,13 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, "%s: EVENT_READ_DONE invalid callback, session %d callback %d payload %pK", __func__, prtd->lsm_client->session, token, read_done); + __pm_relax(&prtd->ws); return; } if (atomic_read(&prtd->read_abort)) { dev_dbg(rtd->dev, "%s: read abort set skip data\n", __func__); + __pm_relax(&prtd->ws); return; } if (!lsm_lab_buffer_sanity(prtd, read_done, &buf_index)) { @@ -245,6 +253,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, "%s: Invalid index %d buf_index max cnt %d\n", __func__, buf_index, prtd->lsm_client->out_hw_params.period_count); + __pm_relax(&prtd->ws); return; } spin_lock_irqsave(&prtd->xrun_lock, flags); @@ -282,6 +291,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, dev_err(rtd->dev, "%s: client_size has invalid size[%d]\n", __func__, client_size); + __pm_relax(&prtd->ws); return; } status = (uint16_t)((uint8_t *)payload)[0]; @@ -297,13 +307,14 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, dev_err(rtd->dev, "%s: client_size has invalid size[%d]\n", __func__, client_size); + __pm_relax(&prtd->ws); return; } status = (uint16_t)((uint8_t *)payload)[0]; payload_size = (uint16_t)((uint8_t *)payload)[1]; index = 2; dev_dbg(rtd->dev, - "%s: event detect status = %d payload size = %d\n", + "%s: event detect status_v2 = %d payload size = %d\n", __func__, status, payload_size); break; @@ -312,6 +323,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, dev_err(rtd->dev, "%s: client_size has invalid size[%d]\n", __func__, client_size); + __pm_relax(&prtd->ws); return; } event_ts_lsw = ((uint32_t *)payload)[0]; @@ -331,6 +343,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, dev_err(rtd->dev, "%s: client_size has invalid size[%d]\n", __func__, client_size); + __pm_relax(&prtd->ws); return; } @@ -350,6 +363,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, "LSM_SESSION_DETECTION_ENGINE_GENERIC_EVENT", sizeof(struct snd_lsm_event_status) + payload_size); + __pm_relax(&prtd->ws); return; } @@ -364,6 +378,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, dev_err(rtd->dev, "%s: Failed to copy memory with invalid size = %d\n", __func__, payload_size); + __pm_relax(&prtd->ws); return; } prtd->event_avail = 1; @@ -388,12 +403,14 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2 || opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V3) { spin_lock_irqsave(&prtd->event_lock, flags); + dev_dbg(rtd->dev, "%s: detection status\n", __func__); temp = krealloc(prtd->event_status, sizeof(struct snd_lsm_event_status_v3) + payload_size, GFP_ATOMIC); if (!temp) { dev_err(rtd->dev, "%s: no memory for event status\n", __func__); + __pm_relax(&prtd->ws); return; } /* @@ -413,12 +430,15 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, payload_size); prtd->event_avail = 1; spin_unlock_irqrestore(&prtd->event_lock, flags); + dev_dbg(rtd->dev, "%s: wakeup event_wait\n", + __func__); wake_up(&prtd->event_wait); } else { spin_unlock_irqrestore(&prtd->event_lock, flags); dev_err(rtd->dev, "%s: Failed to copy memory with invalid size = %d\n", __func__, payload_size); + __pm_relax(&prtd->ws); return; } } else { @@ -430,6 +450,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, if (substream->timer_running) snd_timer_interrupt(substream->timer, 1); } + dev_dbg(rtd->dev, "%s: leave\n", __func__); } static int msm_lsm_lab_buffer_alloc(struct lsm_priv *lsm, int alloc) @@ -1069,6 +1090,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, prtd = runtime->private_data; rtd = substream->private_data; + dev_dbg(rtd->dev, "%s: enter, cmd %x\n", __func__, cmd); switch (cmd) { case SNDRV_LSM_SET_SESSION_DATA: case SNDRV_LSM_SET_SESSION_DATA_V2: @@ -1134,6 +1156,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: lsm open failed, %d\n", __func__, ret); + __pm_relax(&prtd->ws); return ret; } prtd->lsm_client->opened = true; @@ -1269,7 +1292,8 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, uint32_t ts_lsw, ts_msw; uint16_t status = 0, payload_size = 0; - dev_dbg(rtd->dev, "%s: Get event status\n", __func__); + dev_dbg(rtd->dev, "%s: Get event status cmd %xx\n", + __func__, cmd); atomic_set(&prtd->event_wait_stop, 0); /* @@ -1282,6 +1306,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, (cmpxchg(&prtd->event_avail, 1, 0) || (xchg = atomic_cmpxchg(&prtd->event_wait_stop, 1, 0)))); + dev_dbg(rtd->dev, "%s: wait event is done\n", __func__); mutex_lock(&prtd->lsm_api_lock); dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n", __func__, rc, xchg); @@ -1480,12 +1505,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, if (prtd->lsm_client->num_stages > 1) { dev_err(rtd->dev, "%s: %s: not supported for multi stage session\n", __func__, "LSM_LAB_CONTROL"); + __pm_relax(&prtd->ws); return -EINVAL; } if (copy_from_user(&enable, arg, sizeof(enable))) { dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", __func__, "LSM_LAB_CONTROL"); + __pm_relax(&prtd->ws); return -EFAULT; } @@ -1540,6 +1567,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, if (copy_from_user(&mode, arg, sizeof(mode))) { dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", __func__, "LSM_SET_FWK_MODE_CONFIG"); + __pm_relax(&prtd->ws); return -EFAULT; } @@ -1570,6 +1598,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, if (copy_from_user(¶ms, arg, sizeof(params))) { dev_err(rtd->dev, "%s: %s: copy_from_user failed\n", __func__, "LSM_SET_INPUT_HW_PARAMS"); + __pm_relax(&prtd->ws); return -EFAULT; } @@ -1596,6 +1625,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: cmd 0x%x failed %d\n", __func__, cmd, rc); + __pm_relax(&prtd->ws); return rc; } @@ -2500,6 +2530,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream) prtd->lsm_client->fe_id = rtd->dai_link->id; prtd->lsm_client->unprocessed_data = 0; + wakeup_source_init(&prtd->ws, "lsm-client"); return 0; } @@ -2744,6 +2775,7 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) q6lsm_client_free(prtd->lsm_client); + wakeup_source_trash(&prtd->ws); spin_lock_irqsave(&prtd->event_lock, flags); kfree(prtd->event_status); prtd->event_status = NULL; diff --git a/4.0/asoc/msm-pcm-loopback-v2.c b/4.0/asoc/msm-pcm-loopback-v2.c index 3fdced03..8ad8120c 100644 --- a/4.0/asoc/msm-pcm-loopback-v2.c +++ b/4.0/asoc/msm-pcm-loopback-v2.c @@ -242,7 +242,6 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) struct msm_pcm_loopback *pcm = NULL; int ret = 0; uint16_t bits_per_sample = 16; - struct msm_pcm_routing_evt event; struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; uint32_t param_id; struct msm_pcm_pdata *pdata; @@ -264,10 +263,6 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__, pcm->instance, substream->stream); if (pcm->instance == 2) { - struct snd_soc_pcm_runtime *soc_pcm_rx = - pcm->playback_substream->private_data; - struct snd_soc_pcm_runtime *soc_pcm_tx = - pcm->capture_substream->private_data; if (pcm->audio_client != NULL) stop_pcm(pcm); @@ -299,15 +294,6 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&pcm->lock); return -ENOMEM; } - event.event_func = msm_pcm_route_event_handler; - event.priv_data = (void *) pcm; - msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->id, - pcm->audio_client->perf_mode, - pcm->session_id, pcm->capture_substream->stream); - msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->id, - pcm->audio_client->perf_mode, - pcm->session_id, pcm->playback_substream->stream, - event); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pcm->playback_substream = substream; ret = pcm_loopback_set_volume(pcm, pcm->volume); @@ -541,6 +527,10 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, struct msm_pcm_loopback *prtd; pr_debug("%s\n", __func__); + if (!vol) { + pr_err("%s: vol is NULL\n", __func__); + return -ENODEV; + } if ((!substream) || (!substream->runtime)) { pr_debug("%s substream or runtime not found\n", __func__); rc = -ENODEV; diff --git a/4.0/asoc/msm-pcm-q6-noirq.c b/4.0/asoc/msm-pcm-q6-noirq.c index e394f37d..eb8a974e 100644 --- a/4.0/asoc/msm-pcm-q6-noirq.c +++ b/4.0/asoc/msm-pcm-q6-noirq.c @@ -710,6 +710,10 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, struct msm_audio *prtd; pr_debug("%s\n", __func__); + if (!vol) { + pr_err("%s: vol is NULL\n", __func__); + return -ENODEV; + } if (!substream) { pr_err("%s: substream not found\n", __func__); return -ENODEV; diff --git a/4.0/asoc/msm-pcm-q6-v2.c b/4.0/asoc/msm-pcm-q6-v2.c index 64ffe97e..507c0d85 100644 --- a/4.0/asoc/msm-pcm-q6-v2.c +++ b/4.0/asoc/msm-pcm-q6-v2.c @@ -1465,6 +1465,10 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, struct msm_audio *prtd; pr_debug("%s\n", __func__); + if (!vol) { + pr_err("%s: vol is NULL\n", __func__); + return -ENODEV; + } if (!substream) { pr_err("%s substream not found\n", __func__); return -ENODEV; @@ -1508,6 +1512,7 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol, pr_err("%s: substream not found\n", __func__); return -ENODEV; } + soc_prtd = substream->private_data; if (!substream->runtime || !soc_prtd) { pr_err("%s: substream runtime or private_data not found\n", @@ -1728,7 +1733,6 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol, (char)(ucontrol->value.integer.value[i]); /* update chmixer_pspd chmap cached with routing driver as well */ - rtd = substream->private_data; if (rtd) { fe_id = rtd->dai_link->id; chmixer_pspd = pdata ? diff --git a/4.0/dsp/codecs/audio_native.c b/4.0/dsp/codecs/audio_native.c index 93370295..6e249145 100644 --- a/4.0/dsp/codecs/audio_native.c +++ b/4.0/dsp/codecs/audio_native.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 2020, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> #include <linux/module.h> #include "audio_utils.h" +spinlock_t enc_dec_lock; + static int __init audio_native_init(void) { aac_in_init(); @@ -31,6 +33,7 @@ static int __init audio_native_init(void) g711alaw_in_init(); g711mlaw_in_init(); qcelp_in_init(); + spin_lock_init(&enc_dec_lock); return 0; } diff --git a/4.0/dsp/codecs/audio_utils.c b/4.0/dsp/codecs/audio_utils.c index 26e9b0b3..ac934132 100644 --- a/4.0/dsp/codecs/audio_utils.c +++ b/4.0/dsp/codecs/audio_utils.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. */ #include <linux/module.h> @@ -943,8 +943,11 @@ int audio_in_release(struct inode *inode, struct file *file) audio_in_disable(audio); q6asm_audio_client_free(audio->ac); mutex_unlock(&audio->lock); + spin_lock(&enc_dec_lock); kfree(audio->enc_cfg); kfree(audio->codec_cfg); kfree(audio); + file->private_data = NULL; + spin_unlock(&enc_dec_lock); return 0; } diff --git a/4.0/dsp/codecs/audio_utils_aio.c b/4.0/dsp/codecs/audio_utils_aio.c index febbd2a6..67fdc06f 100644 --- a/4.0/dsp/codecs/audio_utils_aio.c +++ b/4.0/dsp/codecs/audio_utils_aio.c @@ -1,6 +1,6 @@ /* Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2020, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -630,9 +630,11 @@ int audio_aio_release(struct inode *inode, struct file *file) #ifdef CONFIG_DEBUG_FS debugfs_remove(audio->dentry); #endif + spin_lock(&enc_dec_lock); kfree(audio->codec_cfg); kfree(audio); file->private_data = NULL; + spin_unlock(&enc_dec_lock); mutex_unlock(&lock); return 0; } diff --git a/4.0/dsp/codecs/q6audio_common.h b/4.0/dsp/codecs/q6audio_common.h index c37813ed..67003fea 100644 --- a/4.0/dsp/codecs/q6audio_common.h +++ b/4.0/dsp/codecs/q6audio_common.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2017, 2020 The Linux Foundation. All rights reserved. */ @@ -9,7 +9,7 @@ #include <dsp/apr_audio-v2.h> #include <dsp/q6asm-v2.h> - +extern spinlock_t enc_dec_lock; void q6_audio_cb(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv); diff --git a/4.0/dsp/codecs/q6audio_v2.c b/4.0/dsp/codecs/q6audio_v2.c index c98ef1c4..6a402f53 100644 --- a/4.0/dsp/codecs/q6audio_v2.c +++ b/4.0/dsp/codecs/q6audio_v2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2013, 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2015-2017, 2020 The Linux Foundation. All rights reserved. */ #include <linux/module.h> @@ -21,6 +21,11 @@ void q6asm_in_cb(uint32_t opcode, uint32_t token, struct q6audio_in *audio = (struct q6audio_in *)priv; unsigned long flags; + spin_lock(&enc_dec_lock); + if (audio == NULL) { + pr_err("%s: failed to get q6audio value\n", __func__); + goto error; + } pr_debug("%s:session id %d: opcode[0x%x]\n", __func__, audio->ac->session, opcode); @@ -58,6 +63,8 @@ void q6asm_in_cb(uint32_t opcode, uint32_t token, break; } spin_unlock_irqrestore(&audio->dsp_lock, flags); +error: + spin_unlock(&enc_dec_lock); } void audio_in_get_dsp_frames(void *priv, diff --git a/4.0/dsp/codecs/q6audio_v2_aio.c b/4.0/dsp/codecs/q6audio_v2_aio.c index ea8b84de..ecd14dad 100644 --- a/4.0/dsp/codecs/q6audio_v2_aio.c +++ b/4.0/dsp/codecs/q6audio_v2_aio.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2012-2018, 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #include <linux/module.h> @@ -43,9 +43,10 @@ void audio_aio_cb(uint32_t opcode, uint32_t token, struct q6audio_aio *audio = (struct q6audio_aio *)priv; union msm_audio_event_payload e_payload; + spin_lock(&enc_dec_lock); if (audio == NULL) { pr_err("%s: failed to get q6audio value\n", __func__); - return; + goto error; } switch (opcode) { case ASM_DATA_EVENT_WRITE_DONE_V2: @@ -111,6 +112,8 @@ void audio_aio_cb(uint32_t opcode, uint32_t token, default: break; } +error: + spin_unlock(&enc_dec_lock); } int extract_meta_out_info(struct q6audio_aio *audio, diff --git a/4.0/dsp/msm_audio_ion_vm.c b/4.0/dsp/msm_audio_ion_vm.c index f9635b33..a8440375 100644 --- a/4.0/dsp/msm_audio_ion_vm.c +++ b/4.0/dsp/msm_audio_ion_vm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. */ #include <linux/init.h> @@ -564,6 +564,7 @@ static int msm_audio_ion_map_buf(void *handle, dma_addr_t *paddr, if (rc) { pr_err("%s: failed to do smmu map, err = %d\n", __func__, rc); + msm_audio_dma_buf_unmap((struct dma_buf *) handle); goto err; } } diff --git a/4.0/dsp/q6afe.c b/4.0/dsp/q6afe.c index 9659e74a..16d15678 100644 --- a/4.0/dsp/q6afe.c +++ b/4.0/dsp/q6afe.c @@ -7020,7 +7020,7 @@ static int afe_sidetone_iir(u16 tx_port_id) * Set IIR enable params */ param_hdr.module_id = mid; - param_hdr.param_id = INSTANCE_ID_0; + param_hdr.instance_id = INSTANCE_ID_0; param_hdr.param_id = AFE_PARAM_ID_ENABLE; param_hdr.param_size = sizeof(enable); enable.enable = iir_enable; diff --git a/4.0/dsp/q6asm.c b/4.0/dsp/q6asm.c index 0bbfc728..8314df74 100644 --- a/4.0/dsp/q6asm.c +++ b/4.0/dsp/q6asm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -2551,7 +2551,7 @@ void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size, /* To make it more robust, we could loop and get the * next avail buf, its risky though */ - pr_err("%s: Next buf idx[0x%x] not available, dir[%d]\n", + pr_debug("%s: Next buf idx[0x%x] not available, dir[%d]\n", __func__, idx, dir); mutex_unlock(&port->lock); return NULL; @@ -10906,14 +10906,25 @@ EXPORT_SYMBOL(q6asm_get_path_delay); int q6asm_get_apr_service_id(int session_id) { + int service_id; + pr_debug("%s:\n", __func__); if (session_id <= 0 || session_id > ASM_ACTIVE_STREAMS_ALLOWED) { pr_err("%s: invalid session_id = %d\n", __func__, session_id); return -EINVAL; } - - return ((struct apr_svc *)(session[session_id].ac)->apr)->id; + mutex_lock(&session[session_id].mutex_lock_per_session); + if (session[session_id].ac != NULL) + if ((session[session_id].ac)->apr != NULL) { + service_id = ((struct apr_svc *) + (session[session_id].ac)->apr)->id; + mutex_unlock( + &session[session_id].mutex_lock_per_session); + return service_id; + } + mutex_unlock(&session[session_id].mutex_lock_per_session); + return -EINVAL; } uint8_t q6asm_get_asm_stream_id(int session_id) diff --git a/4.0/include/soc/soundwire.h b/4.0/include/soc/soundwire.h index 59e7d417..37a00c75 100644 --- a/4.0/include/soc/soundwire.h +++ b/4.0/include/soc/soundwire.h @@ -10,6 +10,13 @@ #include <linux/mod_devicetable.h> #include <linux/irqdomain.h> +#define SWR_CLK_RATE_0P6MHZ 600000 +#define SWR_CLK_RATE_1P2MHZ 1200000 +#define SWR_CLK_RATE_2P4MHZ 2400000 +#define SWR_CLK_RATE_4P8MHZ 4800000 +#define SWR_CLK_RATE_9P6MHZ 9600000 +#define SWR_CLK_RATE_11P2896MHZ 1128960 + extern struct bus_type soundwire_type; /* Soundwire supports max. of 8 channels per port */ diff --git a/4.0/include/soc/swr-wcd.h b/4.0/include/soc/swr-wcd.h index 4ec50944..0c091278 100644 --- a/4.0/include/soc/swr-wcd.h +++ b/4.0/include/soc/swr-wcd.h @@ -32,6 +32,7 @@ struct swr_mstr_port { }; #define MCLK_FREQ 9600000 +#define MCLK_FREQ_LP 600000 #define MCLK_FREQ_NATIVE 11289600 #if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \ diff --git a/4.0/soc/pinctrl-lpi.c b/4.0/soc/pinctrl-lpi.c index 2b9e52e9..4df9791c 100644 --- a/4.0/soc/pinctrl-lpi.c +++ b/4.0/soc/pinctrl-lpi.c @@ -497,6 +497,7 @@ int lpi_pinctrl_suspend(struct device *dev) { int ret = 0; + trace_printk("%s: system suspend\n", __func__); dev_dbg(dev, "%s: system suspend\n", __func__); if ((!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev))) { @@ -533,6 +534,7 @@ static struct notifier_block service_nb = { static void lpi_pinctrl_ssr_disable(struct device *dev, void *data) { + trace_printk("%s: enter\n", __func__); lpi_dev_up = false; lpi_pinctrl_suspend(dev); } diff --git a/4.0/soc/swr-mstr-ctrl.c b/4.0/soc/swr-mstr-ctrl.c index 17b9ed79..23ccd234 100644 --- a/4.0/soc/swr-mstr-ctrl.c +++ b/4.0/soc/swr-mstr-ctrl.c @@ -25,6 +25,8 @@ #include "swrm_registers.h" #include "swr-mstr-ctrl.h" +#define SWR_NUM_PORTS 4 /* TODO - Get this info from DT */ + #define SWRM_FRAME_SYNC_SEL 4000 /* 4KHz */ #define SWRM_FRAME_SYNC_SEL_NATIVE 3675 /* 3.675KHz */ #define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700 @@ -94,6 +96,42 @@ static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm); static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr); static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val); + +static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq) +{ + int clk_div = 0; + u8 div_val = 0; + + if (!mclk_freq || !bus_clk_freq) + return 0; + + clk_div = (mclk_freq / bus_clk_freq); + + switch (clk_div) { + case 32: + div_val = 5; + break; + case 16: + div_val = 4; + break; + case 8: + div_val = 3; + break; + case 4: + div_val = 2; + break; + case 2: + div_val = 1; + break; + case 1: + default: + div_val = 0; + break; + } + + return div_val; +} + static bool swrm_is_msm_variant(int val) { return (val == SWRM_VERSION_1_3); @@ -326,33 +364,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; } @@ -959,6 +1041,49 @@ end: return is_removed; } +int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq) +{ + if (!bus_clk_freq) + return mclk_freq; + + if (mclk_freq == SWR_CLK_RATE_9P6MHZ) { + if (bus_clk_freq <= SWR_CLK_RATE_0P6MHZ) + bus_clk_freq = SWR_CLK_RATE_0P6MHZ; + else if (bus_clk_freq <= SWR_CLK_RATE_1P2MHZ) + bus_clk_freq = SWR_CLK_RATE_1P2MHZ; + else if (bus_clk_freq <= SWR_CLK_RATE_2P4MHZ) + bus_clk_freq = SWR_CLK_RATE_2P4MHZ; + else if (bus_clk_freq <= SWR_CLK_RATE_4P8MHZ) + bus_clk_freq = SWR_CLK_RATE_4P8MHZ; + else if (bus_clk_freq <= SWR_CLK_RATE_9P6MHZ) + bus_clk_freq = SWR_CLK_RATE_9P6MHZ; + } else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ) + bus_clk_freq = SWR_CLK_RATE_11P2896MHZ; + + return bus_clk_freq; +} + +static int swrm_update_bus_clk(struct swr_mstr_ctrl *swrm) +{ + int ret = 0; + int agg_clk = 0; + int i; + + for (i = 0; i < SWR_MSTR_PORT_LEN; i++) + agg_clk += swrm->mport_cfg[i].ch_rate; + + if (agg_clk) + swrm->bus_clk = swrm_get_clk_div_rate(swrm->mclk_freq, + agg_clk); + else + swrm->bus_clk = swrm->mclk_freq; + + dev_dbg(swrm->dev, "%s: all_port_clk: %d, bus_clk: %d\n", + __func__, agg_clk, swrm->bus_clk); + + return ret; +} + static void swrm_disable_ports(struct swr_master *master, u8 bank) { @@ -1225,13 +1350,15 @@ static void swrm_apply_port_config(struct swr_master *master) static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable) { u8 bank; - u32 value, n_row, n_col; + u32 value = 0, n_row = 0, n_col = 0; u32 row = 0, col = 0; + int bus_clk_div_factor; int ret; u8 ssp_period = 0; struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master); int mask = (SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK | SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK | + SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_BMSK | SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_BMSK); u8 inactive_bank; int frame_sync = SWRM_FRAME_SYNC_SEL; @@ -1292,13 +1419,17 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable) clear_bit(DISABLE_PENDING, &swrm->port_req_pending); swrm_disable_ports(master, bank); } - dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d\n", - __func__, enable, swrm->num_cfg_devs); + dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d freq %d\n", + __func__, enable, swrm->num_cfg_devs, swrm->mclk_freq); if (enable) { /* set col = 16 */ n_col = SWR_MAX_COL; col = SWRM_COL_16; + if (swrm->bus_clk == MCLK_FREQ_LP) { + n_col = SWR_MIN_COL; + col = SWRM_COL_02; + } } else { /* * Do not change to col = 2 if there are still active ports @@ -1313,25 +1444,26 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable) } /* Use default 50 * x, frame shape. Change based on mclk */ if (swrm->mclk_freq == MCLK_FREQ_NATIVE) { - dev_dbg(swrm->dev, "setting 64 x %d frameshape\n", - n_col ? 16 : 2); + dev_dbg(swrm->dev, "setting 64 x %d frameshape\n", col); n_row = SWR_ROW_64; row = SWRM_ROW_64; frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE; } else { - dev_dbg(swrm->dev, "setting 50 x %d frameshape\n", - n_col ? 16 : 2); + dev_dbg(swrm->dev, "setting 50 x %d frameshape\n", col); n_row = SWR_ROW_50; row = SWRM_ROW_50; frame_sync = SWRM_FRAME_SYNC_SEL; } ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync); - dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period); - + bus_clk_div_factor = swrm_get_clk_div(swrm->mclk_freq, swrm->bus_clk); + dev_dbg(swrm->dev, "%s: ssp_period: %d, bus_clk_div:%d\n", + __func__, ssp_period, bus_clk_div_factor); value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank)); value &= (~mask); value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) | (n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) | + (bus_clk_div_factor << + SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_SHFT) | ((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT)); swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK_ADDR(bank), value); @@ -1435,6 +1567,11 @@ static int swrm_connect_port(struct swr_master *master, mport->port_en = true; mport->req_ch |= mstr_ch_msk; master->port_en_mask |= (1 << mstr_port_id); + if (swrm->clk_stop_mode0_supp && + (mport->ch_rate < portinfo->ch_rate[i])) { + mport->ch_rate = portinfo->ch_rate[i]; + swrm_update_bus_clk(swrm); + } } master->num_port += portinfo->num_port; set_bit(ENABLE_PENDING, &swrm->port_req_pending); @@ -1497,6 +1634,10 @@ static int swrm_disconnect_port(struct swr_master *master, } port_req->req_ch &= ~portinfo->ch_en[i]; mport->req_ch &= ~mstr_ch_mask; + if (swrm->clk_stop_mode0_supp && !mport->req_ch) { + mport->ch_rate = 0; + swrm_update_bus_clk(swrm); + } } master->num_port -= portinfo->num_port; set_bit(DISABLE_PENDING, &swrm->port_req_pending); @@ -1869,6 +2010,11 @@ handle_irq: dev_err_ratelimited(swrm->dev, "%s: SWR bus clsh detected\n", __func__); + swrm->intr_mask &= + ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET; + swr_master_write(swrm, + SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, + swrm->intr_mask); break; case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW: dev_dbg(swrm->dev, "%s: SWR read FIFO overflow\n", @@ -2142,22 +2288,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); } @@ -2172,22 +2311,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); } @@ -2421,9 +2549,10 @@ static int swrm_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n", __func__, "qcom,swr-num-dev"); } else { - if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) { + if (swrm->num_dev > SWRM_NUM_AUTO_ENUM_SLAVES) { dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n", - __func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES); + __func__, swrm->num_dev, + SWRM_NUM_AUTO_ENUM_SLAVES); ret = -EINVAL; goto err_pdata_fail; } @@ -2890,7 +3019,23 @@ static int swrm_runtime_suspend(struct device *dev) mutex_unlock(&swrm->reslock); enable_bank_switch(swrm, 0, SWR_ROW_50, SWR_MIN_COL); mutex_lock(&swrm->reslock); - swrm_clk_pause(swrm); + if (!swrm->clk_stop_mode0_supp) { + swrm_clk_pause(swrm); + } else { + /* Mask bus clash interrupt */ + swrm->intr_mask &= ~((u32)0x08); + swr_master_write(swrm, + SWRM_INTERRUPT_MASK_ADDR, + swrm->intr_mask); + swr_master_write(swrm, + SWR_MSTR_RX_SWRM_CPU_INTERRUPT_EN, + swrm->intr_mask); + mutex_unlock(&swrm->reslock); + /* clock stop sequence */ + swrm_cmd_fifo_wr_cmd(swrm, 0x2, 0xF, 0xF, + SWRS_SCP_CONTROL); + mutex_lock(&swrm->reslock); + } swr_master_write(swrm, SWRM_COMP_CFG_ADDR, 0x00); list_for_each_entry(swr_dev, &mstr->devices, dev_list) { ret = swr_device_down(swr_dev); @@ -3166,12 +3311,19 @@ 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->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); break; case SWR_DEVICE_SSR_UP: /* wait for clk voting to be zero */ @@ -3214,7 +3366,12 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) mutex_lock(&swrm->reslock); list_for_each_entry(swr_dev, &mstr->devices, dev_list) { ret = swr_reset_device(swr_dev); - if (ret) { + if (ret == -ENODEV) { + dev_dbg_ratelimited(swrm->dev, + "%s slave reset not implemented\n", + __func__); + ret = 0; + } else if (ret) { dev_err(swrm->dev, "%s: failed to reset swr device %d\n", __func__, swr_dev->dev_num); diff --git a/4.0/soc/swr-mstr-ctrl.h b/4.0/soc/swr-mstr-ctrl.h index 85f3e364..ce0b64d5 100644 --- a/4.0/soc/swr-mstr-ctrl.h +++ b/4.0/soc/swr-mstr-ctrl.h @@ -26,6 +26,7 @@ #define SWR_ROW_48 0 #define SWR_ROW_50 1 #define SWR_ROW_64 3 +#define SWR_COL_04 1 /* Cols = 4 */ #define SWR_MAX_COL 7 /* Cols = 16 */ #define SWR_MIN_COL 0 /* Cols = 2 */ @@ -42,7 +43,7 @@ #define SWR_MAX_CH_PER_PORT 8 -#define SWR_MAX_SLAVE_DEVICES 11 +#define SWRM_NUM_AUTO_ENUM_SLAVES 6 enum { SWR_MSTR_PAUSE, @@ -81,7 +82,6 @@ struct swrm_mports { bool port_en; u8 ch_en; u8 req_ch; - u8 ch_rate; u8 offset1; u8 offset2; u8 sinterval; @@ -91,6 +91,7 @@ struct swrm_mports { u8 blk_pack_mode; u8 word_length; u8 lane_ctrl; + u32 ch_rate; }; struct swrm_port_type { diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 534cd2d9..883f8107 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -818,6 +818,28 @@ static int tx_macro_enable_micbias(struct snd_soc_dapm_widget *w, return 0; } +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, BOLERO_CDC_TX0_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, BOLERO_CDC_TX1_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, BOLERO_CDC_TX2_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec3_enum, BOLERO_CDC_TX3_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec4_enum, BOLERO_CDC_TX4_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec5_enum, BOLERO_CDC_TX5_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec6_enum, BOLERO_CDC_TX6_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec7_enum, BOLERO_CDC_TX7_TX_PATH_CFG0, 5, + cf_text); + static int tx_macro_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1478,6 +1500,22 @@ static const struct snd_kcontrol_new tx_macro_snd_controls[] = { BOLERO_CDC_TX7_TX_VOL_CTL, 0, -84, 40, digital_gain), + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_SINGLE_EXT("DEC0_BCS Switch", SND_SOC_NOPM, 0, 1, 0, tx_macro_get_bcs, tx_macro_set_bcs), }; diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index a1bbd0bd..aa864ddb 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -369,9 +369,9 @@ void q6lsm_client_free(struct lsm_client *client) pr_err("%s: Invalid Session %d\n", __func__, client->session); return; } - mutex_lock(&session_lock); apr_deregister(client->apr); client->mmap_apr = NULL; + mutex_lock(&session_lock); q6lsm_session_free(client); q6lsm_mmap_apr_dereg(); mutex_destroy(&client->cmd_lock); |