From 2d15d974618db4ed3adafe9b9fe092db0f5076a0 Mon Sep 17 00:00:00 2001
From: Bard Liao <bardliao@realtek.com>
Date: Wed, 27 Aug 2014 19:50:34 +0800
Subject: [PATCH] ASoC: rt5677: Add DMIC2 clock selection

There are two pins can be used for rt5677's DMIC2 clock. This patch
add the select options for it.

Signed-off-by: Bard Liao <bardliao@realtek.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 include/sound/rt5677.h    |  8 ++++++
 sound/soc/codecs/rt5677.c | 57 +++++++++++++++++++++++++++++++++------
 sound/soc/codecs/rt5677.h | 10 +++++++
 3 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h
index 3da14313bcfc..a676717f74f4 100644
--- a/include/sound/rt5677.h
+++ b/include/sound/rt5677.h
@@ -12,10 +12,18 @@
 #ifndef __LINUX_SND_RT5677_H
 #define __LINUX_SND_RT5677_H
 
+enum rt5677_dmic2_clk {
+	RT5677_DMIC_CLK1 = 0,
+	RT5677_DMIC_CLK2 = 1,
+};
+
+
 struct rt5677_platform_data {
 	/* IN1 IN2 can optionally be differential */
 	bool in1_diff;
 	bool in2_diff;
+	/* DMIC2 clock source selection */
+	enum rt5677_dmic2_clk dmic2_clk_pin;
 };
 
 #endif
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 67f14556462f..f0b751bf1d6c 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -1700,14 +1700,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 
 	SND_SOC_DAPM_INPUT("Haptic Generator"),
 
-	SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0,
-		NULL, 0),
-	SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0,
-		NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_1_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_2_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1,
+		RT5677_DMIC_3_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2,
+		RT5677_DMIC_4_EN_SFT, 0, NULL, 0),
 
 	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
 		set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
@@ -2130,6 +2135,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "DMIC L4", NULL, "DMIC CLK" },
 	{ "DMIC R4", NULL, "DMIC CLK" },
 
+	{ "DMIC L1", NULL, "DMIC1 power" },
+	{ "DMIC R1", NULL, "DMIC1 power" },
+	{ "DMIC L3", NULL, "DMIC3 power" },
+	{ "DMIC R3", NULL, "DMIC3 power" },
+	{ "DMIC L4", NULL, "DMIC4 power" },
+	{ "DMIC R4", NULL, "DMIC4 power" },
+
 	{ "BST1", NULL, "IN1P" },
 	{ "BST1", NULL, "IN1N" },
 	{ "BST2", NULL, "IN2P" },
@@ -2793,6 +2805,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 	{ "PDM2R", NULL, "PDM2 R Mux" },
 };
 
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = {
+	{ "DMIC L2", NULL, "DMIC1 power" },
+	{ "DMIC R2", NULL, "DMIC1 power" },
+};
+
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = {
+	{ "DMIC L2", NULL, "DMIC2 power" },
+	{ "DMIC R2", NULL, "DMIC2 power" },
+};
+
 static int rt5677_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -3144,6 +3166,16 @@ static int rt5677_probe(struct snd_soc_codec *codec)
 
 	rt5677->codec = codec;
 
+	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5677_dmic2_clk_2,
+			ARRAY_SIZE(rt5677_dmic2_clk_2));
+	} else { /*use dmic1 clock by default*/
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5677_dmic2_clk_1,
+			ARRAY_SIZE(rt5677_dmic2_clk_1));
+	}
+
 	rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
@@ -3381,6 +3413,15 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 		regmap_update_bits(rt5677->regmap, RT5677_IN1,
 					RT5677_IN_DF2, RT5677_IN_DF2);
 
+	if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+		regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
+					RT5677_GPIO5_FUNC_MASK,
+					RT5677_GPIO5_FUNC_DMIC);
+		regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+					RT5677_GPIO5_DIR_MASK,
+					RT5677_GPIO5_DIR_OUT);
+	}
+
 	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
 				      rt5677_dai, ARRAY_SIZE(rt5677_dai));
 }
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 863393e62096..8791ab9637f3 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -1363,6 +1363,11 @@
 #define RT5677_SEL_SRC_IB01			(0x1 << 0)
 #define RT5677_SEL_SRC_IB01_SFT			0
 
+/* GPIO Control 2 (0xc1) */
+#define RT5677_GPIO5_DIR_MASK			(0x1 << 14)
+#define RT5677_GPIO5_DIR_IN			(0x0 << 14)
+#define RT5677_GPIO5_DIR_OUT			(0x1 << 14)
+
 /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */
 #define RT5677_DSP_IB_01_H			(0x1 << 15)
 #define RT5677_DSP_IB_01_H_SFT			15
@@ -1393,6 +1398,11 @@
 #define RT5677_DSP_IB_9_L			(0x1 << 1)
 #define RT5677_DSP_IB_9_L_SFT			1
 
+/* General Control2 (0xfc)*/
+#define RT5677_GPIO5_FUNC_MASK			(0x1 << 9)
+#define RT5677_GPIO5_FUNC_GPIO			(0x0 << 9)
+#define RT5677_GPIO5_FUNC_DMIC			(0x1 << 9)
+
 /* System Clock Source */
 enum {
 	RT5677_SCLK_S_MCLK,
-- 
2.34.1