aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/twl6040.c62
1 files changed, 57 insertions, 5 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 7845cdb65a4a..c8f7fc28a16d 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -79,6 +79,8 @@ struct twl6040_data {
79 int codec_powered; 79 int codec_powered;
80 int pll; 80 int pll;
81 int non_lp; 81 int non_lp;
82 int hs_power_mode;
83 int hs_power_mode_locked;
82 unsigned int clk_in; 84 unsigned int clk_in;
83 unsigned int sysclk; 85 unsigned int sysclk;
84 struct snd_pcm_hw_constraint_list *sysclk_constraints; 86 struct snd_pcm_hw_constraint_list *sysclk_constraints;
@@ -651,15 +653,26 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
651{ 653{
652 struct snd_soc_codec *codec = w->codec; 654 struct snd_soc_codec *codec = w->codec;
653 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 655 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
656 int ret = 0;
654 657
655 if (SND_SOC_DAPM_EVENT_ON(event)) 658 if (SND_SOC_DAPM_EVENT_ON(event)) {
656 priv->non_lp++; 659 priv->non_lp++;
657 else 660 if (!strcmp(w->name, "Earphone Driver")) {
661 /* Earphone doesn't support low power mode */
662 priv->hs_power_mode_locked = 1;
663 ret = headset_power_mode(codec, 1);
664 }
665 } else {
658 priv->non_lp--; 666 priv->non_lp--;
667 if (!strcmp(w->name, "Earphone Driver")) {
668 priv->hs_power_mode_locked = 0;
669 ret = headset_power_mode(codec, priv->hs_power_mode);
670 }
671 }
659 672
660 msleep(1); 673 msleep(1);
661 674
662 return 0; 675 return ret;
663} 676}
664 677
665static void twl6040_hs_jack_report(struct snd_soc_codec *codec, 678static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
@@ -964,6 +977,43 @@ static const struct snd_kcontrol_new hfr_mux_controls =
964static const struct snd_kcontrol_new ep_driver_switch_controls = 977static const struct snd_kcontrol_new ep_driver_switch_controls =
965 SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); 978 SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
966 979
980/* Headset power mode */
981static const char *twl6040_headset_power_texts[] = {
982 "Low-Power", "High-Perfomance",
983};
984
985static const struct soc_enum twl6040_headset_power_enum =
986 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_headset_power_texts),
987 twl6040_headset_power_texts);
988
989static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
990 struct snd_ctl_elem_value *ucontrol)
991{
992 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
993 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
994
995 ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
996
997 return 0;
998}
999
1000static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
1001 struct snd_ctl_elem_value *ucontrol)
1002{
1003 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1004 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1005 int high_perf = ucontrol->value.enumerated.item[0];
1006 int ret = 0;
1007
1008 if (!priv->hs_power_mode_locked)
1009 ret = headset_power_mode(codec, high_perf);
1010
1011 if (!ret)
1012 priv->hs_power_mode = high_perf;
1013
1014 return ret;
1015}
1016
967static const struct snd_kcontrol_new twl6040_snd_controls[] = { 1017static const struct snd_kcontrol_new twl6040_snd_controls[] = {
968 /* Capture gains */ 1018 /* Capture gains */
969 SOC_DOUBLE_TLV("Capture Preamplifier Volume", 1019 SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -982,6 +1032,10 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
982 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv), 1032 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
983 SOC_SINGLE_TLV("Earphone Playback Volume", 1033 SOC_SINGLE_TLV("Earphone Playback Volume",
984 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv), 1034 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
1035
1036 SOC_ENUM_EXT("Headset Power Mode", twl6040_headset_power_enum,
1037 twl6040_headset_power_get_enum,
1038 twl6040_headset_power_put_enum),
985}; 1039};
986 1040
987static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { 1041static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
@@ -1339,7 +1393,6 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1339 if (ret) 1393 if (ret)
1340 return ret; 1394 return ret;
1341 1395
1342 headset_power_mode(codec, 0);
1343 priv->sysclk_constraints = &lp_constraints; 1396 priv->sysclk_constraints = &lp_constraints;
1344 break; 1397 break;
1345 case TWL6040_SYSCLK_SEL_HPPLL: 1398 case TWL6040_SYSCLK_SEL_HPPLL:
@@ -1348,7 +1401,6 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1348 if (ret) 1401 if (ret)
1349 return ret; 1402 return ret;
1350 1403
1351 headset_power_mode(codec, 1);
1352 priv->sysclk_constraints = &hp_constraints; 1404 priv->sysclk_constraints = &hp_constraints;
1353 break; 1405 break;
1354 default: 1406 default: