Merge 346468d572df78d56fa0c37da11882bb39c713c3 on remote branch
Change-Id: Iaedf2dbfd70ab13f3c86c946438e39719efd0790
diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c
index 158f350..de04e1e 100644
--- a/asoc/codecs/bolero/tx-macro.c
+++ b/asoc/codecs/bolero/tx-macro.c
@@ -234,11 +234,11 @@
}
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 @@
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 @@
__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_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 cbb77ee..2e36995 100644
--- a/asoc/codecs/bolero/va-macro.c
+++ b/asoc/codecs/bolero/va-macro.c
@@ -399,12 +399,8 @@
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(
@@ -557,9 +553,12 @@
(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,
@@ -652,9 +651,12 @@
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/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c
index 8a5e99e..f2f16da 100644
--- a/asoc/codecs/wsa883x/wsa883x.c
+++ b/asoc/codecs/wsa883x/wsa883x.c
@@ -770,6 +770,30 @@
}
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)
{
@@ -996,6 +1020,12 @@
/* 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,6 +1034,12 @@
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(wsa883x->component,
diff --git a/asoc/codecs/wsa883x/wsa883x.h b/asoc/codecs/wsa883x/wsa883x.h
index e080134..bb71983 100644
--- a/asoc/codecs/wsa883x/wsa883x.h
+++ b/asoc/codecs/wsa883x/wsa883x.h
@@ -21,6 +21,7 @@
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 @@
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 23f5f42..f5d0ea8 100644
--- a/asoc/kona.c
+++ b/asoc/kona.c
@@ -88,6 +88,8 @@
#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,
@@ -195,7 +197,10 @@
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 {
@@ -2691,6 +2696,12 @@
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;
@@ -4902,6 +4913,121 @@
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)
{
@@ -4949,6 +5075,11 @@
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;
}
@@ -8236,6 +8367,115 @@
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;
@@ -8307,6 +8547,15 @@
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) {
@@ -8419,6 +8668,10 @@
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/dsp/q6afe.c b/dsp/q6afe.c
index 283d425..bfcbfce 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -246,6 +246,9 @@
/* 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;
};
struct afe_clkinfo_per_port {
@@ -2172,6 +2175,70 @@
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 +2379,7 @@
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 +2440,7 @@
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 +2449,7 @@
__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 +2463,13 @@
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 +2484,7 @@
(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 +2497,13 @@
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 +2515,8 @@
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 +2530,13 @@
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 +2552,7 @@
(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 +2574,14 @@
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;
+ ex_vi_ftm_cfg->num_ch = this_afe.num_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];
-
+ 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))
@@ -5277,6 +5334,11 @@
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 +8494,11 @@
* 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 +9639,7 @@
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;
@@ -10816,3 +10882,34 @@
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);
diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h
index eed5652..dc51307 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 @@
*/
} __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 @@
#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/q6afe-v2.h b/include/dsp/q6afe-v2.h
index 8b82069..310de65 100644
--- a/include/dsp/q6afe-v2.h
+++ b/include/dsp/q6afe-v2.h
@@ -432,6 +432,9 @@
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);