Browse Source

asoc: bolero: Update dmic sample rate config for VA macro

Add support for DMICs of different sampling rates
with respective clk_div config update in VA macro
register.

Change-Id: I8faa46774cf1fe561af3bd7a284bc7d37f85cb9d
Signed-off-by: Laxminath Kasam <[email protected]>
Laxminath Kasam 6 years ago
parent
commit
135d405d2e
1 changed files with 86 additions and 5 deletions
  1. 86 5
      asoc/codecs/bolero/va-macro.c

+ 86 - 5
asoc/codecs/bolero/va-macro.c

@@ -39,7 +39,11 @@
 #define  CF_MIN_3DB_75HZ		0x1
 #define  CF_MIN_3DB_150HZ		0x2
 
+#define VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED 0
+#define VA_MACRO_MCLK_FREQ 9600000
 #define VA_MACRO_TX_PATH_OFFSET 0x80
+#define VA_MACRO_TX_DMIC_CLK_DIV_MASK 0x0E
+#define VA_MACRO_TX_DMIC_CLK_DIV_SHFT 0x01
 
 #define BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS	40
 
@@ -66,6 +70,15 @@ enum {
 	VA_MACRO_DEC_MAX,
 };
 
+enum {
+	VA_MACRO_CLK_DIV_2,
+	VA_MACRO_CLK_DIV_3,
+	VA_MACRO_CLK_DIV_4,
+	VA_MACRO_CLK_DIV_6,
+	VA_MACRO_CLK_DIV_8,
+	VA_MACRO_CLK_DIV_16,
+};
+
 struct va_mute_work {
 	struct va_macro_priv *va_priv;
 	u32 decimator;
@@ -94,6 +107,7 @@ struct va_macro_priv {
 	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;
 	char __iomem *va_io_base;
 	struct regulator *micb_supply;
@@ -415,22 +429,22 @@ static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w,
 	case 0:
 	case 1:
 		dmic_clk_cnt = &(va_priv->dmic_0_1_clk_cnt);
-		dmic_clk_reg = BOLERO_CDC_VA_TX0_TX_PATH_CTL;
+		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_TX1_TX_PATH_CTL;
+		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_TX2_TX_PATH_CTL;
+		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_TX3_TX_PATH_CTL;
+		dmic_clk_reg = BOLERO_CDC_VA_TOP_CSR_DMIC3_CTL;
 		break;
 	default:
 		dev_err(va_dev, "%s: Invalid DMIC Selection\n",
@@ -446,6 +460,10 @@ static int va_macro_enable_dmic(struct snd_soc_dapm_widget *w,
 		if (*dmic_clk_cnt == 1) {
 			snd_soc_update_bits(codec, dmic_clk_reg,
 					dmic_clk_en, dmic_clk_en);
+			snd_soc_update_bits(codec, dmic_clk_reg,
+					VA_MACRO_TX_DMIC_CLK_DIV_MASK,
+					va_priv->dmic_clk_div <<
+					VA_MACRO_TX_DMIC_CLK_DIV_SHFT);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -1255,6 +1273,56 @@ static const struct snd_kcontrol_new va_macro_snd_controls[] = {
 			  0, -84, 40, digital_gain),
 };
 
+static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate,
+				      struct va_macro_priv *va_priv)
+{
+	u32 div_factor;
+	u32 mclk_rate = VA_MACRO_MCLK_FREQ;
+
+	if (dmic_sample_rate == VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED ||
+	    mclk_rate % dmic_sample_rate != 0)
+		goto undefined_rate;
+
+	div_factor = mclk_rate / dmic_sample_rate;
+
+	switch (div_factor) {
+	case 2:
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_2;
+		break;
+	case 3:
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_3;
+		break;
+	case 4:
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_4;
+		break;
+	case 6:
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_6;
+		break;
+	case 8:
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_8;
+		break;
+	case 16:
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_16;
+		break;
+	default:
+		/* Any other DIV factor is invalid */
+		goto undefined_rate;
+	}
+
+	/* Valid dmic DIV factors */
+	dev_dbg(va_priv->dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n",
+		__func__, div_factor, mclk_rate);
+
+	return dmic_sample_rate;
+
+undefined_rate:
+	dev_dbg(va_priv->dev, "%s: Invalid rate %d, for mclk %d\n",
+		 __func__, dmic_sample_rate, mclk_rate);
+	dmic_sample_rate = VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED;
+
+	return dmic_sample_rate;
+}
+
 static int va_macro_init(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -1355,7 +1423,7 @@ static int va_macro_probe(struct platform_device *pdev)
 {
 	struct macro_ops ops;
 	struct va_macro_priv *va_priv;
-	u32 va_base_addr;
+	u32 va_base_addr, sample_rate = 0;
 	char __iomem *va_io_base;
 	struct clk *va_core_clk;
 	bool va_without_decimation = false;
@@ -1363,6 +1431,7 @@ static int va_macro_probe(struct platform_device *pdev)
 	const char *micb_voltage_str = "qcom,va-vdd-micb-voltage";
 	const char *micb_current_str = "qcom,va-vdd-micb-current";
 	int ret = 0;
+	const char *dmic_sample_rate = "qcom,va-dmic-sample-rate";
 
 	va_priv = devm_kzalloc(&pdev->dev, sizeof(struct va_macro_priv),
 			    GFP_KERNEL);
@@ -1381,6 +1450,18 @@ static int va_macro_probe(struct platform_device *pdev)
 					"qcom,va-without-decimation");
 
 	va_priv->va_without_decimation = va_without_decimation;
+	ret = of_property_read_u32(pdev->dev.of_node, dmic_sample_rate,
+				   &sample_rate);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: could not find %s entry in dt\n",
+			__func__, sample_rate);
+		va_priv->dmic_clk_div = VA_MACRO_CLK_DIV_2;
+	} else {
+		if (va_macro_validate_dmic_sample_rate(
+		sample_rate, va_priv) == VA_MACRO_DMIC_SAMPLE_RATE_UNDEFINED)
+			return -EINVAL;
+	}
+
 	va_io_base = devm_ioremap(&pdev->dev, va_base_addr,
 				  VA_MAX_OFFSET);
 	if (!va_io_base) {