Kaynağa Gözat

ASoC: bolero: Add concurrency support on audio capture path

During voice activation and audio capture concurrency usecase,
there is no common reference count for DMIC clock enablement,
results into mute when one usecase tears down. Change enables
a common reference count in bolero codec driver between voice
activation usecase and audio capture usecase to avoid mute
during VA and audio capture concurrency.

Change-Id: I424c941178d7e9ff91288a50ba27605b2b9d3abe
Signed-off-by: Sudheer Papothi <[email protected]>
Signed-off-by: Akhil Karuturi <[email protected]>
Sudheer Papothi 5 yıl önce
ebeveyn
işleme
0e19126c1f

+ 129 - 1
asoc/codecs/bolero/bolero-cdc.c

@@ -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.
  */
 
 #include <linux/of_platform.h>
@@ -470,6 +470,129 @@ void bolero_unregister_res_clk(struct device *dev)
 }
 EXPORT_SYMBOL(bolero_unregister_res_clk);
 
+static u8 bolero_dmic_clk_div_get(struct snd_soc_component *component,
+				   int mode)
+{
+	struct bolero_priv* priv = snd_soc_component_get_drvdata(component);
+	int macro = (mode ? VA_MACRO : TX_MACRO);
+	int ret = 0;
+
+	if (priv->macro_params[macro].clk_div_get) {
+		ret = priv->macro_params[macro].clk_div_get(component);
+		if (ret > 0)
+			return ret;
+	}
+
+	return 1;
+}
+
+int bolero_dmic_clk_enable(struct snd_soc_component *component,
+			   u32 dmic, u32 tx_mode, bool enable)
+{
+	struct bolero_priv* priv = snd_soc_component_get_drvdata(component);
+	u8  dmic_clk_en = 0x01;
+	u16 dmic_clk_reg = 0;
+	s32 *dmic_clk_cnt = NULL;
+	u8 *dmic_clk_div = NULL;
+	u8 freq_change_mask = 0;
+	u8 clk_div = 0;
+
+	dev_dbg(component->dev, "%s: enable: %d, tx_mode:%d, dmic: %d\n",
+		__func__, enable, tx_mode, dmic);
+
+	switch (dmic) {
+	case 0:
+	case 1:
+		dmic_clk_cnt = &(priv->dmic_0_1_clk_cnt);
+		dmic_clk_div = &(priv->dmic_0_1_clk_div);
+		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL;
+		freq_change_mask = 0x01;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_cnt = &(priv->dmic_2_3_clk_cnt);
+		dmic_clk_div = &(priv->dmic_2_3_clk_div);
+		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL;
+		freq_change_mask = 0x02;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_cnt = &(priv->dmic_4_5_clk_cnt);
+		dmic_clk_div = &(priv->dmic_4_5_clk_div);
+		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL;
+		freq_change_mask = 0x04;
+		break;
+	case 6:
+	case 7:
+		dmic_clk_cnt = &(priv->dmic_6_7_clk_cnt);
+		dmic_clk_div = &(priv->dmic_6_7_clk_div);
+		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
+		freq_change_mask = 0x08;
+		break;
+	default:
+		dev_err(component->dev, "%s: Invalid DMIC Selection\n",
+			__func__);
+		return -EINVAL;
+	}
+	dev_dbg(component->dev, "%s: DMIC%d dmic_clk_cnt %d\n",
+			__func__, dmic, *dmic_clk_cnt);
+	if (enable) {
+		clk_div = bolero_dmic_clk_div_get(component, tx_mode);
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_component_update_bits(component,
+					BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+					0x80, 0x00);
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+						0x0E, clk_div << 0x1);
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+					dmic_clk_en, dmic_clk_en);
+		} else {
+			if (*dmic_clk_div > clk_div) {
+				snd_soc_component_update_bits(component,
+						BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+						freq_change_mask, freq_change_mask);
+				snd_soc_component_update_bits(component, dmic_clk_reg,
+						0x0E, clk_div << 0x1);
+				snd_soc_component_update_bits(component,
+						BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+						freq_change_mask, 0x00);
+			} else {
+				clk_div = *dmic_clk_div;
+			}
+		}
+		*dmic_clk_div = clk_div;
+	} else {
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0) {
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+					dmic_clk_en, 0);
+			clk_div = 0;
+			snd_soc_component_update_bits(component, dmic_clk_reg,
+							0x0E, clk_div << 0x1);
+		} else {
+			clk_div = bolero_dmic_clk_div_get(component, tx_mode);
+			if (*dmic_clk_div > clk_div) {
+				clk_div = bolero_dmic_clk_div_get(component, !tx_mode);
+				snd_soc_component_update_bits(component,
+							BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+							freq_change_mask, freq_change_mask);
+				snd_soc_component_update_bits(component, dmic_clk_reg,
+								0x0E, clk_div << 0x1);
+				snd_soc_component_update_bits(component,
+							BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
+							freq_change_mask, 0x00);
+			} else {
+				clk_div = *dmic_clk_div;
+			}
+		}
+		*dmic_clk_div = clk_div;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(bolero_dmic_clk_enable);
+
 /**
  * bolero_register_macro - Registers macro to bolero
  *
@@ -518,6 +641,9 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
 		priv->macro_params[macro_id].reg_evt_listener =
 							ops->reg_evt_listener;
 	}
+	if (macro_id == TX_MACRO || macro_id == VA_MACRO)
+		priv->macro_params[macro_id].clk_div_get = ops->clk_div_get;
+
 	if (priv->version == BOLERO_VERSION_2_1) {
 		if (macro_id == VA_MACRO)
 			priv->macro_params[macro_id].reg_wake_irq =
@@ -588,6 +714,8 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id)
 		priv->macro_params[macro_id].clk_switch = NULL;
 		priv->macro_params[macro_id].reg_evt_listener = NULL;
 	}
+	if (macro_id == TX_MACRO || macro_id == VA_MACRO)
+		priv->macro_params[macro_id].clk_div_get = NULL;
 
 	priv->num_dais -= priv->macro_params[macro_id].num_dais;
 	priv->num_macros_registered--;

+ 16 - 1
asoc/codecs/bolero/bolero-cdc.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 BOLERO_CDC_H
@@ -50,6 +50,12 @@ enum {
 	BOLERO_MACRO_EVT_BCS_CLK_OFF
 };
 
+enum {
+	DMIC_TX = 0,
+	DMIC_VA = 1,
+
+};
+
 struct macro_ops {
 	int (*init)(struct snd_soc_component *component);
 	int (*exit)(struct snd_soc_component *component);
@@ -63,6 +69,7 @@ struct macro_ops {
 	int (*set_port_map)(struct snd_soc_component *component, u32 uc,
 			    u32 size, void *data);
 	int (*clk_switch)(struct snd_soc_component *component);
+	int (*clk_div_get)(struct snd_soc_component *component);
 	int (*reg_evt_listener)(struct snd_soc_component *component, bool en);
 	char __iomem *io_base;
 	u16 clk_id_req;
@@ -93,6 +100,8 @@ int bolero_register_event_listener(struct snd_soc_component *component,
 void bolero_wsa_pa_on(struct device *dev);
 bool bolero_check_core_votes(struct device *dev);
 int bolero_get_version(struct device *dev);
+int bolero_dmic_clk_enable(struct snd_soc_component *component,
+			   u32 dmic, u32 tx_mode, bool enable);
 #else
 static inline int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb)
 {
@@ -177,5 +186,11 @@ static int bolero_get_version(struct device *dev)
 {
 	return 0;
 }
+
+static int bolero_dmic_clk_enable(struct snd_soc_component *component,
+			   u32 dmic, u32 tx_mode, bool enable)
+{
+	return 0;
+}
 #endif /* CONFIG_SND_SOC_BOLERO */
 #endif /* BOLERO_CDC_H */

