aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-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) {