Skip to content

Commit

Permalink
ASoC: TWL4030: Optimize the power up sequence
Browse files Browse the repository at this point in the history
Since the reg cache now contains the chip default values
for all registers (REG_OPTION is reset to it's default
within this patch), there is no longer need to rewrite
_all_ registers.
Initialize only few selected registers.

According to the latest information, the offset cancellation
need to be done only once, when the codec is powered on, so
there is no need for the power up wrapper.

Move all chip initialization code under chip_init, and do
it when the codec is initialized.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
  • Loading branch information
Peter Ujfalusi authored and Liam Girdwood committed May 31, 2010
1 parent 979bb1f commit ee4ccac
Showing 1 changed file with 60 additions and 73 deletions.
133 changes: 60 additions & 73 deletions sound/soc/codecs/twl4030.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* this register not used */
0x00, /* REG_CODEC_MODE (0x1) */
0xc3, /* REG_OPTION (0x2) */
0x00, /* REG_OPTION (0x2) */
0x00, /* REG_UNKNOWN (0x3) */
0x00, /* REG_MICBIAS_CTL (0x4) */
0x00, /* REG_ANAMICL (0x5) */
Expand Down Expand Up @@ -243,62 +243,52 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
udelay(10);
}

static void twl4030_init_chip(struct snd_soc_codec *codec)
{
u8 *cache = codec->reg_cache;
int i;

/* clear CODECPDZ prior to setting register defaults */
twl4030_codec_enable(codec, 0);

/* set all audio section registers to reasonable defaults */
for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
if (i != TWL4030_REG_APLL_CTL)
twl4030_write(codec, i, cache[i]);

}

static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
static void twl4030_init_chip(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct twl4030_setup_data *setup = socdev->codec_data;
struct snd_soc_codec *codec = socdev->card->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
int status = -1;
u8 reg, byte;
int i = 0;

if (enable) {
twl4030->apll_enabled++;
if (twl4030->apll_enabled == 1)
status = twl4030_codec_enable_resource(
TWL4030_CODEC_RES_APLL);
} else {
twl4030->apll_enabled--;
if (!twl4030->apll_enabled)
status = twl4030_codec_disable_resource(
TWL4030_CODEC_RES_APLL);
}
/* Refresh APLL_CTL register from HW */
twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
TWL4030_REG_APLL_CTL);
twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);

if (status >= 0)
twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
}
/* anti-pop when changing analog gain */
reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
twl4030_write(codec, TWL4030_REG_MISC_SET_1,
reg | TWL4030_SMOOTH_ANAVOL_EN);

static void twl4030_power_up(struct snd_soc_codec *codec)
{
struct snd_soc_device *socdev = codec->socdev;
struct twl4030_setup_data *setup = socdev->codec_data;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 anamicl, regmisc1, byte;
int i = 0;
twl4030_write(codec, TWL4030_REG_OPTION,
TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);

if (twl4030->codec_powered)
/* Machine dependent setup */
if (!setup)
return;

/* set CODECPDZ to turn on codec */
twl4030_codec_enable(codec, 1);
/* Configuration for headset ramp delay from setup data */
if (setup->sysclk != twl4030->sysclk)
dev_warn(codec->dev,
"Mismatch in APLL mclk: %u (configured: %u)\n",
setup->sysclk, twl4030->sysclk);

reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
reg &= ~TWL4030_RAMP_DELAY;
reg |= (setup->ramp_delay_value << 2);
twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);

/* initiate offset cancellation */
anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
anamicl &= ~TWL4030_OFFSET_CNCL_SEL;
anamicl |= setup->offset_cncl_path;
twl4030_codec_enable(codec, 1);

reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
reg &= ~TWL4030_OFFSET_CNCL_SEL;
reg |= setup->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
anamicl | TWL4030_CNCL_OFFSET_START);
reg | TWL4030_CNCL_OFFSET_START);

/* wait for offset cancellation to complete */
do {
Expand All @@ -313,14 +303,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec)
/* Make sure that the reg_cache has the same value as the HW */
twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);

/* anti-pop when changing analog gain */
regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
twl4030_write(codec, TWL4030_REG_MISC_SET_1,
regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);

/* toggle CODECPDZ as per TRM */
twl4030_codec_enable(codec, 0);
twl4030_codec_enable(codec, 1);
}

static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
int status = -1;

if (enable) {
twl4030->apll_enabled++;
if (twl4030->apll_enabled == 1)
status = twl4030_codec_enable_resource(
TWL4030_CODEC_RES_APLL);
} else {
twl4030->apll_enabled--;
if (!twl4030->apll_enabled)
status = twl4030_codec_disable_resource(
TWL4030_CODEC_RES_APLL);
}

if (status >= 0)
twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
}

/* Earpiece */
Expand Down Expand Up @@ -1599,7 +1603,7 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF)
twl4030_power_up(codec);
twl4030_codec_enable(codec, 1);
break;
case SND_SOC_BIAS_OFF:
twl4030_codec_enable(codec, 0);
Expand Down Expand Up @@ -2196,31 +2200,16 @@ static struct snd_soc_codec *twl4030_codec;
static int twl4030_soc_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct twl4030_setup_data *setup = socdev->codec_data;
struct snd_soc_codec *codec;
struct twl4030_priv *twl4030;
int ret;

BUG_ON(!twl4030_codec);

codec = twl4030_codec;
twl4030 = snd_soc_codec_get_drvdata(codec);
socdev->card->codec = codec;

/* Configuration for headset ramp delay from setup data */
if (setup) {
unsigned char hs_pop;

if (setup->sysclk != twl4030->sysclk)
dev_warn(&pdev->dev,
"Mismatch in APLL mclk: %u (configured: %u)\n",
setup->sysclk, twl4030->sysclk);

hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
hs_pop &= ~TWL4030_RAMP_DELAY;
hs_pop |= (setup->ramp_delay_value << 2);
twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
}
twl4030_init_chip(pdev);
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
Expand Down Expand Up @@ -2296,9 +2285,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)

/* Set the defaults, and power up the codec */
twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
twl4030_init_chip(codec);
codec->bias_level = SND_SOC_BIAS_OFF;
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

ret = snd_soc_register_codec(codec);
if (ret != 0) {
Expand Down

0 comments on commit ee4ccac

Please sign in to comment.