aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl4030.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-05-26 04:38:17 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-05-31 06:08:58 -0400
commitee4ccac7cea0e4a4f44bbb109285129e1b293461 (patch)
treed764a7cb2423666fd4c2c108dc20a5c6ce201998 /sound/soc/codecs/twl4030.c
parent979bb1f4b8b058e9fb23d6166807e30b507a1a6d (diff)
ASoC: TWL4030: Optimize the power up sequence
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>
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r--sound/soc/codecs/twl4030.c133
1 files changed, 60 insertions, 73 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index a6cbaf3c51f..08f24de406c 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -43,7 +43,7 @@
43static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 43static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
44 0x00, /* this register not used */ 44 0x00, /* this register not used */
45 0x00, /* REG_CODEC_MODE (0x1) */ 45 0x00, /* REG_CODEC_MODE (0x1) */
46 0xc3, /* REG_OPTION (0x2) */ 46 0x00, /* REG_OPTION (0x2) */
47 0x00, /* REG_UNKNOWN (0x3) */ 47 0x00, /* REG_UNKNOWN (0x3) */
48 0x00, /* REG_MICBIAS_CTL (0x4) */ 48 0x00, /* REG_MICBIAS_CTL (0x4) */
49 0x00, /* REG_ANAMICL (0x5) */ 49 0x00, /* REG_ANAMICL (0x5) */
@@ -243,62 +243,52 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
243 udelay(10); 243 udelay(10);
244} 244}
245 245
246static void twl4030_init_chip(struct snd_soc_codec *codec) 246static void twl4030_init_chip(struct platform_device *pdev)
247{
248 u8 *cache = codec->reg_cache;
249 int i;
250
251 /* clear CODECPDZ prior to setting register defaults */
252 twl4030_codec_enable(codec, 0);
253
254 /* set all audio section registers to reasonable defaults */
255 for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
256 if (i != TWL4030_REG_APLL_CTL)
257 twl4030_write(codec, i, cache[i]);
258
259}
260
261static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
262{ 247{
248 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
249 struct twl4030_setup_data *setup = socdev->codec_data;
250 struct snd_soc_codec *codec = socdev->card->codec;
263 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 251 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
264 int status = -1; 252 u8 reg, byte;
253 int i = 0;
265 254
266 if (enable) { 255 /* Refresh APLL_CTL register from HW */
267 twl4030->apll_enabled++; 256 twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
268 if (twl4030->apll_enabled == 1) 257 TWL4030_REG_APLL_CTL);
269 status = twl4030_codec_enable_resource( 258 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
270 TWL4030_CODEC_RES_APLL);
271 } else {
272 twl4030->apll_enabled--;
273 if (!twl4030->apll_enabled)
274 status = twl4030_codec_disable_resource(
275 TWL4030_CODEC_RES_APLL);
276 }
277 259
278 if (status >= 0) 260 /* anti-pop when changing analog gain */
279 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); 261 reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
280} 262 twl4030_write(codec, TWL4030_REG_MISC_SET_1,
263 reg | TWL4030_SMOOTH_ANAVOL_EN);
281 264
282static void twl4030_power_up(struct snd_soc_codec *codec) 265 twl4030_write(codec, TWL4030_REG_OPTION,
283{ 266 TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
284 struct snd_soc_device *socdev = codec->socdev; 267 TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
285 struct twl4030_setup_data *setup = socdev->codec_data;
286 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
287 u8 anamicl, regmisc1, byte;
288 int i = 0;
289 268
290 if (twl4030->codec_powered) 269 /* Machine dependent setup */
270 if (!setup)
291 return; 271 return;
292 272
293 /* set CODECPDZ to turn on codec */ 273 /* Configuration for headset ramp delay from setup data */
294 twl4030_codec_enable(codec, 1); 274 if (setup->sysclk != twl4030->sysclk)
275 dev_warn(codec->dev,
276 "Mismatch in APLL mclk: %u (configured: %u)\n",
277 setup->sysclk, twl4030->sysclk);
278
279 reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
280 reg &= ~TWL4030_RAMP_DELAY;
281 reg |= (setup->ramp_delay_value << 2);
282 twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
295 283
296 /* initiate offset cancellation */ 284 /* initiate offset cancellation */
297 anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); 285 twl4030_codec_enable(codec, 1);
298 anamicl &= ~TWL4030_OFFSET_CNCL_SEL; 286
299 anamicl |= setup->offset_cncl_path; 287 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
288 reg &= ~TWL4030_OFFSET_CNCL_SEL;
289 reg |= setup->offset_cncl_path;
300 twl4030_write(codec, TWL4030_REG_ANAMICL, 290 twl4030_write(codec, TWL4030_REG_ANAMICL,
301 anamicl | TWL4030_CNCL_OFFSET_START); 291 reg | TWL4030_CNCL_OFFSET_START);
302 292
303 /* wait for offset cancellation to complete */ 293 /* wait for offset cancellation to complete */
304 do { 294 do {
@@ -313,14 +303,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec)
313 /* Make sure that the reg_cache has the same value as the HW */ 303 /* Make sure that the reg_cache has the same value as the HW */
314 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); 304 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
315 305
316 /* anti-pop when changing analog gain */
317 regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
318 twl4030_write(codec, TWL4030_REG_MISC_SET_1,
319 regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
320
321 /* toggle CODECPDZ as per TRM */
322 twl4030_codec_enable(codec, 0); 306 twl4030_codec_enable(codec, 0);
323 twl4030_codec_enable(codec, 1); 307}
308
309static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
310{
311 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
312 int status = -1;
313
314 if (enable) {
315 twl4030->apll_enabled++;
316 if (twl4030->apll_enabled == 1)
317 status = twl4030_codec_enable_resource(
318 TWL4030_CODEC_RES_APLL);
319 } else {
320 twl4030->apll_enabled--;
321 if (!twl4030->apll_enabled)
322 status = twl4030_codec_disable_resource(
323 TWL4030_CODEC_RES_APLL);
324 }
325
326 if (status >= 0)
327 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
324} 328}
325 329
326/* Earpiece */ 330/* Earpiece */
@@ -1599,7 +1603,7 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
1599 break; 1603 break;
1600 case SND_SOC_BIAS_STANDBY: 1604 case SND_SOC_BIAS_STANDBY:
1601 if (codec->bias_level == SND_SOC_BIAS_OFF) 1605 if (codec->bias_level == SND_SOC_BIAS_OFF)
1602 twl4030_power_up(codec); 1606 twl4030_codec_enable(codec, 1);
1603 break; 1607 break;
1604 case SND_SOC_BIAS_OFF: 1608 case SND_SOC_BIAS_OFF:
1605 twl4030_codec_enable(codec, 0); 1609 twl4030_codec_enable(codec, 0);
@@ -2196,31 +2200,16 @@ static struct snd_soc_codec *twl4030_codec;
2196static int twl4030_soc_probe(struct platform_device *pdev) 2200static int twl4030_soc_probe(struct platform_device *pdev)
2197{ 2201{
2198 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 2202 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2199 struct twl4030_setup_data *setup = socdev->codec_data;
2200 struct snd_soc_codec *codec; 2203 struct snd_soc_codec *codec;
2201 struct twl4030_priv *twl4030;
2202 int ret; 2204 int ret;
2203 2205
2204 BUG_ON(!twl4030_codec); 2206 BUG_ON(!twl4030_codec);
2205 2207
2206 codec = twl4030_codec; 2208 codec = twl4030_codec;
2207 twl4030 = snd_soc_codec_get_drvdata(codec);
2208 socdev->card->codec = codec; 2209 socdev->card->codec = codec;
2209 2210
2210 /* Configuration for headset ramp delay from setup data */ 2211 twl4030_init_chip(pdev);
2211 if (setup) { 2212 twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2212 unsigned char hs_pop;
2213
2214 if (setup->sysclk != twl4030->sysclk)
2215 dev_warn(&pdev->dev,
2216 "Mismatch in APLL mclk: %u (configured: %u)\n",
2217 setup->sysclk, twl4030->sysclk);
2218
2219 hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
2220 hs_pop &= ~TWL4030_RAMP_DELAY;
2221 hs_pop |= (setup->ramp_delay_value << 2);
2222 twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
2223 }
2224 2213
2225 /* register pcms */ 2214 /* register pcms */
2226 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 2215 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -2296,9 +2285,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2296 2285
2297 /* Set the defaults, and power up the codec */ 2286 /* Set the defaults, and power up the codec */
2298 twl4030->sysclk = twl4030_codec_get_mclk() / 1000; 2287 twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
2299 twl4030_init_chip(codec);
2300 codec->bias_level = SND_SOC_BIAS_OFF; 2288 codec->bias_level = SND_SOC_BIAS_OFF;
2301 twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2302 2289
2303 ret = snd_soc_register_codec(codec); 2290 ret = snd_soc_register_codec(codec);
2304 if (ret != 0) { 2291 if (ret != 0) {