+ 9 - 1
asoc/codecs/bolero/internal.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 _BOLERO_INTERNAL_H
@@ -82,6 +82,14 @@ struct bolero_priv {
 	struct blocking_notifier_head notifier;
 	struct device *clk_dev;
 	rsc_clk_cb_t rsc_clk_cb;
+	s32 dmic_0_1_clk_cnt;
+	s32 dmic_2_3_clk_cnt;
+	s32 dmic_4_5_clk_cnt;
+	s32 dmic_6_7_clk_cnt;
+	u8 dmic_0_1_clk_div;
+	u8 dmic_2_3_clk_div;
+	u8 dmic_4_5_clk_div;
+	u8 dmic_6_7_clk_div;
 };
 
 struct regmap *bolero_regmap_init(struct device *dev,

+ 16 - 55
asoc/codecs/bolero/tx-macro.c

@@ -158,10 +158,6 @@ struct tx_macro_priv {
 	struct work_struct tx_macro_add_child_devices_work;
 	struct hpf_work tx_hpf_work[NUM_DECIMATORS];
 	struct tx_mute_work tx_mute_dwork[NUM_DECIMATORS];
-	s32 dmic_0_1_clk_cnt;
-	s32 dmic_2_3_clk_cnt;
-	s32 dmic_4_5_clk_cnt;
-	s32 dmic_6_7_clk_cnt;
 	u16 dmic_clk_div;
 	u32 version;
 	u32 is_used_tx_swr_gpio;
@@ -814,17 +810,9 @@ static int tx_macro_enable_dmic(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_component *component =
 				snd_soc_dapm_to_component(w->dapm);
-	u8  dmic_clk_en = 0x01;
-	u16 dmic_clk_reg = 0;
-	s32 *dmic_clk_cnt = NULL;
 	unsigned int dmic = 0;
 	int ret = 0;
 	char *wname = NULL;
-	struct device *tx_dev = NULL;
-	struct tx_macro_priv *tx_priv = NULL;
-
-	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
-		return -EINVAL;
 
 	wname = strpbrk(w->name, "01234567");
 	if (!wname) {
@@ -839,54 +827,15 @@ static int tx_macro_enable_dmic(struct snd_soc_dapm_widget *w,
 		return -EINVAL;
 	}
 
-	switch (dmic) {
-	case 0:
-	case 1:
-		dmic_clk_cnt = &(tx_priv->dmic_0_1_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL;
-		break;
-	case 2:
-	case 3:
-		dmic_clk_cnt = &(tx_priv->dmic_2_3_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL;
-		break;
-	case 4:
-	case 5:
-		dmic_clk_cnt = &(tx_priv->dmic_4_5_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL;
-		break;
-	case 6:
-	case 7:
-		dmic_clk_cnt = &(tx_priv->dmic_6_7_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
-		break;
-	default:
-		dev_err(component->dev, "%s: Invalid DMIC Selection\n",
-			__func__);
-		return -EINVAL;
-	}
-	dev_dbg(component->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
-			__func__, event,  dmic, *dmic_clk_cnt);
+	dev_dbg(component->dev, "%s: event %d DMIC%d\n",
+			__func__, event,  dmic);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		(*dmic_clk_cnt)++;
-		if (*dmic_clk_cnt == 1) {
-			snd_soc_component_update_bits(component,
-					BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
-					0x80, 0x00);
-
-			snd_soc_component_update_bits(component, dmic_clk_reg,
-					0x0E, tx_priv->dmic_clk_div << 0x1);
-			snd_soc_component_update_bits(component, dmic_clk_reg,
-					dmic_clk_en, dmic_clk_en);
-		}
+		bolero_dmic_clk_enable(component, dmic, DMIC_TX, true);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		(*dmic_clk_cnt)--;
-		if (*dmic_clk_cnt  == 0)
-			snd_soc_component_update_bits(component, dmic_clk_reg,
-					dmic_clk_en, 0);
+		bolero_dmic_clk_enable(component, dmic, DMIC_TX, false);
 		break;
 	}
 
@@ -2590,6 +2539,17 @@ exit:
 	return ret;
 }
 
+static int tx_macro_clk_div_get(struct snd_soc_component *component)
+{
+	struct device *tx_dev = NULL;
+	struct tx_macro_priv *tx_priv = NULL;
+
+	if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
+		return -EINVAL;
+
+	return tx_priv->dmic_clk_div;
+}
+
 static int tx_macro_clk_switch(struct snd_soc_component *component)
 {
 	struct device *tx_dev = NULL;
@@ -3093,6 +3053,7 @@ static void tx_macro_init_ops(struct macro_ops *ops,
 	ops->event_handler = tx_macro_event_handler;
 	ops->reg_wake_irq = tx_macro_reg_wake_irq;
 	ops->set_port_map = tx_macro_set_port_map;
+	ops->clk_div_get = tx_macro_clk_div_get;
 	ops->clk_switch = tx_macro_clk_switch;
 	ops->reg_evt_listener = tx_macro_register_event_listener;
 }

+ 20 - 61
asoc/codecs/bolero/va-macro.c

@@ -142,10 +142,6 @@ struct va_macro_priv {
 	struct va_mute_work va_mute_dwork[VA_MACRO_NUM_DECIMATORS];
 	unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
 	unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
-	s32 dmic_0_1_clk_cnt;
-	s32 dmic_2_3_clk_cnt;
-	s32 dmic_4_5_clk_cnt;
-	s32 dmic_6_7_clk_cnt;
 	u16 dmic_clk_div;
 	u16 va_mclk_users;
 	int swr_clk_users;
@@ -196,6 +192,17 @@ static bool va_macro_get_data(struct snd_soc_component *component,
 	return true;
 }
 
+static int va_macro_clk_div_get(struct snd_soc_component *component)
+{
+	struct device *va_dev = NULL;
+	struct va_macro_priv *va_priv = NULL;
+
+	if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
+		return -EINVAL;
+
+	return va_priv->dmic_clk_div;
+}
+
 static int va_macro_mclk_enable(struct va_macro_priv *va_priv,
 				 bool mclk_enable, bool dapm)
 {
@@ -978,81 +985,32 @@ static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_component *component =
 				snd_soc_dapm_to_component(w->dapm);
-	u8  dmic_clk_en = 0x01;
-	u16 dmic_clk_reg;
-	s32 *dmic_clk_cnt;
-	unsigned int dmic;
-	int ret;
+	unsigned int dmic = 0;
+	int ret = 0;
 	char *wname;
-	struct device *va_dev = NULL;
-	struct va_macro_priv *va_priv = NULL;
-
-	if (!va_macro_get_data(component, &va_dev, &va_priv, __func__))
-		return -EINVAL;
 
 	wname = strpbrk(w->name, "01234567");
 	if (!wname) {
-		dev_err(va_dev, "%s: widget not found\n", __func__);
+		dev_err(component->dev, "%s: widget not found\n", __func__);
 		return -EINVAL;
 	}
 
 	ret = kstrtouint(wname, 10, &dmic);
 	if (ret < 0) {
-		dev_err(va_dev, "%s: Invalid DMIC line on the codec\n",
+		dev_err(component->dev, "%s: Invalid DMIC line on the codec\n",
 			__func__);
 		return -EINVAL;
 	}
 
-	switch (dmic) {
-	case 0:
-	case 1:
-		dmic_clk_cnt = &(va_priv->dmic_0_1_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC0_CTL;
-		break;
-	case 2:
-	case 3:
-		dmic_clk_cnt = &(va_priv->dmic_2_3_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC1_CTL;
-		break;
-	case 4:
-	case 5:
-		dmic_clk_cnt = &(va_priv->dmic_4_5_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC2_CTL;
-		break;
-	case 6:
-	case 7:
-		dmic_clk_cnt = &(va_priv->dmic_6_7_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
-		break;
-	default:
-		dev_err(va_dev, "%s: Invalid DMIC Selection\n",
-			__func__);
-		return -EINVAL;
-	}
-	dev_dbg(va_dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n",
-		__func__, event,  dmic, *dmic_clk_cnt);
+	dev_dbg(component->dev, "%s: event %d DMIC%d\n",
+		__func__, event,  dmic);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		(*dmic_clk_cnt)++;
-		if (*dmic_clk_cnt == 1) {
-			snd_soc_component_update_bits(component,
-					BOLERO_CDC_VA_TOP_CSR_DMIC_CFG,
-					0x80, 0x00);
-			snd_soc_component_update_bits(component, dmic_clk_reg,
-					VA_MACRO_TX_DMIC_CLK_DIV_MASK,
-					va_priv->dmic_clk_div <<
-					VA_MACRO_TX_DMIC_CLK_DIV_SHFT);
-			snd_soc_component_update_bits(component, dmic_clk_reg,
-					dmic_clk_en, dmic_clk_en);
-		}
+		bolero_dmic_clk_enable(component, dmic, DMIC_VA, true);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		(*dmic_clk_cnt)--;
-		if (*dmic_clk_cnt  == 0) {
-			snd_soc_component_update_bits(component, dmic_clk_reg,
-					dmic_clk_en, 0);
-		}
+		bolero_dmic_clk_enable(component, dmic, DMIC_VA, false);
 		break;
 	}
 
@@ -2795,6 +2753,7 @@ static void va_macro_init_ops(struct macro_ops *ops,
 	ops->event_handler = va_macro_event_handler;
 	ops->set_port_map = va_macro_set_port_map;
 	ops->reg_wake_irq = va_macro_reg_wake_irq;
+	ops->clk_div_get = va_macro_clk_div_get;
 }
 
 static int va_macro_probe(struct platform_device *pdev)