ASoC: twl6040: Move PLL selection to codec driver
It is better if the selection between the Low power, and High performance PLL is handled within the codec driver, not in machine driver(s) to avoid duplicated code, and also to have consistent tracking of the selected PLL, and the resulting differences in supported sample rates. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
7cca606794
commit
af958c72af
|
@ -80,6 +80,7 @@ struct twl6040_data {
|
||||||
int codec_powered;
|
int codec_powered;
|
||||||
int pll;
|
int pll;
|
||||||
int non_lp;
|
int non_lp;
|
||||||
|
int pll_power_mode;
|
||||||
int hs_power_mode;
|
int hs_power_mode;
|
||||||
int hs_power_mode_locked;
|
int hs_power_mode_locked;
|
||||||
unsigned int clk_in;
|
unsigned int clk_in;
|
||||||
|
@ -210,6 +211,37 @@ static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
|
||||||
TWL6040_REG_DLB,
|
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
|
* read twl6040 register cache
|
||||||
*/
|
*/
|
||||||
|
@ -1049,6 +1081,43 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
|
||||||
return ret;
|
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[] = {
|
static const struct snd_kcontrol_new twl6040_snd_controls[] = {
|
||||||
/* Capture gains */
|
/* Capture gains */
|
||||||
SOC_DOUBLE_TLV("Capture Preamplifier Volume",
|
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,
|
SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum,
|
||||||
twl6040_headset_power_get_enum,
|
twl6040_headset_power_get_enum,
|
||||||
twl6040_headset_power_put_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[] = {
|
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;
|
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,
|
static int twl6040_startup(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_dai *dai)
|
struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
|
@ -1427,16 +1467,12 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||||
freq, priv->sysclk);
|
freq, priv->sysclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
priv->sysclk_constraints = &lp_constraints;
|
|
||||||
break;
|
break;
|
||||||
case TWL6040_SYSCLK_SEL_HPPLL:
|
case TWL6040_SYSCLK_SEL_HPPLL:
|
||||||
ret = twl6040_set_pll(twl6040, TWL6040_HPPLL_ID,
|
ret = twl6040_set_pll(twl6040, TWL6040_HPPLL_ID,
|
||||||
freq, priv->sysclk);
|
freq, priv->sysclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
priv->sysclk_constraints = &hp_constraints;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
|
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;
|
goto work_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->sysclk_constraints = &hp_constraints;
|
priv->sysclk_constraints = &lp_constraints;
|
||||||
priv->workqueue = create_singlethread_workqueue("twl6040-codec");
|
priv->workqueue = create_singlethread_workqueue("twl6040-codec");
|
||||||
if (!priv->workqueue) {
|
if (!priv->workqueue) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
|
|
@ -24,5 +24,6 @@
|
||||||
|
|
||||||
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
|
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
|
||||||
struct snd_soc_jack *jack, int report);
|
struct snd_soc_jack *jack, int report);
|
||||||
|
int twl6040_get_clk_id(struct snd_soc_codec *codec);
|
||||||
|
|
||||||
#endif /* End of __TWL6040_H__ */
|
#endif /* End of __TWL6040_H__ */
|
||||||
|
|
|
@ -36,8 +36,6 @@
|
||||||
#include "omap-pcm.h"
|
#include "omap-pcm.h"
|
||||||
#include "../codecs/twl6040.h"
|
#include "../codecs/twl6040.h"
|
||||||
|
|
||||||
static int twl6040_power_mode;
|
|
||||||
|
|
||||||
static int sdp4430_hw_params(struct snd_pcm_substream *substream,
|
static int sdp4430_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
|
@ -46,13 +44,13 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
|
||||||
int clk_id, freq;
|
int clk_id, freq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (twl6040_power_mode) {
|
clk_id = twl6040_get_clk_id(rtd->codec);
|
||||||
clk_id = TWL6040_SYSCLK_SEL_HPPLL;
|
if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
|
||||||
freq = 38400000;
|
freq = 38400000;
|
||||||
} else {
|
else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
|
||||||
clk_id = TWL6040_SYSCLK_SEL_LPPLL;
|
|
||||||
freq = 32768;
|
freq = 32768;
|
||||||
}
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* set the codec mclk */
|
/* set the codec mclk */
|
||||||
ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
|
ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
|
||||||
|
@ -83,35 +81,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sdp4430_get_power_mode(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
ucontrol->value.integer.value[0] = twl6040_power_mode;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sdp4430_set_power_mode(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
if (twl6040_power_mode == ucontrol->value.integer.value[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
twl6040_power_mode = ucontrol->value.integer.value[0];
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *power_texts[] = {"Low-Power", "High-Performance"};
|
|
||||||
|
|
||||||
static const struct soc_enum sdp4430_enum[] = {
|
|
||||||
SOC_ENUM_SINGLE_EXT(2, power_texts),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct snd_kcontrol_new sdp4430_controls[] = {
|
|
||||||
SOC_ENUM_EXT("TWL6040 Power Mode", sdp4430_enum[0],
|
|
||||||
sdp4430_get_power_mode, sdp4430_set_power_mode),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* SDP4430 machine DAPM */
|
/* SDP4430 machine DAPM */
|
||||||
static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
|
static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
|
||||||
SND_SOC_DAPM_MIC("Ext Mic", NULL),
|
SND_SOC_DAPM_MIC("Ext Mic", NULL),
|
||||||
|
@ -154,12 +123,6 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
|
||||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Add SDP4430 specific controls */
|
|
||||||
ret = snd_soc_add_controls(codec, sdp4430_controls,
|
|
||||||
ARRAY_SIZE(sdp4430_controls));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Add SDP4430 specific widgets */
|
/* Add SDP4430 specific widgets */
|
||||||
ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
|
ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
|
||||||
ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
|
ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
|
||||||
|
@ -239,9 +202,6 @@ static int __init sdp4430_soc_init(void)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* Codec starts in HP mode */
|
|
||||||
twl6040_power_mode = 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
|
Loading…
Reference in New Issue