diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 133 |
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 @@ | |||
43 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | 43 | static 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 | ||
246 | static void twl4030_init_chip(struct snd_soc_codec *codec) | 246 | static 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 | |||
261 | static 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 | ||
282 | static 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 | |||
309 | static 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; | |||
2196 | static int twl4030_soc_probe(struct platform_device *pdev) | 2200 | static 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) { |