diff mbox

[v5,15/18] ASoC: twl6040: Remove pll and headset mode dependency

Message ID 1307983070-2257-16-git-send-email-peter.ujfalusi@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Peter Ujfalusi June 13, 2011, 4:37 p.m. UTC
From: Misael Lopez Cruz <misael.lopez@ti.com>

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.

Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 sound/soc/codecs/twl6040.c |   64 +++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 61 insertions(+), 3 deletions(-)

Comments

Peter Ujfalusi June 17, 2011, 1:04 p.m. UTC | #1
On Friday 17 June 2011 15:27:59 Mark Brown wrote:
> On Mon, Jun 13, 2011 at 07:37:47PM +0300, Peter Ujfalusi wrote:
> > From: Misael Lopez Cruz <misael.lopez@ti.com>
> > 
> > Remove dependency between pll (hppll, lppll) and headset power
> > mode (low-power, high-performance), as headset power mode can
> > be used with any pll.
> 
> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> 
> but...
> 
> > 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.
> 
> Might be nicer to allow the user to set the control given that you'll
> just ignore the configured value anyway if it's not usable right now.

Yeah, we can allow the change, but skip the register updates for use cases 
when it is not allowed.

I did spot other issue related to this power mode handling: the DAPM event 
handler has been attached to HFDAC, and not to the HSDAC, so the refcounting 
is done for a wrong set of DAC... The HFDACs has no relationship with the 
Earpiece output (it is connected to HSDACL).
Mark Brown June 17, 2011, 1:27 p.m. UTC | #2
On Mon, Jun 13, 2011 at 07:37:47PM +0300, Peter Ujfalusi wrote:
> From: Misael Lopez Cruz <misael.lopez@ti.com>
> 
> Remove dependency between pll (hppll, lppll) and headset power
> mode (low-power, high-performance), as headset power mode can
> be used with any pll.

Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

but...

> 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.

Might be nicer to allow the user to set the control given that you'll
just ignore the configured value anyway if it's not usable right now.
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 7845cdb..d334d86 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -79,6 +79,8 @@  struct twl6040_data {
 	int codec_powered;
 	int pll;
 	int non_lp;
+	int power_mode_forced;
+	int headset_mode;
 	unsigned int clk_in;
 	unsigned int sysclk;
 	struct snd_pcm_hw_constraint_list *sysclk_constraints;
@@ -651,15 +653,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,
@@ -964,6 +977,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",
@@ -982,6 +1033,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[] = {
@@ -1450,6 +1505,9 @@  static int twl6040_probe(struct snd_soc_codec *codec)
 	priv->codec = codec;
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 
+	/* default is high-performance mode */
+	priv->headset_mode = 1;
+
 	priv->workqueue = create_singlethread_workqueue("twl6040-codec");
 	if (!priv->workqueue) {
 		ret = -ENOMEM;