summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/twl6040.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/twl6040.c')
-rw-r--r--sound/soc/codecs/twl6040.c110
1 files changed, 73 insertions, 37 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 8f923e5c9e48..94108ce63c6b 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -80,6 +80,7 @@ struct twl6040_data {
int codec_powered;
int pll;
int non_lp;
+ int pll_power_mode;
int hs_power_mode;
int hs_power_mode_locked;
unsigned int clk_in;
@@ -210,6 +211,37 @@ static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
TWL6040_REG_DLB,
};
+/* set of rates for each pll: low-power and high-performance */
+static unsigned int lp_rates[] = {
+ 8000,
+ 11250,
+ 16000,
+ 22500,
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+};
+
+static struct snd_pcm_hw_constraint_list lp_constraints = {
+ .count = ARRAY_SIZE(lp_rates),
+ .list = lp_rates,
+};
+
+static unsigned int hp_rates[] = {
+ 8000,
+ 16000,
+ 32000,
+ 48000,
+ 96000,
+};
+
+static struct snd_pcm_hw_constraint_list hp_constraints = {
+ .count = ARRAY_SIZE(hp_rates),
+ .list = hp_rates,
+};
+
/*
* read twl6040 register cache
*/
@@ -1049,6 +1081,43 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
return ret;
}
+static int twl6040_pll_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->pll_power_mode;
+
+ return 0;
+}
+
+static int twl6040_pll_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);
+
+ priv->pll_power_mode = ucontrol->value.enumerated.item[0];
+ if (priv->pll_power_mode)
+ priv->sysclk_constraints = &hp_constraints;
+ else
+ priv->sysclk_constraints = &lp_constraints;
+
+ return 0;
+}
+
+int twl6040_get_clk_id(struct snd_soc_codec *codec)
+{
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+ if (priv->pll_power_mode)
+ return TWL6040_SYSCLK_SEL_HPPLL;
+ else
+ return TWL6040_SYSCLK_SEL_LPPLL;
+}
+EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
+
static const struct snd_kcontrol_new twl6040_snd_controls[] = {
/* Capture gains */
SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1071,6 +1140,9 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum,
twl6040_headset_power_get_enum,
twl6040_headset_power_put_enum),
+
+ SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum,
+ twl6040_pll_get_enum, twl6040_pll_put_enum),
};
static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
@@ -1289,38 +1361,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-/* set of rates for each pll: low-power and high-performance */
-
-static unsigned int lp_rates[] = {
- 8000,
- 11250,
- 16000,
- 22500,
- 32000,
- 44100,
- 48000,
- 88200,
- 96000,
-};
-
-static struct snd_pcm_hw_constraint_list lp_constraints = {
- .count = ARRAY_SIZE(lp_rates),
- .list = lp_rates,
-};
-
-static unsigned int hp_rates[] = {
- 8000,
- 16000,
- 32000,
- 48000,
- 96000,
-};
-
-static struct snd_pcm_hw_constraint_list hp_constraints = {
- .count = ARRAY_SIZE(hp_rates),
- .list = hp_rates,
-};
-
static int twl6040_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -1427,16 +1467,12 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
freq, priv->sysclk);
if (ret)
return ret;
-
- priv->sysclk_constraints = &lp_constraints;
break;
case TWL6040_SYSCLK_SEL_HPPLL:
ret = twl6040_set_pll(twl6040, TWL6040_HPPLL_ID,
freq, priv->sysclk);
if (ret)
return ret;
-
- priv->sysclk_constraints = &hp_constraints;
break;
default:
dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
@@ -1563,7 +1599,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
goto work_err;
}
- priv->sysclk_constraints = &hp_constraints;
+ priv->sysclk_constraints = &lp_constraints;
priv->workqueue = create_singlethread_workqueue("twl6040-codec");
if (!priv->workqueue) {
ret = -ENOMEM;