diff options
-rw-r--r-- | sound/soc/codecs/twl6040.c | 62 |
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 | ||
665 | static void twl6040_hs_jack_report(struct snd_soc_codec *codec, | 678 | static void twl6040_hs_jack_report(struct snd_soc_codec *codec, |
@@ -964,6 +977,43 @@ static const struct snd_kcontrol_new hfr_mux_controls = | |||
964 | static const struct snd_kcontrol_new ep_driver_switch_controls = | 977 | static 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 */ | ||
981 | static const char *twl6040_headset_power_texts[] = { | ||
982 | "Low-Power", "High-Perfomance", | ||
983 | }; | ||
984 | |||
985 | static 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 | |||
989 | static 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 | |||
1000 | static 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 | |||
967 | static const struct snd_kcontrol_new twl6040_snd_controls[] = { | 1017 | static 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 | ||
987 | static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { | 1041 | static 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: |