aboutsummaryrefslogtreecommitdiffstats
path: root/bsp/pandaboard/ASoC-twl6040-Remove-pll-and-headset-mode-dependency.patch
blob: 630640b0e76c015bc42822bc75dd2ad4a724f9d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
From 029aea5a1a4c422edc768bde52509b718ed42d3b Mon Sep 17 00:00:00 2001
From: Misael Lopez Cruz <misael.lopez@ti.com>
Date: Fri, 11 Feb 2011 17:51:05 -0600
Subject: [PATCH 19/60] ASoC: twl6040: Remove pll and headset mode dependency

commit 7ff3aff0cc6da687bf1058afb4ab2f98753008f6 upstream

Remove dependency between pll (hppll, lppll) and headset power
mode (low-power, high-performance), as headset power mode can
be used with any pll.

A new control is created to allow headset power mode configuration
from userspace. Changing headset power mode during earpiece related
usecases is not allowed as earpiece requires HS DAC in HP mode.

Change-Id: Icb313f8fa7e17bdf52a618cd5c829d976e8cc580
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Integrated-by: Jingdong Lu <jingdong.lu@windriver.com>
---
 sound/soc/codecs/twl6040.c |   69 ++++++++++++++++++++++++++++++++++++++------
 1 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 4c33663..6547646 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -82,6 +82,8 @@ struct twl6040_data {
 	int codec_powered;
 	int pll;
 	int non_lp;
+	int power_mode_forced;
+	int headset_mode;
 	unsigned int sysclk;
 	struct snd_pcm_hw_constraint_list *sysclk_constraints;
 	struct completion ready;
@@ -713,15 +715,26 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
 {
 	struct snd_soc_codec *codec = w->codec;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
 
-	if (SND_SOC_DAPM_EVENT_ON(event))
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
 		priv->non_lp++;
-	else
+		if (!strcmp(w->name, "Earphone Driver")) {
+			/* Earphone doesn't support low power mode */
+			priv->power_mode_forced = 1;
+			ret = headset_power_mode(codec, 1);
+		}
+	} else {
 		priv->non_lp--;
+		if (!strcmp(w->name, "Earphone Driver")) {
+			priv->power_mode_forced = 0;
+			ret = headset_power_mode(codec, priv->headset_mode);
+		}
+	}
 
 	msleep(1);
 
-	return 0;
+	return ret;
 }
 
 static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
@@ -1040,6 +1053,44 @@ static const struct snd_kcontrol_new hfr_mux_controls =
 static const struct snd_kcontrol_new ep_driver_switch_controls =
 	SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
 
+/* Headset power mode */
+static const char *twl6040_headset_power_texts[] = {
+	"Low-Power", "High-Perfomance",
+};
+
+static const struct soc_enum twl6040_headset_power_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_headset_power_texts),
+			twl6040_headset_power_texts);
+
+static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = priv->headset_mode;
+
+	return 0;
+}
+
+static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+	int high_perf = ucontrol->value.enumerated.item[0];
+	int ret;
+
+	if (priv->power_mode_forced)
+		return -EPERM;
+
+	ret = headset_power_mode(codec, high_perf);
+	if (!ret)
+		priv->headset_mode = high_perf;
+
+	return ret;
+}
+
 static const struct snd_kcontrol_new twl6040_snd_controls[] = {
 	/* Capture gains */
 	SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1058,6 +1109,10 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
 		TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
 	SOC_SINGLE_TLV("Earphone Playback Volume",
 		TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
+
+	SOC_ENUM_EXT("Headset Power Mode", twl6040_headset_power_enum,
+		twl6040_headset_power_get_enum,
+		twl6040_headset_power_put_enum),
 };
 
 static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
@@ -1459,9 +1514,6 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	case TWL6040_SYSCLK_SEL_LPPLL:
 		switch (freq) {
 		case 32768:
-			/* headset dac and driver must be in low-power mode */
-			headset_power_mode(codec, 0);
-
 			/* clk32k input requires low-power pll */
 			lppllctl |= TWL6040_LPLLENA;
 			twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
@@ -1529,9 +1581,6 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 			return -EINVAL;
 		}
 
-		/* headset dac and driver must be in high-performance mode */
-		headset_power_mode(codec, 1);
-
 		twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
 		udelay(500);
 		lppllctl |= TWL6040_HPLLSEL;
@@ -1627,6 +1676,8 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 
 	priv->audpwron = audpwron;
 	priv->naudint = naudint;
+	/* default is high-performance mode */
+	priv->headset_mode = 1;
 	priv->workqueue = create_singlethread_workqueue("twl6040-codec");
 
 	if (!priv->workqueue) {
-- 
1.7.4.1