diff options
author | Wilson Sung <wilsonsung@google.com> | 2021-03-19 17:27:07 +0800 |
---|---|---|
committer | Wilson Sung <wilsonsung@google.com> | 2021-03-19 17:31:38 +0800 |
commit | e4ec5db336f06b9cd8d94a9e3af527b60dfa3973 (patch) | |
tree | 59714d26952a06278a16bd10e1d033b276264584 | |
parent | 935f0b18ffed97fed2aa4de0a1ccb3152ad7c317 (diff) | |
parent | 8b44f642a7e2cd83939cc27cfc3c067abedfbde0 (diff) | |
download | msm-extra-e4ec5db336f06b9cd8d94a9e3af527b60dfa3973.tar.gz |
Merge branch LA.UM.9.12.R1.11.00.00.597.108 into qcom-msm-4.19-7250-audio-drivers.lnx.4.0.r3
Change-Id: I0cef4ccfb5e280c4c21009fa9d1ea7f2ad7d2637
-rw-r--r-- | asoc/codecs/bolero/tx-macro.c | 16 | ||||
-rw-r--r-- | asoc/codecs/bolero/va-macro.c | 20 | ||||
-rw-r--r-- | asoc/codecs/bolero/wsa-macro.c | 14 | ||||
-rw-r--r-- | asoc/codecs/wsa881x.c | 227 | ||||
-rw-r--r-- | asoc/codecs/wsa883x/wsa883x.c | 80 | ||||
-rw-r--r-- | asoc/codecs/wsa883x/wsa883x.h | 5 | ||||
-rw-r--r-- | asoc/kona.c | 264 | ||||
-rw-r--r-- | asoc/msm-pcm-q6-v2.c | 11 | ||||
-rw-r--r-- | asoc/msm-pcm-routing-v2.c | 21 | ||||
-rw-r--r-- | dsp/audio_cal_utils.c | 25 | ||||
-rw-r--r-- | dsp/audio_calibration.c | 3 | ||||
-rw-r--r-- | dsp/msm_audio_ion.c | 11 | ||||
-rw-r--r-- | dsp/msm_audio_ion_vm.c | 10 | ||||
-rw-r--r-- | dsp/q6afe.c | 230 | ||||
-rw-r--r-- | dsp/q6asm.c | 6 | ||||
-rw-r--r-- | dsp/q6lsm.c | 8 | ||||
-rw-r--r-- | include/dsp/apr_audio-v2.h | 26 | ||||
-rw-r--r-- | include/dsp/audio_cal_utils.h | 4 | ||||
-rw-r--r-- | include/dsp/q6afe-v2.h | 4 | ||||
-rw-r--r-- | soc/swr-mstr-ctrl.c | 34 | ||||
-rw-r--r-- | soc/swr-mstr-ctrl.h | 4 |
21 files changed, 825 insertions, 198 deletions
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 158f3500..de04e1e9 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -234,11 +234,11 @@ static int tx_macro_mclk_enable(struct tx_macro_priv *tx_priv, } bolero_clk_rsc_fs_gen_request(tx_priv->dev, true); + regcache_mark_dirty(regmap); + regcache_sync_region(regmap, + TX_START_OFFSET, + TX_MAX_OFFSET); if (tx_priv->tx_mclk_users == 0) { - regcache_mark_dirty(regmap); - regcache_sync_region(regmap, - TX_START_OFFSET, - TX_MAX_OFFSET); /* 9.6MHz MCLK, set value 0x00 if other frequency */ regmap_update_bits(regmap, BOLERO_CDC_TX_TOP_CSR_FREQ_MCLK, 0x01, 0x01); @@ -2445,11 +2445,7 @@ static int tx_macro_register_event_listener(struct snd_soc_component *component, ret = swrm_wcd_notify( tx_priv->swr_ctrl_data[0].tx_swr_pdev, SWR_REGISTER_WAKEUP, NULL); - msm_cdc_pinctrl_set_wakeup_capable( - tx_priv->tx_swr_gpio_p, false); } else { - msm_cdc_pinctrl_set_wakeup_capable( - tx_priv->tx_swr_gpio_p, true); ret = swrm_wcd_notify( tx_priv->swr_ctrl_data[0].tx_swr_pdev, SWR_DEREGISTER_WAKEUP, NULL); @@ -2484,6 +2480,8 @@ static int tx_macro_tx_va_mclk_enable(struct tx_macro_priv *tx_priv, __func__); goto exit; } + msm_cdc_pinctrl_set_wakeup_capable( + tx_priv->tx_swr_gpio_p, false); } clk_tx_ret = bolero_clk_rsc_request_clock(tx_priv->dev, @@ -2612,6 +2610,8 @@ tx_clk: TX_CORE_CLK, false); if (tx_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_set_wakeup_capable( + tx_priv->tx_swr_gpio_p, true); ret = msm_cdc_pinctrl_select_sleep_state( tx_priv->tx_swr_gpio_p); if (ret < 0) { diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index 5ce2ec12..2e369952 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -388,9 +388,6 @@ static int va_macro_swr_pwr_event_v2(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->swr_ctrl_data) { @@ -402,12 +399,8 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, dev_dbg(va_dev, "%s: clock switch failed\n", __func__); } - msm_cdc_pinctrl_set_wakeup_capable( - va_priv->va_swr_gpio_p, false); break; case SND_SOC_DAPM_POST_PMD: - 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( @@ -441,9 +434,6 @@ 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) { @@ -563,9 +553,12 @@ static int va_macro_tx_va_mclk_enable(struct va_macro_priv *va_priv, (enable ? "enable" : "disable"), va_priv->va_mclk_users); if (enable) { - if (va_priv->swr_clk_users == 0) + if (va_priv->swr_clk_users == 0) { msm_cdc_pinctrl_select_active_state( va_priv->va_swr_gpio_p); + msm_cdc_pinctrl_set_wakeup_capable( + va_priv->va_swr_gpio_p, false); + } clk_tx_ret = bolero_clk_rsc_request_clock(va_priv->dev, TX_CORE_CLK, TX_CORE_CLK, @@ -658,9 +651,12 @@ static int va_macro_tx_va_mclk_enable(struct va_macro_priv *va_priv, TX_CORE_CLK, TX_CORE_CLK, false); - if (va_priv->swr_clk_users == 0) + if (va_priv->swr_clk_users == 0) { + msm_cdc_pinctrl_set_wakeup_capable( + va_priv->va_swr_gpio_p, true); msm_cdc_pinctrl_select_sleep_state( va_priv->va_swr_gpio_p); + } } return 0; diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index ca7391d0..5ace96db 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -445,8 +445,8 @@ static struct snd_soc_dai_driver wsa_macro_dai[] = { static const struct wsa_macro_reg_mask_val wsa_macro_spkr_default[] = { {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80}, {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80}, - {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01}, - {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x1F, 0x19}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x1F, 0x19}, {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x58}, {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x58}, }; @@ -454,8 +454,8 @@ static const struct wsa_macro_reg_mask_val wsa_macro_spkr_default[] = { static const struct wsa_macro_reg_mask_val wsa_macro_spkr_mode1[] = { {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x00}, {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x00}, - {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x00}, - {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x00}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x1F, 0x18}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x1F, 0x18}, {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x7C, 0x44}, {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x7C, 0x44}, }; @@ -2744,10 +2744,10 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = { static const struct wsa_macro_reg_mask_val wsa_macro_reg_init[] = { {BOLERO_CDC_WSA_BOOST0_BOOST_CFG1, 0x3F, 0x12}, {BOLERO_CDC_WSA_BOOST0_BOOST_CFG2, 0x1C, 0x08}, - {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x1E, 0x18}, + {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x1E, 0x0C}, {BOLERO_CDC_WSA_BOOST1_BOOST_CFG1, 0x3F, 0x12}, {BOLERO_CDC_WSA_BOOST1_BOOST_CFG2, 0x1C, 0x08}, - {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x1E, 0x18}, + {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x1E, 0x0C}, {BOLERO_CDC_WSA_BOOST0_BOOST_CTL, 0x70, 0x58}, {BOLERO_CDC_WSA_BOOST1_BOOST_CTL, 0x70, 0x58}, {BOLERO_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08}, @@ -2758,8 +2758,6 @@ static const struct wsa_macro_reg_mask_val wsa_macro_reg_init[] = { {BOLERO_CDC_WSA_TX1_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {BOLERO_CDC_WSA_TX2_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {BOLERO_CDC_WSA_TX3_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, - {BOLERO_CDC_WSA_COMPANDER0_CTL3, 0x80, 0x80}, - {BOLERO_CDC_WSA_COMPANDER1_CTL3, 0x80, 0x80}, {BOLERO_CDC_WSA_COMPANDER0_CTL7, 0x01, 0x01}, {BOLERO_CDC_WSA_COMPANDER1_CTL7, 0x01, 0x01}, {BOLERO_CDC_WSA_RX0_RX_PATH_CFG0, 0x01, 0x01}, diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c index b23bc01f..52f29d88 100644 --- a/asoc/codecs/wsa881x.c +++ b/asoc/codecs/wsa881x.c @@ -109,6 +109,11 @@ struct wsa881x_priv { int (*register_notifier)(void *handle, struct notifier_block *nblock, bool enable); + struct dentry *debugfs_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; }; /* from bolero to WSA events */ @@ -146,14 +151,6 @@ static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC; module_param(wsa881x_ocp_poll_timer_sec, int, 0664); MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling"); -static struct wsa881x_priv *dbgwsa881x; -static struct dentry *debugfs_wsa881x_dent; -static struct dentry *debugfs_peek; -static struct dentry *debugfs_poke; -static struct dentry *debugfs_reg_dump; -static unsigned int read_data; -static unsigned int devnum; - static int32_t wsa881x_resource_acquire(struct snd_soc_component *component, bool enable); @@ -401,30 +398,28 @@ static bool is_swr_slv_reg_readable(int reg) return ret; } -static ssize_t wsa881x_swrslave_reg_show(char __user *ubuf, size_t count, - loff_t *ppos) +static ssize_t wsa881x_swrslave_reg_show(struct swr_device *pdev, char __user *ubuf, + size_t count, loff_t *ppos) { int i, reg_val, len; ssize_t total = 0; char tmp_buf[SWR_SLV_MAX_BUF_LEN]; - if (!ubuf || !ppos || (devnum == 0)) + if (!ubuf || !ppos) return 0; for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); - i <= SWR_SLV_MAX_REG_ADDR; i++) { + i <= SWR_SLV_MAX_REG_ADDR; i++) { if (!is_swr_slv_reg_readable(i)) continue; - swr_read(dbgwsa881x->swr_slave, devnum, - i, ®_val, 1); - len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i, - (reg_val & 0xFF)); + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); if (len < 0) { pr_err("%s: fail to fill the buffer\n", __func__); total = -EFAULT; goto copy_err; } - if ((total + len) >= count - 1) break; if (copy_to_user((ubuf + total), tmp_buf, len)) { @@ -432,53 +427,84 @@ static ssize_t wsa881x_swrslave_reg_show(char __user *ubuf, size_t count, total = -EFAULT; goto copy_err; } - *ppos += len; total += len; + *ppos += len; } copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; return total; } +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return wsa881x_swrslave_reg_show(pdev, ubuf, count, ppos); +} + static ssize_t codec_debug_read(struct file *file, char __user *ubuf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { char lbuf[SWR_SLV_RD_BUF_LEN]; - char *access_str; - ssize_t ret_cnt; + struct swr_device *pdev = NULL; + struct wsa881x_priv *wsa881x = NULL; if (!count || !file || !ppos || !ubuf) return -EINVAL; - access_str = file->private_data; + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + wsa881x = swr_get_dev_data(pdev); + if (!wsa881x) + return -EINVAL; + if (*ppos < 0) return -EINVAL; - if (!strcmp(access_str, "swrslave_peek")) { - snprintf(lbuf, sizeof(lbuf), "0x%x\n", (read_data & 0xFF)); - ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf, - strnlen(lbuf, 7)); - } else if (!strcmp(access_str, "swrslave_reg_dump")) { - ret_cnt = wsa881x_swrslave_reg_show(ubuf, count, ppos); - } else { - pr_err("%s: %s not permitted to read\n", __func__, access_str); - ret_cnt = -EPERM; - } - return ret_cnt; + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (wsa881x->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); } -static ssize_t codec_debug_write(struct file *filp, - const char __user *ubuf, size_t cnt, loff_t *ppos) +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) { char lbuf[SWR_SLV_WR_BUF_LEN]; - int rc; + int rc = 0; u32 param[5]; - char *access_str; + struct swr_device *pdev = NULL; + struct wsa881x_priv *wsa881x = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; - if (!filp || !ppos || !ubuf) + wsa881x = swr_get_dev_data(pdev); + if (!wsa881x) + return -EINVAL; + + if (*ppos < 0) return -EINVAL; - access_str = filp->private_data; if (cnt > sizeof(lbuf) - 1) return -EINVAL; @@ -487,32 +513,46 @@ static ssize_t codec_debug_write(struct file *filp, return -EFAULT; lbuf[cnt] = '\0'; - if (!strcmp(access_str, "swrslave_poke")) { - /* write */ - rc = get_parameters(lbuf, param, 3); - if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (param[1] <= 0xFF) && - (rc == 0)) - swr_write(dbgwsa881x->swr_slave, param[2], - param[0], ¶m[1]); - else - rc = -EINVAL; - } else if (!strcmp(access_str, "swrslave_peek")) { - /* read */ - rc = get_parameters(lbuf, param, 2); - if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)) - swr_read(dbgwsa881x->swr_slave, param[1], - param[0], &read_data, 1); - else - rc = -EINVAL; - } else if (!strcmp(access_str, "swrslave_reg_dump")) { - /* reg dump */ - rc = get_parameters(lbuf, param, 1); - if ((rc == 0) && (param[0] > 0) && - (param[0] <= SWR_SLV_MAX_DEVICES)) - devnum = param[0]; - else - rc = -EINVAL; - } + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &wsa881x->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); if (rc == 0) rc = cnt; else @@ -521,12 +561,21 @@ static ssize_t codec_debug_write(struct file *filp, return rc; } -static const struct file_operations codec_debug_ops = { +static const struct file_operations codec_debug_write_ops = { .open = codec_debug_open, .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = codec_debug_open, .read = codec_debug_read, + .write = codec_debug_peek_write, }; +static const struct file_operations codec_debug_dump_ops = { + .open = codec_debug_open, + .read = codec_debug_dump, +}; static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x) { mutex_lock(&wsa881x->res_lock); @@ -1454,27 +1503,31 @@ static int wsa881x_swr_probe(struct swr_device *pdev) wsa881x_gpio_ctrl(wsa881x, true); wsa881x->state = WSA881X_DEV_UP; - if (!debugfs_wsa881x_dent) { - dbgwsa881x = wsa881x; - debugfs_wsa881x_dent = debugfs_create_dir( - "wsa881x_swr_slave", 0); - if (!IS_ERR(debugfs_wsa881x_dent)) { - debugfs_peek = debugfs_create_file("swrslave_peek", - S_IFREG | 0444, debugfs_wsa881x_dent, - (void *) "swrslave_peek", - &codec_debug_ops); - - debugfs_poke = debugfs_create_file("swrslave_poke", - S_IFREG | 0444, debugfs_wsa881x_dent, - (void *) "swrslave_poke", - &codec_debug_ops); - - debugfs_reg_dump = debugfs_create_file( + if (!wsa881x->debugfs_dent) { + wsa881x->debugfs_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(wsa881x->debugfs_dent)) { + wsa881x->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + wsa881x->debugfs_dent, + (void *) pdev, + &codec_debug_read_ops); + + wsa881x->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + wsa881x->debugfs_dent, + (void *) pdev, + &codec_debug_write_ops); + + wsa881x->debugfs_reg_dump = + debugfs_create_file( "swrslave_reg_dump", S_IFREG | 0444, - debugfs_wsa881x_dent, - (void *) "swrslave_reg_dump", - &codec_debug_ops); + wsa881x->debugfs_dent, + (void *) pdev, + &codec_debug_dump_ops); } } @@ -1566,8 +1619,8 @@ static int wsa881x_swr_remove(struct swr_device *pdev) if (wsa881x->register_notifier) wsa881x->register_notifier(wsa881x->handle, &wsa881x->bolero_nblock, false); - debugfs_remove_recursive(debugfs_wsa881x_dent); - debugfs_wsa881x_dent = NULL; + debugfs_remove_recursive(wsa881x->debugfs_dent); + wsa881x->debugfs_dent = NULL; mutex_destroy(&wsa881x->res_lock); mutex_destroy(&wsa881x->temp_lock); snd_soc_unregister_component(&pdev->dev); diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c index 8a5e99e4..31ba5ba7 100644 --- a/asoc/codecs/wsa883x/wsa883x.c +++ b/asoc/codecs/wsa883x/wsa883x.c @@ -481,8 +481,33 @@ static irqreturn_t wsa883x_uvlo_handle_irq(int irq, void *data) static irqreturn_t wsa883x_pa_on_err_handle_irq(int irq, void *data) { - pr_err_ratelimited("%s: interrupt for irq =%d triggered\n", - __func__, irq); + u8 pa_fsm_sta = 0, pa_fsm_err = 0; + struct wsa883x_priv *wsa883x = data; + struct snd_soc_component *component = NULL; + + if (!wsa883x) + return IRQ_NONE; + + component = wsa883x->component; + if (!component) + return IRQ_NONE; + + pa_fsm_sta = (snd_soc_component_read32(component, WSA883X_PA_FSM_STA) + & 0x70); + + if (pa_fsm_sta) + pa_fsm_err = snd_soc_component_read32(component, + WSA883X_PA_FSM_ERR_COND); + pr_err_ratelimited("%s: irq: %d, pa_fsm_sta: %d, pa_fsm_err: %d\n", + __func__, irq, pa_fsm_sta, pa_fsm_err); + + snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x10, 0x10); + snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x10, 0x00); + return IRQ_HANDLED; } @@ -770,6 +795,30 @@ int wsa883x_codec_info_create_codec_entry(struct snd_info_entry *codec_root, } EXPORT_SYMBOL(wsa883x_codec_info_create_codec_entry); +/* + * wsa883x_codec_get_dev_num - returns swr device number + * @component: Codec instance + * + * Return: swr device number on success or negative error + * code on failure. + */ +int wsa883x_codec_get_dev_num(struct snd_soc_component *component) +{ + struct wsa883x_priv *wsa883x; + + if (!component) + return -EINVAL; + + wsa883x = snd_soc_component_get_drvdata(component); + if (!wsa883x) { + pr_err("%s: wsa883x component is NULL\n", __func__); + return -EINVAL; + } + + return wsa883x->swr_slave->dev_num; +} +EXPORT_SYMBOL(wsa883x_codec_get_dev_num); + static int wsa883x_get_compander(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -993,9 +1042,16 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, 0x01, 0x01); /* Added delay as per HW sequence */ usleep_range(250, 300); + wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR); /* Force remove group */ swr_remove_from_group(wsa883x->swr_slave, wsa883x->swr_slave->dev_num); + snd_soc_component_update_bits(component, + WSA883X_VBAT_ADC_FLT_CTL, + 0x0E, 0x06); + snd_soc_component_update_bits(component, + WSA883X_VBAT_ADC_FLT_CTL, + 0x01, 0x01); if (test_bit(SPKR_ADIE_LB, &wsa883x->status_mask)) snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, 0x01, 0x01); @@ -1004,11 +1060,23 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, if (!test_bit(SPKR_ADIE_LB, &wsa883x->status_mask)) wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD); + snd_soc_component_update_bits(component, + WSA883X_VBAT_ADC_FLT_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, + WSA883X_VBAT_ADC_FLT_CTL, + 0x0E, 0x00); + snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x01, 0x00); + snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x10, 0x10); snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, + 0x10, 0x00); + snd_soc_component_update_bits(wsa883x->component, WSA883X_PDM_WD_CTL, 0x01, 0x00); - snd_soc_component_update_bits(wsa883x->component, - WSA883X_PDM_WD_CTL, - 0x01, 0x00); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR); clear_bit(SPKR_STATUS, &wsa883x->status_mask); clear_bit(SPKR_ADIE_LB, &wsa883x->status_mask); break; @@ -1558,7 +1626,7 @@ static int wsa883x_swr_probe(struct swr_device *pdev) "WSA UVLO", wsa883x_uvlo_handle_irq, NULL); wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR, - "WSA PA ERR", wsa883x_pa_on_err_handle_irq, NULL); + "WSA PA ERR", wsa883x_pa_on_err_handle_irq, wsa883x); wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR); diff --git a/asoc/codecs/wsa883x/wsa883x.h b/asoc/codecs/wsa883x/wsa883x.h index e080134e..bb719831 100644 --- a/asoc/codecs/wsa883x/wsa883x.h +++ b/asoc/codecs/wsa883x/wsa883x.h @@ -21,6 +21,7 @@ int wsa883x_set_channel_map(struct snd_soc_component *component, int wsa883x_codec_info_create_codec_entry( struct snd_info_entry *codec_root, struct snd_soc_component *component); +int wsa883x_codec_get_dev_num(struct snd_soc_component *component); #else static int wsa883x_set_channel_map(struct snd_soc_component *component, u8 *port, u8 num_port, unsigned int *ch_mask, @@ -36,6 +37,10 @@ static int wsa883x_codec_info_create_codec_entry( return 0; } +static int wsa883x_codec_get_dev_num(struct snd_soc_component *component) +{ + return 0; +} #endif #endif /* _WSA883X_H */ diff --git a/asoc/kona.c b/asoc/kona.c index 5192e3ec..f5d0ea8e 100644 --- a/asoc/kona.c +++ b/asoc/kona.c @@ -80,12 +80,16 @@ #define ADSP_STATE_READY_TIMEOUT_MS 3000 -#define WSA8810_NAME_1 "wsa881x.20170211" -#define WSA8810_NAME_2 "wsa881x.20170212" +#define WSA8810_NAME_1 "wsa881x.1020170211" +#define WSA8810_NAME_2 "wsa881x.1020170212" +#define WSA8815_NAME_1 "wsa881x.1021170213" +#define WSA8815_NAME_2 "wsa881x.1021170214" #define WCN_CDC_SLIM_RX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX_LITO 3 +#define SWR_MAX_SLAVE_DEVICES 6 + enum { RX_PATH = 0, TX_PATH, @@ -193,7 +197,10 @@ struct msm_asoc_mach_data { struct device_node *fsa_handle; struct clk *lpass_audio_hw_vote; int core_audio_vote_count; + u32 wsa_max_devs; u32 tdm_max_slots; /* Max TDM slots used */ + int (*get_wsa_dev_num)(struct snd_soc_component*); + struct afe_cps_hw_intf_cfg cps_config; }; struct tdm_port { @@ -2689,6 +2696,12 @@ static int msm_get_port_id(int be_id) case MSM_BACKEND_DAI_SENARY_MI2S_TX: afe_port_id = AFE_PORT_ID_SENARY_MI2S_TX; break; + case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0: + afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_RX_0; + break; + case MSM_BACKEND_DAI_WSA_CDC_DMA_TX_0: + afe_port_id = AFE_PORT_ID_WSA_CODEC_DMA_TX_0; + break; case MSM_BACKEND_DAI_VA_CDC_DMA_TX_0: afe_port_id = AFE_PORT_ID_VA_CODEC_DMA_TX_0; break; @@ -4900,6 +4913,121 @@ static int msm_snd_cdc_dma_startup(struct snd_pcm_substream *substream) return ret; } +static void set_cps_config(struct snd_soc_pcm_runtime *rtd, + u32 num_ch, u32 ch_mask) +{ + int i = 0; + int val = 0; + u8 dev_num = 0; + int ch_configured = 0; + int j = 0; + int n = 0; + char wsa_cdc_name[DEV_NAME_STR_LEN]; + struct snd_soc_component *component = NULL; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + if (!pdata) { + pr_err("%s: pdata is NULL\n", __func__); + return; + } + + if (!num_ch) { + pr_err("%s: channel count is 0\n", __func__); + return; + } + + if (!pdata->get_wsa_dev_num) { + pr_err("%s: get_wsa_dev_num is NULL\n", __func__); + return; + } + + if (!pdata->cps_config.spkr_dep_cfg) { + pr_debug("%s: spkr_dep_cfg is NULL\n", __func__); + return; + } + + if (!pdata->cps_config.hw_reg_cfg.lpass_wr_cmd_reg_phy_addr || + !pdata->cps_config.hw_reg_cfg.lpass_rd_cmd_reg_phy_addr || + !pdata->cps_config.hw_reg_cfg.lpass_rd_fifo_reg_phy_addr) { + pr_err("%s: cps static configuration is not set\n", __func__); + return; + } + + pdata->cps_config.lpass_hw_intf_cfg_mode = 1; + + while (ch_configured < num_ch) { + if (!(ch_mask & (1 << i))) { + i++; + continue; + } + + snprintf(wsa_cdc_name, sizeof(wsa_cdc_name), "wsa-codec.%d", + i+1); + + /* Use n to make sure both WSA components are retrieved */ + /* When first WSA component is retrieved adjust looping + variable such that the next time only the remaining part + of the array is traversed */ + for (j = n; j < rtd->card->num_aux_devs; j++) + { + if (msm_codec_conf[j].name_prefix != NULL ) { + if (strstr(msm_codec_conf[j].name_prefix, + "Left")) { + component = soc_find_component_locked( + msm_aux_dev[j].codec_of_node, + NULL); + n = j+1; + break; + } + else if (strstr(msm_codec_conf[j].name_prefix, + "Right")) { + component = soc_find_component_locked( + msm_aux_dev[j].codec_of_node, + NULL); + n = j+1; + break; + } + } + } + + if (!component) { + pr_err("%s: %s component is NULL\n", __func__, + wsa_cdc_name); + return; + } + + dev_num = pdata->get_wsa_dev_num(component); + if (dev_num < 0 || dev_num > SWR_MAX_SLAVE_DEVICES) { + pr_err("%s: invalid slave dev num : %d\n", __func__, + dev_num); + return; + } + + /* Clear stale dev num info */ + pdata->cps_config.spkr_dep_cfg[i].vbatt_pkd_reg_addr &= 0xFFFF; + pdata->cps_config.spkr_dep_cfg[i].temp_pkd_reg_addr &= 0xFFFF; + + val = 0; + + /* bits 20:23 carry swr device number */ + val |= dev_num << 20; + + /* bits 24:27 carry read length in bytes */ + val |= 1 << 24; + + /* Update dev num in packed reg addr */ + pdata->cps_config.spkr_dep_cfg[i].vbatt_pkd_reg_addr |= val; + pdata->cps_config.spkr_dep_cfg[i].temp_pkd_reg_addr |= val; + i++; + ch_configured++; + } + + afe_set_cps_config(msm_get_port_id(dai_link->id), + &pdata->cps_config, ch_mask); +} + static int msm_snd_cdc_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -4947,6 +5075,11 @@ static int msm_snd_cdc_dma_hw_params(struct snd_pcm_substream *substream, goto err; } + if (dai_link->id == MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0 || + dai_link->id == MSM_BACKEND_DAI_WSA_CDC_DMA_RX_1) { + set_cps_config(rtd, user_set_rx_ch, + rx_ch_cdc_dma); + } } break; } @@ -5531,6 +5664,11 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd) WSA_MACRO_SPKR_MODE_1); wsa_macro_set_spkr_gain_offset(component, WSA_MACRO_GAIN_OFFSET_M1P5_DB); + } else if (aux_comp->name != NULL && ( + !strcmp(aux_comp->name, WSA8815_NAME_1) || + !strcmp(aux_comp->name, WSA8815_NAME_2))) { + wsa_macro_set_spkr_mode(component, + WSA_MACRO_SPKR_MODE_DEFAULT); } } } @@ -8229,6 +8367,115 @@ static int msm_audio_ssr_register(struct device *dev) return ret; } +static void parse_cps_configuration(struct platform_device *pdev, + struct msm_asoc_mach_data *pdata) +{ + int ret = 0; + int i = 0, j = 0; + u32 dt_values[MAX_CPS_LEVELS]; + + if (!pdev || !pdata || !pdata->wsa_max_devs) + return; + + pdata->get_wsa_dev_num = wsa883x_codec_get_dev_num; + pdata->cps_config.hw_reg_cfg.num_spkr = pdata->wsa_max_devs; + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,cps_reg_phy_addr", dt_values, + sizeof(dt_values)/sizeof(dt_values[0])); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,cps_reg_phy_addr"); + } else { + pdata->cps_config.hw_reg_cfg.lpass_wr_cmd_reg_phy_addr = + dt_values[0]; + pdata->cps_config.hw_reg_cfg.lpass_rd_cmd_reg_phy_addr = + dt_values[1]; + pdata->cps_config.hw_reg_cfg.lpass_rd_fifo_reg_phy_addr = + dt_values[2]; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,cps_threshold_levels", dt_values, + sizeof(dt_values)/sizeof(dt_values[0]) - 1); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,cps_threshold_levels"); + } else { + pdata->cps_config.hw_reg_cfg.vbatt_lower2_threshold = + dt_values[0]; + pdata->cps_config.hw_reg_cfg.vbatt_lower1_threshold = + dt_values[1]; + } + + pdata->cps_config.spkr_dep_cfg = devm_kzalloc(&pdev->dev, + sizeof(struct lpass_swr_spkr_dep_cfg_t) + * pdata->wsa_max_devs, GFP_KERNEL); + if (!pdata->cps_config.spkr_dep_cfg) { + dev_err(&pdev->dev, "%s: spkr dep cfg alloc failed\n", __func__); + return; + } + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,cps_wsa_vbatt_temp_reg_addr", dt_values, + sizeof(dt_values)/sizeof(dt_values[0]) - 1); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,cps_wsa_vbatt_temp_reg_addr"); + } else { + for (i = 0; i < pdata->wsa_max_devs; i++) { + pdata->cps_config.spkr_dep_cfg[i].vbatt_pkd_reg_addr = + dt_values[0]; + pdata->cps_config.spkr_dep_cfg[i].temp_pkd_reg_addr = + dt_values[1]; + } + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,cps_normal_values", dt_values, + sizeof(dt_values)/sizeof(dt_values[0])); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,cps_normal_values"); + } else { + for (i = 0; i < pdata->wsa_max_devs; i++) { + for (j = 0; j < MAX_CPS_LEVELS; j++) { + pdata->cps_config.spkr_dep_cfg[i]. + value_normal_thrsd[j] = dt_values[j]; + } + } + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,cps_lower1_values", dt_values, + sizeof(dt_values)/sizeof(dt_values[0])); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,cps_lower1_values"); + } else { + for (i = 0; i < pdata->wsa_max_devs; i++) { + for (j = 0; j < MAX_CPS_LEVELS; j++) { + pdata->cps_config.spkr_dep_cfg[i]. + value_low1_thrsd[j] = dt_values[j]; + } + } + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,cps_lower2_values", dt_values, + sizeof(dt_values)/sizeof(dt_values[0])); + if (ret) { + dev_dbg(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,cps_lower2_values"); + } else { + for (i = 0; i < pdata->wsa_max_devs; i++) { + for (j = 0; j < MAX_CPS_LEVELS; j++) { + pdata->cps_config.spkr_dep_cfg[i]. + value_low2_thrsd[j] = dt_values[j]; + } + } + } +} + static int msm_asoc_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; @@ -8300,6 +8547,15 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s: Sound card %s registered\n", __func__, card->name); + /* Get maximum WSA device count for this platform */ + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa-max-devs", &pdata->wsa_max_devs); + if (ret) { + dev_err(&pdev->dev, "%s: No DT match for wsa max devs\n", + __func__); + pdata->wsa_max_devs = 0; + } + ret = of_property_read_u32(pdev->dev.of_node, "qcom,tdm-max-slots", &pdata->tdm_max_slots); if (ret) { @@ -8412,6 +8668,10 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) atomic_set(&(pdata->mi2s_gpio_ref_count[index]), 0); } + /* parse cps configuration from dt */ + if (of_property_read_bool(pdev->dev.of_node, "qcom,cps_reg_phy_addr")) + parse_cps_configuration(pdev, pdata); + /* Register LPASS audio hw vote */ lpass_audio_hw_vote = devm_clk_get(&pdev->dev, "lpass_audio_hw_vote"); if (IS_ERR(lpass_audio_hw_vote)) { diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c index de28f65a..e6a5c1a7 100644 --- a/asoc/msm-pcm-q6-v2.c +++ b/asoc/msm-pcm-q6-v2.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ @@ -1007,9 +1007,12 @@ static int msm_pcm_capture_copy(struct snd_pcm_substream *substream, xfer = size; offset = prtd->in_frame_info[idx].offset; pr_debug("Offset value = %d\n", offset); - if (size == 0 || size < fbytes) { - memset(bufptr + offset + size, 0, fbytes - size); - size = xfer = fbytes; + if (size == 0 || size < prtd->pcm_count) { + memset(bufptr + offset + size, 0, prtd->pcm_count - size); + if (fbytes > prtd->pcm_count) + size = xfer = prtd->pcm_count; + else + size = xfer = fbytes; } if (copy_to_user(buf, bufptr+offset, xfer)) { diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index 03603a2c..7aafe2b9 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include <linux/init.h> @@ -3033,6 +3033,7 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int mux = ucontrol->value.enumerated.item[0]; int lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX; + int lsm_port_idx = 0; u8 fe_idx = 0; if (mux >= e->items) { @@ -3042,6 +3043,7 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, pr_debug("%s: LSM enable %ld\n", __func__, ucontrol->value.integer.value[0]); + lsm_port_idx = ucontrol->value.integer.value[0]; switch (ucontrol->value.integer.value[0]) { case 1: lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX; @@ -3098,6 +3100,10 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, set_lsm_port(lsm_port); msm_routing_get_lsm_fe_idx(kcontrol, &fe_idx); lsm_port_index[fe_idx] = ucontrol->value.integer.value[0]; + /* Set the default AFE LSM Port to 0xffff */ + if(lsm_port_idx <= 0 || lsm_port_idx >= ARRAY_SIZE(lsm_port_text)) + lsm_port = 0xffff; + afe_set_lsm_afe_port_id(fe_idx, lsm_port); return 0; } @@ -22767,9 +22773,9 @@ static int msm_routing_put_app_type_cfg_control(struct snd_kcontrol *kcontrol, memset(app_type_cfg, 0, MAX_APP_TYPES* sizeof(struct msm_pcm_routing_app_type_data)); - if (num_app_types > MAX_APP_TYPES) { - pr_err("%s: number of app types exceed the max supported\n", - __func__); + if (num_app_types > MAX_APP_TYPES || num_app_types < 0) { + pr_err("%s: number of app types %d is invalid\n", + __func__, num_app_types); return -EINVAL; } for (j = 0; j < num_app_types; j++) { @@ -22973,9 +22979,10 @@ static int msm_routing_put_lsm_app_type_cfg_control( int i = 0, j; mutex_lock(&routing_lock); - if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) { - pr_err("%s: number of app types exceed the max supported\n", - __func__); + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > MAX_APP_TYPES) { + pr_err("%s: number of app types %ld is invalid\n", + __func__, ucontrol->value.integer.value[0]); mutex_unlock(&routing_lock); return -EINVAL; } diff --git a/dsp/audio_cal_utils.c b/dsp/audio_cal_utils.c index 8e0d7e03..0f37fda4 100644 --- a/dsp/audio_cal_utils.c +++ b/dsp/audio_cal_utils.c @@ -10,6 +10,8 @@ #include <linux/mutex.h> #include <dsp/audio_cal_utils.h> +struct mutex cal_lock; + static int unmap_memory(struct cal_type_data *cal_type, struct cal_block_data *cal_block); @@ -946,7 +948,9 @@ int cal_utils_dealloc_cal(size_t data_size, void *data, if (ret < 0) goto err; + mutex_lock(&cal_lock); delete_cal_block(cal_block); + mutex_unlock(&cal_lock); err: mutex_unlock(&cal_type->lock); done: @@ -1061,6 +1065,11 @@ void cal_utils_mark_cal_used(struct cal_block_data *cal_block) } EXPORT_SYMBOL(cal_utils_mark_cal_used); +int __init cal_utils_init(void) +{ + mutex_init(&cal_lock); + return 0; +} /** * cal_utils_is_cal_stale * @@ -1070,9 +1079,19 @@ EXPORT_SYMBOL(cal_utils_mark_cal_used); */ bool cal_utils_is_cal_stale(struct cal_block_data *cal_block) { - if ((cal_block) && (cal_block->cal_stale)) - return true; + bool ret = false; - return false; + mutex_lock(&cal_lock); + if (!cal_block) { + pr_err("%s: cal_block is Null", __func__); + goto unlock; + } + + if (cal_block->cal_stale) + ret = true; + +unlock: + mutex_unlock(&cal_lock); + return ret; } EXPORT_SYMBOL(cal_utils_is_cal_stale); diff --git a/dsp/audio_calibration.c b/dsp/audio_calibration.c index a5167be3..854d8821 100644 --- a/dsp/audio_calibration.c +++ b/dsp/audio_calibration.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016-2017, 2020, The Linux Foundation. All rights reserved. */ #include <linux/slab.h> #include <linux/fs.h> @@ -591,6 +591,7 @@ int __init audio_cal_init(void) pr_debug("%s\n", __func__); + cal_utils_init(); memset(&audio_cal, 0, sizeof(audio_cal)); mutex_init(&audio_cal.common_lock); for (; i < MAX_CAL_TYPES; i++) { diff --git a/dsp/msm_audio_ion.c b/dsp/msm_audio_ion.c index 566f8bf1..2bf02fca 100644 --- a/dsp/msm_audio_ion.c +++ b/dsp/msm_audio_ion.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> @@ -67,7 +67,7 @@ static int msm_audio_dma_buf_map(struct dma_buf *dma_buf, dma_addr_t *addr, size_t *len) { - struct msm_audio_alloc_data *alloc_data; + struct msm_audio_alloc_data *alloc_data = NULL; struct device *cb_dev; unsigned long ionflag = 0; int rc = 0; @@ -133,6 +133,7 @@ detach_dma_buf: alloc_data->attach); free_alloc_data: kfree(alloc_data); + alloc_data = NULL; return rc; } @@ -170,6 +171,7 @@ static int msm_audio_dma_buf_unmap(struct dma_buf *dma_buf) list_del(&(alloc_data->list)); kfree(alloc_data); + alloc_data = NULL; break; } } @@ -312,6 +314,11 @@ static int msm_audio_ion_map_buf(struct dma_buf *dma_buf, dma_addr_t *paddr, { int rc = 0; + if (!dma_buf || !paddr || !vaddr || !plen) { + pr_err("%s: Invalid params\n", __func__); + return -EINVAL; + } + rc = msm_audio_ion_get_phys(dma_buf, paddr, plen); if (rc) { pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n", diff --git a/dsp/msm_audio_ion_vm.c b/dsp/msm_audio_ion_vm.c index 37b17b68..ed60c652 100644 --- a/dsp/msm_audio_ion_vm.c +++ b/dsp/msm_audio_ion_vm.c @@ -124,7 +124,7 @@ static int msm_audio_ion_dma_buf_map(struct dma_buf *dma_buf, dma_addr_t *addr, size_t *len) { - struct msm_audio_alloc_data *alloc_data; + struct msm_audio_alloc_data *alloc_data = NULL; struct device *cb_dev; unsigned long ionflag = 0; int rc = 0; @@ -189,6 +189,7 @@ detach_dma_buf: dma_buf_detach(dma_buf, alloc_data->attach); free_alloc_data: kfree(alloc_data); + alloc_data = NULL; return rc; } @@ -262,6 +263,7 @@ static int msm_audio_dma_buf_unmap(void *handle) list_del(&(alloc_data->list)); kfree(alloc_data); + alloc_data = NULL; break; } } else { @@ -278,6 +280,7 @@ static int msm_audio_dma_buf_unmap(void *handle) list_del(&(alloc_data->list)); kfree(alloc_data); + alloc_data = NULL; break; } } @@ -541,6 +544,11 @@ static int msm_audio_ion_map_buf(void *handle, dma_addr_t *paddr, { int rc = 0; + if (!handle || !paddr || !vaddr || !plen) { + pr_err("%s: Invalid params\n", __func__); + return -EINVAL; + } + rc = msm_audio_ion_get_phys((struct dma_buf*) handle, paddr, plen); if (rc) { pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n", diff --git a/dsp/q6afe.c b/dsp/q6afe.c index c9a5c95e..88124df9 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -27,6 +27,7 @@ #define AFE_CLK_TOKEN 1024 #define SP_V4_NUM_MAX_SPKRS SP_V2_NUM_MAX_SPKRS +#define MAX_LSM_SESSIONS 8 struct afe_avcs_payload_port_mapping { u16 port_id; @@ -246,6 +247,10 @@ struct afe_ctl { /* FTM spk params */ uint32_t initial_cal; uint32_t v_vali_flag; + uint32_t num_spkrs; + uint32_t cps_ch_mask; + struct afe_cps_hw_intf_cfg *cps_config; + int lsm_afe_ports[MAX_LSM_SESSIONS]; }; struct afe_clkinfo_per_port { @@ -300,6 +305,8 @@ bool afe_close_done[2] = {true, true}; #define SIZEOF_CFG_CMD(y) \ (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y))) +static bool q6afe_is_afe_lsm_port(int port_id); + static void q6afe_unload_avcs_modules(u16 port_id, int index) { int ret = 0; @@ -2172,6 +2179,70 @@ fail_cmd: return ret; } +static int afe_send_cps_config(int src_port) +{ + int i = 0; + struct param_hdr_v3 param_info; + int ret = -EINVAL; + u8 *packed_payload = NULL; + int cpy_size = 0; + int ch_copied = 0; + size_t param_size = 0; + + if ((-1 == this_afe.vi_tx_port) || (!this_afe.cps_ch_mask) || + (!this_afe.cps_config)) { + pr_err("%s: speaker prot not configured for 0x%x\n", __func__, + src_port); + return -EINVAL; + } + + param_size = sizeof(struct afe_cps_hw_intf_cfg) - + sizeof(this_afe.cps_config->spkr_dep_cfg) + + (sizeof(struct lpass_swr_spkr_dep_cfg_t) + * this_afe.num_spkrs); + + this_afe.cps_config->hw_reg_cfg.num_spkr = this_afe.num_spkrs; + packed_payload = kzalloc(param_size, GFP_KERNEL); + if (packed_payload == NULL) + return -ENOMEM; + + cpy_size = sizeof(struct afe_cps_hw_intf_cfg) - + sizeof(this_afe.cps_config->spkr_dep_cfg); + memcpy(packed_payload, this_afe.cps_config, cpy_size); + + while (ch_copied < this_afe.num_spkrs) { + if (!(this_afe.cps_ch_mask & (1 << i))) { + i++; + continue; + } + + memcpy(packed_payload + cpy_size, + &this_afe.cps_config->spkr_dep_cfg[i], + sizeof(struct lpass_swr_spkr_dep_cfg_t)); + cpy_size += sizeof(struct lpass_swr_spkr_dep_cfg_t); + ch_copied++; + i++; + } + + memset(¶m_info, 0, sizeof(param_info)); + param_info.module_id = AFE_MODULE_SPEAKER_PROTECTION_V4_RX; + param_info.instance_id = INSTANCE_ID_0; + param_info.param_id = AFE_PARAM_ID_CPS_LPASS_HW_INTF_CFG; + param_info.param_size = param_size; + + ret = q6afe_pack_and_set_param_in_band(src_port, + q6audio_get_port_index(src_port), + param_info, packed_payload); + if (ret) + pr_err("%s: port = 0x%x param = 0x%x failed %d\n", __func__, + src_port, param_info.param_id, ret); + + pr_debug("%s: config.pdata.param_id 0x%x status %d 0x%x\n", __func__, + param_info.param_id, ret, src_port); + kfree(packed_payload); + return ret; +} + static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id, union afe_spkr_prot_config *prot_config, uint32_t param_size) { @@ -2312,6 +2383,7 @@ static void afe_send_cal_spv4_tx(int port_id) struct afe_sp_v4_channel_v_vali_cfg *ch_v_vali_cfg; struct afe_sp_v4_param_ex_vi_ftm_cfg *ex_vi_ftm_cfg; struct afe_sp_v4_channel_ex_vi_ftm *ch_ex_vi_ftm_cfg; + uint32_t i = 0; pr_debug("%s: Entry.. port_id %d\n", __func__, port_id); @@ -2372,7 +2444,7 @@ static void afe_send_cal_spv4_tx(int port_id) v4_vi_op_mode->th_r0t0_selection_flag[SP_V2_SPKR_2] = USE_SAFE_R0TO; } - afe_spk_config.v4_vi_op_mode.num_speakers = SP_V2_NUM_MAX_SPKRS; + afe_spk_config.v4_vi_op_mode.num_speakers = this_afe.num_spkrs; if (afe_spk_prot_prepare(port_id, 0, AFE_PARAM_ID_SP_V4_VI_OP_MODE_CFG, &afe_spk_config, @@ -2381,7 +2453,7 @@ static void afe_send_cal_spv4_tx(int port_id) __func__); size = sizeof(struct afe_sp_v4_param_th_vi_r0t0_cfg) + - (SP_V2_NUM_MAX_SPKRS * sizeof(struct afe_sp_v4_channel_r0t0)); + (this_afe.num_spkrs * sizeof(struct afe_sp_v4_channel_r0t0)); tmp_ptr = kzalloc(size, GFP_KERNEL); if (!tmp_ptr) { mutex_unlock( @@ -2395,15 +2467,13 @@ static void afe_send_cal_spv4_tx(int port_id) ch_r0t0_cfg = (struct afe_sp_v4_channel_r0t0 *)(th_vi_r0t0_cfg + 1); - th_vi_r0t0_cfg->num_speakers = SP_V2_NUM_MAX_SPKRS; - ch_r0t0_cfg[SP_V2_SPKR_1].r0_cali_q24 = - (uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_1]; - ch_r0t0_cfg[SP_V2_SPKR_2].r0_cali_q24 = - (uint32_t) this_afe.prot_cfg.r0[SP_V2_SPKR_2]; - ch_r0t0_cfg[SP_V2_SPKR_1].t0_cali_q6 = - (uint32_t) this_afe.prot_cfg.t0[SP_V2_SPKR_1]; - ch_r0t0_cfg[SP_V2_SPKR_2].t0_cali_q6 = - (uint32_t) this_afe.prot_cfg.t0[SP_V2_SPKR_2]; + th_vi_r0t0_cfg->num_speakers = this_afe.num_spkrs; + for (i = 0; i < this_afe.num_spkrs; i++) { + ch_r0t0_cfg[i].r0_cali_q24 = + (uint32_t) this_afe.prot_cfg.r0[i]; + ch_r0t0_cfg[i].t0_cali_q6 = + (uint32_t) this_afe.prot_cfg.t0[i]; + } if (afe_spk_prot_prepare(port_id, 0, AFE_PARAM_ID_SP_V4_VI_R0T0_CFG, (union afe_spkr_prot_config *)tmp_ptr, size)) @@ -2418,7 +2488,7 @@ static void afe_send_cal_spv4_tx(int port_id) (this_afe.vi_tx_port == port_id) && (this_afe.prot_cfg.sp_version >= AFE_API_VERSION_V9)) { size = sizeof(struct afe_sp_v4_param_th_vi_ftm_cfg) + - (SP_V2_NUM_MAX_SPKRS*sizeof(struct afe_sp_v4_channel_ftm_cfg)); + (this_afe.num_spkrs * sizeof(struct afe_sp_v4_channel_ftm_cfg)); tmp_ptr = kzalloc(size, GFP_KERNEL); if (!tmp_ptr) { mutex_unlock( @@ -2431,16 +2501,13 @@ static void afe_send_cal_spv4_tx(int port_id) ch_ftm_cfg = (struct afe_sp_v4_channel_ftm_cfg *)(th_vi_ftm_cfg+1); - th_vi_ftm_cfg->num_ch = SP_V2_NUM_MAX_SPKRS; - ch_ftm_cfg[SP_V2_SPKR_1].wait_time_ms = - this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_1]; - ch_ftm_cfg[SP_V2_SPKR_2].wait_time_ms = - this_afe.th_ftm_cfg.wait_time[SP_V2_SPKR_2]; - ch_ftm_cfg[SP_V2_SPKR_1].ftm_time_ms = - this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_1]; - ch_ftm_cfg[SP_V2_SPKR_2].ftm_time_ms = - this_afe.th_ftm_cfg.ftm_time[SP_V2_SPKR_2]; - + th_vi_ftm_cfg->num_ch = this_afe.num_spkrs; + for (i = 0; i < this_afe.num_spkrs; i++) { + ch_ftm_cfg[i].wait_time_ms = + this_afe.th_ftm_cfg.wait_time[i]; + ch_ftm_cfg[i].ftm_time_ms = + this_afe.th_ftm_cfg.ftm_time[i]; + } if (afe_spk_prot_prepare(port_id, 0, AFE_PARAM_ID_SP_V4_TH_VI_FTM_CFG, (union afe_spkr_prot_config *)tmp_ptr, size)) @@ -2452,8 +2519,8 @@ static void afe_send_cal_spv4_tx(int port_id) MSM_SPKR_PROT_IN_V_VALI_MODE) && (this_afe.vi_tx_port == port_id)) { size = sizeof(struct afe_sp_v4_param_th_vi_v_vali_cfg) + - (SP_V2_NUM_MAX_SPKRS * - sizeof(struct afe_sp_v4_channel_v_vali_cfg)); + (this_afe.num_spkrs * + sizeof(struct afe_sp_v4_channel_v_vali_cfg)); tmp_ptr = kzalloc(size, GFP_KERNEL); if (!tmp_ptr) { mutex_unlock( @@ -2467,16 +2534,13 @@ static void afe_send_cal_spv4_tx(int port_id) ch_v_vali_cfg = (struct afe_sp_v4_channel_v_vali_cfg *)(th_vi_v_vali_cfg + 1); - th_vi_v_vali_cfg->num_ch = SP_V2_NUM_MAX_SPKRS; - ch_v_vali_cfg[SP_V2_SPKR_1].wait_time_ms = - this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_1]; - ch_v_vali_cfg[SP_V2_SPKR_2].wait_time_ms = - this_afe.v_vali_cfg.wait_time[SP_V2_SPKR_2]; - ch_v_vali_cfg[SP_V2_SPKR_1].vali_time_ms = - this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_1]; - ch_v_vali_cfg[SP_V2_SPKR_2].vali_time_ms = - this_afe.v_vali_cfg.vali_time[SP_V2_SPKR_2]; - + th_vi_v_vali_cfg->num_ch = this_afe.num_spkrs; + for (i = 0; i < this_afe.num_spkrs; i++) { + ch_v_vali_cfg[i].wait_time_ms = + this_afe.v_vali_cfg.wait_time[i]; + ch_v_vali_cfg[i].vali_time_ms = + this_afe.v_vali_cfg.vali_time[i]; + } if (afe_spk_prot_prepare(port_id, 0, AFE_PARAM_ID_SP_V4_TH_VI_V_VALI_CFG, (union afe_spkr_prot_config *)tmp_ptr, size)) @@ -2492,7 +2556,7 @@ static void afe_send_cal_spv4_tx(int port_id) (this_afe.vi_tx_port == port_id) && (this_afe.prot_cfg.sp_version >= AFE_API_VERSION_V9)) { size = sizeof(struct afe_sp_v4_param_ex_vi_ftm_cfg) + - (SP_V2_NUM_MAX_SPKRS * + (this_afe.num_spkrs * sizeof(struct afe_sp_v4_channel_ex_vi_ftm)); tmp_ptr = kzalloc(size, GFP_KERNEL); if (!tmp_ptr) { @@ -2514,17 +2578,14 @@ static void afe_send_cal_spv4_tx(int port_id) sizeof(struct afe_sp_v4_param_ex_vi_mode_cfg))) pr_info("%s: ex vi mode cfg failed\n", __func__); - ex_vi_ftm_cfg->num_ch = SP_V2_NUM_MAX_SPKRS; - - ch_ex_vi_ftm_cfg[SP_V2_SPKR_1].wait_time_ms = - this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_1]; - ch_ex_vi_ftm_cfg[SP_V2_SPKR_2].wait_time_ms = - this_afe.ex_ftm_cfg.wait_time[SP_V2_SPKR_2]; - ch_ex_vi_ftm_cfg[SP_V2_SPKR_1].ftm_time_ms = - this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_1]; - ch_ex_vi_ftm_cfg[SP_V2_SPKR_2].ftm_time_ms = - this_afe.ex_ftm_cfg.ftm_time[SP_V2_SPKR_2]; + ex_vi_ftm_cfg->num_ch = this_afe.num_spkrs; + for (i = 0; i < this_afe.num_spkrs; i++) { + ch_ex_vi_ftm_cfg[i].wait_time_ms = + this_afe.ex_ftm_cfg.wait_time[i]; + ch_ex_vi_ftm_cfg[i].ftm_time_ms = + this_afe.ex_ftm_cfg.ftm_time[i]; + } if (afe_spk_prot_prepare(port_id, 0, AFE_PARAM_ID_SP_V4_EX_VI_FTM_CFG, (union afe_spkr_prot_config *)tmp_ptr, size)) @@ -2954,7 +3015,7 @@ static int afe_send_port_topology_id(u16 port_id) } ret = afe_get_cal_topology_id(port_id, &topology_id, AFE_TOPOLOGY_CAL); - if (ret < 0) { + if (ret < 0 && q6afe_is_afe_lsm_port(port_id)) { pr_debug("%s: Check for LSM topology\n", __func__); ret = afe_get_cal_topology_id(port_id, &topology_id, AFE_LSM_TOPOLOGY_CAL); @@ -3291,7 +3352,7 @@ static int send_afe_cal_type(int cal_index, int port_id) this_afe.cal_data[cal_index]); if (cal_block == NULL || cal_utils_is_cal_stale(cal_block)) { - pr_err("%s cal_block not found!!\n", __func__); + pr_err_ratelimited("%s cal_block not found!!\n", __func__); ret = -EINVAL; goto unlock; } @@ -3327,7 +3388,7 @@ void afe_send_cal(u16 port_id) if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) { afe_send_cal_spkr_prot_tx(port_id); ret = send_afe_cal_type(AFE_COMMON_TX_CAL, port_id); - if (ret < 0) + if (ret < 0 && q6afe_is_afe_lsm_port(port_id)) send_afe_cal_type(AFE_LSM_TX_CAL, port_id); } else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) { send_afe_cal_type(AFE_COMMON_RX_CAL, port_id); @@ -5277,6 +5338,11 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, afe_send_hw_delay(port_id, rate); } + if ((this_afe.cps_config) && + (this_afe.vi_rx_port == port_id)) { + afe_send_cps_config(port_id); + } + /* Start SW MAD module */ mad_type = afe_port_get_mad_type(port_id); pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id, @@ -8432,8 +8498,11 @@ int afe_close(int port_id) * even if ramp down configuration failed it is not serious enough to * warrant bailaing out. */ - if (afe_spk_ramp_dn_cfg(port_id) < 0) - pr_err("%s: ramp down configuration failed\n", __func__); + if (q6core_get_avcs_api_version_per_service( + APRV2_IDS_SERVICE_ID_ADSP_AFE_V) < AFE_API_VERSION_V9) { + if (afe_spk_ramp_dn_cfg(port_id) < 0) + pr_err("%s: ramp down config failed\n", __func__); + } stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); @@ -9574,6 +9643,7 @@ int afe_spk_prot_feed_back_cfg(int src_port, int dst_port, this_afe.v4_ch_map_cfg.chan_info[index++] = 4; } this_afe.v4_ch_map_cfg.num_channels = index; + this_afe.num_spkrs = index / 2; pr_debug("%s no of channels: %d\n", __func__, index); this_afe.vi_tx_port = src_port; this_afe.vi_rx_port = dst_port; @@ -10609,6 +10679,8 @@ int __init afe_init(void) init_waitqueue_head(&this_afe.wait_wakeup); init_waitqueue_head(&this_afe.lpass_core_hw_wait); init_waitqueue_head(&this_afe.clk_wait); + for (i = 0; i < MAX_LSM_SESSIONS; i++) + this_afe.lsm_afe_ports[i] = 0xffff; ret = afe_init_cal_data(); if (ret) pr_err("%s: could not init cal data! %d\n", __func__, ret); @@ -10816,3 +10888,61 @@ done: return ret; } EXPORT_SYMBOL(afe_unvote_lpass_core_hw); + +/** + * afe_set_cps_config - + * to set cps speaker protection configuration + * + * @src_port: source port to send configuration to + * @cps_config: cps speaker protection v4 configuration + * @ch_mask: channel mask + * + */ +void afe_set_cps_config(int src_port, + struct afe_cps_hw_intf_cfg *cps_config, + u32 ch_mask) +{ + this_afe.cps_config = NULL; + this_afe.cps_ch_mask = 0; + + if (!cps_config) { + pr_err("%s: cps config is NULL\n", __func__); + return; + } + + if (q6audio_validate_port(src_port) < 0) { + pr_err("%s: Invalid src port 0x%x\n", __func__, src_port); + return; + } + + this_afe.cps_ch_mask = ch_mask; + this_afe.cps_config = cps_config; +} +EXPORT_SYMBOL(afe_set_cps_config); + +static bool q6afe_is_afe_lsm_port(int port_id) +{ + int i = 0; + + for (i = 0; i < MAX_LSM_SESSIONS; i++) { + if (port_id == this_afe.lsm_afe_ports[i]) + return true; + } + return false; +} + +/** + * afe_set_lsm_afe_port_id - + * Update LSM AFE port + * idx: LSM port index + * lsm_port: LSM port id +*/ +void afe_set_lsm_afe_port_id(int idx, int lsm_port) +{ + if (idx < 0 || idx >= MAX_LSM_SESSIONS) { + pr_err("%s: %d Invalid lsm port index\n", __func__, idx); + return; + } + this_afe.lsm_afe_ports[idx] = lsm_port; +} +EXPORT_SYMBOL(afe_set_lsm_afe_port_id); diff --git a/dsp/q6asm.c b/dsp/q6asm.c index 235cdbd4..2939599d 100644 --- a/dsp/q6asm.c +++ b/dsp/q6asm.c @@ -8486,6 +8486,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, if (mmap_region_cmd == NULL) { rc = -EINVAL; kfree(buffer_node); + buffer_node = NULL; return rc; } mmap_regions = (struct avs_cmd_shared_mem_map_regions *) @@ -8522,6 +8523,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, mmap_regions->hdr.opcode, rc); rc = -EINVAL; kfree(buffer_node); + buffer_node = NULL; goto fail_cmd; } @@ -8533,6 +8535,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, pr_err("%s: timeout. waited for memory_map\n", __func__); rc = -ETIMEDOUT; kfree(buffer_node); + buffer_node = NULL; goto fail_cmd; } if (atomic_read(&ac->mem_state) > 0) { @@ -8542,6 +8545,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, rc = adsp_err_get_lnx_err_code( atomic_read(&ac->mem_state)); kfree(buffer_node); + buffer_node = NULL; goto fail_cmd; } mutex_lock(&ac->cmd_lock); @@ -8561,6 +8565,7 @@ static int q6asm_memory_map_regions(struct audio_client *ac, int dir, rc = 0; fail_cmd: kfree(mmap_region_cmd); + mmap_region_cmd = NULL; return rc; } EXPORT_SYMBOL(q6asm_memory_map_regions); @@ -8656,6 +8661,7 @@ fail_cmd: if (buf_node->buf_phys_addr == buf_add) { list_del(&buf_node->list); kfree(buf_node); + buf_node = NULL; break; } } diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index cc57a253..857dad3f 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -2436,6 +2436,7 @@ int q6lsm_get_one_param(struct lsm_client *client, { struct param_hdr_v3 param_info; int rc = 0; + bool iid_supported = q6common_is_instance_id_supported(); memset(¶m_info, 0, sizeof(param_info)); @@ -2444,7 +2445,12 @@ int q6lsm_get_one_param(struct lsm_client *client, param_info.module_id = p_info->module_id; param_info.instance_id = p_info->instance_id; param_info.param_id = p_info->param_id; - param_info.param_size = p_info->param_size + sizeof(param_info); + + if (iid_supported) + param_info.param_size = p_info->param_size + sizeof(struct param_hdr_v3); + else + param_info.param_size = p_info->param_size + sizeof(struct param_hdr_v2); + rc = q6lsm_get_params(client, NULL, ¶m_info); if (rc) { pr_err("%s: LSM_GET_CUSTOM_PARAMS failed, rc %d\n", diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index eed5652f..dc51307a 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -10,6 +10,9 @@ #include <ipc/apr.h> #include <linux/msm_audio.h> +/* number of threshold levels in speaker protection module */ +#define MAX_CPS_LEVELS 3 + /* size of header needed for passing data out of band */ #define APR_CMD_OB_HDR_SZ 12 @@ -2364,6 +2367,28 @@ int16_t excursionf[AFE_SPKR_PROT_EXCURSIONF_LEN]; */ } __packed; +struct lpass_swr_spkr_dep_cfg_t { + uint32_t vbatt_pkd_reg_addr; + uint32_t temp_pkd_reg_addr; + uint32_t value_normal_thrsd[MAX_CPS_LEVELS]; + uint32_t value_low1_thrsd[MAX_CPS_LEVELS]; + uint32_t value_low2_thrsd[MAX_CPS_LEVELS]; +} __packed; + +struct lpass_swr_hw_reg_cfg_t { + uint32_t lpass_wr_cmd_reg_phy_addr; + uint32_t lpass_rd_cmd_reg_phy_addr; + uint32_t lpass_rd_fifo_reg_phy_addr; + uint32_t vbatt_lower1_threshold; + uint32_t vbatt_lower2_threshold; + uint32_t num_spkr; +} __packed; + +struct afe_cps_hw_intf_cfg { + uint32_t lpass_hw_intf_cfg_mode; + struct lpass_swr_hw_reg_cfg_t hw_reg_cfg; + struct lpass_swr_spkr_dep_cfg_t *spkr_dep_cfg; +} __packed; #define AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER 0x000100E0 @@ -10784,6 +10809,7 @@ struct cmd_set_topologies { #define AFE_PARAM_ID_FBSP_MODE_RX_CFG 0x0001021D #define AFE_PARAM_ID_FBSP_PTONE_RAMP_CFG 0x00010260 #define AFE_PARAM_ID_SP_RX_TMAX_XMAX_LOGGING 0x000102BC +#define AFE_PARAM_ID_CPS_LPASS_HW_INTF_CFG 0x000102EF struct asm_fbsp_mode_rx_cfg { uint32_t minor_version; diff --git a/include/dsp/audio_cal_utils.h b/include/dsp/audio_cal_utils.h index 06078150..99f619f2 100644 --- a/include/dsp/audio_cal_utils.h +++ b/include/dsp/audio_cal_utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2018, 2020, The Linux Foundation. All rights reserved. */ #ifndef _AUDIO_CAL_UTILS_H #define _AUDIO_CAL_UTILS_H @@ -95,4 +95,6 @@ int32_t cal_utils_get_cal_type_version(void *cal_type_data); void cal_utils_mark_cal_used(struct cal_block_data *cal_block); bool cal_utils_is_cal_stale(struct cal_block_data *cal_block); + +int cal_utils_init(void); #endif diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index 8b82069a..bd2cba69 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -432,6 +432,9 @@ int afe_pseudo_port_start_nowait(u16 port_id); int afe_pseudo_port_stop_nowait(u16 port_id); int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg); int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg); +void afe_set_cps_config(int src_port, + struct afe_cps_hw_intf_cfg *cps_config, + u32 ch_mask); int afe_set_lpass_clk_cfg(int index, struct afe_clk_set *cfg); int afe_set_digital_codec_core_clock(u16 port_id, struct afe_digital_clk_cfg *cfg); @@ -496,6 +499,7 @@ int afe_get_doa_tracking_mon(u16 port_id, int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift, uint32_t clk_reset); int afe_set_clk_id(u16 port_id, uint32_t clk_id); +void afe_set_lsm_afe_port_id(int idx, int lsm_port); enum { AFE_LPASS_CORE_HW_BLOCK_ID_NONE, diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 7bf2f9a6..385e59fa 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #include <linux/irq.h> @@ -104,6 +104,7 @@ 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 int swrm_runtime_resume(struct device *dev); +static void swrm_wait_for_fifo_avail(struct swr_mstr_ctrl *swrm, int swrm_rd_wr); static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq) { @@ -627,6 +628,9 @@ static int swr_master_bulk_write(struct swr_mstr_ctrl *swrm, u32 *reg_addr, * This still meets the hardware spec */ usleep_range(50, 55); + if (reg_addr[i] == SWRM_CMD_FIFO_WR_CMD) + swrm_wait_for_fifo_avail(swrm, + SWRM_WR_CHECK_AVAIL); swr_master_write(swrm, reg_addr[i], val[i]); } usleep_range(100, 110); @@ -1755,10 +1759,12 @@ static void swrm_enable_slave_irq(struct swr_mstr_ctrl *swrm) dev_dbg(swrm->dev, "%s: slave status: 0x%x\n", __func__, status); for (i = 0; i < (swrm->master.num_dev + 1); i++) { if (status & SWRM_MCP_SLV_STATUS_MASK) { - swrm_cmd_fifo_rd_cmd(swrm, &temp, i, 0x0, + if (!swrm->clk_stop_wakeup) { + swrm_cmd_fifo_rd_cmd(swrm, &temp, i, 0x0, SWRS_SCP_INT_STATUS_CLEAR_1, 1); - swrm_cmd_fifo_wr_cmd(swrm, 0xFF, i, 0x0, + swrm_cmd_fifo_wr_cmd(swrm, 0xFF, i, 0x0, SWRS_SCP_INT_STATUS_CLEAR_1); + } swrm_cmd_fifo_wr_cmd(swrm, 0x4, i, 0x0, SWRS_SCP_INT_STATUS_MASK_1); } @@ -2170,7 +2176,9 @@ handle_irq: * re-enable Host IRQ and process slave pending * interrupts, if any. */ + swrm->clk_stop_wakeup = true; swrm_enable_slave_irq(swrm); + swrm->clk_stop_wakeup = false; } break; default: @@ -2741,6 +2749,8 @@ static int swrm_probe(struct platform_device *pdev) swrm->dev_up = true; swrm->state = SWR_MSTR_UP; swrm->ipc_wakeup = false; + swrm->enable_slave_irq = false; + swrm->clk_stop_wakeup = false; swrm->ipc_wakeup_triggered = false; swrm->disable_div2_clk_switch = FALSE; init_completion(&swrm->reset); @@ -3093,7 +3103,7 @@ exit: swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false); if (!hw_core_err) swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); - if (swrm_clk_req_err) + if (swrm_clk_req_err || aud_core_err || hw_core_err) pm_runtime_set_autosuspend_delay(&pdev->dev, ERR_AUTO_SUSPEND_TIMER_VAL); else @@ -3123,6 +3133,10 @@ static int swrm_runtime_suspend(struct device *dev) __func__, swrm->state); dev_dbg(dev, "%s: pm_runtime: suspend state: %d\n", __func__, swrm->state); + if (swrm->state == SWR_MSTR_SSR_RESET) { + swrm->state = SWR_MSTR_SSR; + return 0; + } mutex_lock(&swrm->reslock); mutex_lock(&swrm->force_down_lock); current_state = swrm->state; @@ -3477,6 +3491,18 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) dev_err(swrm->dev, "%s: clock voting not zero\n", __func__); + if (swrm->state == SWR_MSTR_UP || + pm_runtime_autosuspend_expiration(swrm->dev)) { + swrm->state = SWR_MSTR_SSR_RESET; + dev_dbg(swrm->dev, + "%s:suspend swr if active at SSR up\n", + __func__); + pm_runtime_set_autosuspend_delay(swrm->dev, + ERR_AUTO_SUSPEND_TIMER_VAL); + usleep_range(50000, 50100); + swrm->state = SWR_MSTR_SSR; + } + mutex_lock(&swrm->devlock); swrm->dev_up = true; mutex_unlock(&swrm->devlock); diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index f5365923..1b707166 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _SWR_WCD_CTRL_H @@ -51,6 +51,7 @@ enum { SWR_MSTR_UP, SWR_MSTR_DOWN, SWR_MSTR_SSR, + SWR_MSTR_SSR_RESET, }; enum swrm_pm_state { @@ -185,6 +186,7 @@ struct swr_mstr_ctrl { u32 rd_fifo_depth; u32 wr_fifo_depth; bool enable_slave_irq; + bool clk_stop_wakeup; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_swrm_dent; struct dentry *debugfs_peek; |