aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-26 20:42:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-26 20:42:18 -0400
commitb0189cd087aa82bd23277cb5c8960ab030e13e5c (patch)
tree7b1a4c152cd62ce136fd5b0e4379d58eb2244e66 /sound/soc
parent69f1d1a6acbaa7d83ef3f4ee26209c58cd000204 (diff)
parentbc574e190d3fbed37d724e33a16aee326d6f2ac4 (diff)
Merge branch 'next/devel2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc
* 'next/devel2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc: (47 commits) OMAP: Add debugfs node to show the summary of all clocks OMAP2+: hwmod: Follow the recommended PRCM module enable sequence OMAP2+: clock: allow per-SoC clock init code to prevent clockdomain calls from clock code OMAP2+: clockdomain: Add per clkdm lock to prevent concurrent state programming OMAP2+: PM: idle clkdms only if already in idle OMAP2+: clockdomain: add clkdm_in_hwsup() OMAP2+: clockdomain: Add 2 APIs to control clockdomain from hwmod framework OMAP: clockdomain: Remove redundant call to pwrdm_wait_transition() OMAP4: hwmod: Introduce the module control in hwmod control OMAP4: cm: Add two new APIs for modulemode control OMAP4: hwmod data: Add modulemode entry in omap_hwmod structure OMAP4: hwmod data: Add PRM context register offset OMAP4: prm: Remove deprecated functions OMAP4: prm: Replace warm reset API with the offset based version OMAP4: hwmod: Replace RSTCTRL absolute address with offset macros OMAP: hwmod: Wait the idle status to be disabled OMAP4: hwmod: Replace CLKCTRL absolute address with offset macros OMAP2+: hwmod: Init clkdm field at boot time OMAP4: hwmod data: Add clock domain attribute OMAP4: clock data: Add missing divider selection for auxclks ...
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/twl4030.c22
-rw-r--r--sound/soc/codecs/twl6040.c733
-rw-r--r--sound/soc/codecs/twl6040.h119
-rw-r--r--sound/soc/omap/sdp3430.c2
-rw-r--r--sound/soc/omap/sdp4430.c52
-rw-r--r--sound/soc/omap/zoom2.c2
7 files changed, 351 insertions, 582 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 36a030f1d1f5..379b2e3afd98 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -250,10 +250,11 @@ config SND_SOC_TLV320DAC33
250 tristate 250 tristate
251 251
252config SND_SOC_TWL4030 252config SND_SOC_TWL4030
253 select TWL4030_CODEC 253 select MFD_TWL4030_AUDIO
254 tristate 254 tristate
255 255
256config SND_SOC_TWL6040 256config SND_SOC_TWL6040
257 select TWL6040_CORE
257 tristate 258 tristate
258 259
259config SND_SOC_UDA134X 260config SND_SOC_UDA134X
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index bec788b12613..71674bec9604 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -36,7 +36,7 @@
36#include <sound/tlv.h> 36#include <sound/tlv.h>
37 37
38/* Register descriptions are here */ 38/* Register descriptions are here */
39#include <linux/mfd/twl4030-codec.h> 39#include <linux/mfd/twl4030-audio.h>
40 40
41/* Shadow register used by the audio driver */ 41/* Shadow register used by the audio driver */
42#define TWL4030_REG_SW_SHADOW 0x4A 42#define TWL4030_REG_SW_SHADOW 0x4A
@@ -251,9 +251,9 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
251 return; 251 return;
252 252
253 if (enable) 253 if (enable)
254 mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER); 254 mode = twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
255 else 255 else
256 mode = twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER); 256 mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
257 257
258 if (mode >= 0) { 258 if (mode >= 0) {
259 twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode); 259 twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode);
@@ -297,7 +297,7 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
297 297
298static void twl4030_init_chip(struct snd_soc_codec *codec) 298static void twl4030_init_chip(struct snd_soc_codec *codec)
299{ 299{
300 struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev); 300 struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
301 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 301 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
302 u8 reg, byte; 302 u8 reg, byte;
303 int i = 0; 303 int i = 0;
@@ -375,13 +375,13 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
375 if (enable) { 375 if (enable) {
376 twl4030->apll_enabled++; 376 twl4030->apll_enabled++;
377 if (twl4030->apll_enabled == 1) 377 if (twl4030->apll_enabled == 1)
378 status = twl4030_codec_enable_resource( 378 status = twl4030_audio_enable_resource(
379 TWL4030_CODEC_RES_APLL); 379 TWL4030_AUDIO_RES_APLL);
380 } else { 380 } else {
381 twl4030->apll_enabled--; 381 twl4030->apll_enabled--;
382 if (!twl4030->apll_enabled) 382 if (!twl4030->apll_enabled)
383 status = twl4030_codec_disable_resource( 383 status = twl4030_audio_disable_resource(
384 TWL4030_CODEC_RES_APLL); 384 TWL4030_AUDIO_RES_APLL);
385 } 385 }
386 386
387 if (status >= 0) 387 if (status >= 0)
@@ -732,7 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
732 732
733static void headset_ramp(struct snd_soc_codec *codec, int ramp) 733static void headset_ramp(struct snd_soc_codec *codec, int ramp)
734{ 734{
735 struct twl4030_codec_audio_data *pdata = codec->dev->platform_data; 735 struct twl4030_codec_data *pdata = codec->dev->platform_data;
736 unsigned char hs_gain, hs_pop; 736 unsigned char hs_gain, hs_pop;
737 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 737 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
738 /* Base values for ramp delay calculation: 2^19 - 2^26 */ 738 /* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -2260,7 +2260,7 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
2260 } 2260 }
2261 snd_soc_codec_set_drvdata(codec, twl4030); 2261 snd_soc_codec_set_drvdata(codec, twl4030);
2262 /* Set the defaults, and power up the codec */ 2262 /* Set the defaults, and power up the codec */
2263 twl4030->sysclk = twl4030_codec_get_mclk() / 1000; 2263 twl4030->sysclk = twl4030_audio_get_mclk() / 1000;
2264 codec->dapm.idle_bias_off = 1; 2264 codec->dapm.idle_bias_off = 1;
2265 2265
2266 twl4030_init_chip(codec); 2266 twl4030_init_chip(codec);
@@ -2297,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
2297 2297
2298static int __devinit twl4030_codec_probe(struct platform_device *pdev) 2298static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2299{ 2299{
2300 struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; 2300 struct twl4030_codec_data *pdata = pdev->dev.platform_data;
2301 2301
2302 if (!pdata) { 2302 if (!pdata) {
2303 dev_err(&pdev->dev, "platform_data is missing\n"); 2303 dev_err(&pdev->dev, "platform_data is missing\n");
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index cd63bba623df..443032b3b329 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -24,11 +24,10 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/delay.h> 25#include <linux/delay.h>
26#include <linux/pm.h> 26#include <linux/pm.h>
27#include <linux/i2c.h>
28#include <linux/gpio.h>
29#include <linux/platform_device.h> 27#include <linux/platform_device.h>
30#include <linux/slab.h> 28#include <linux/slab.h>
31#include <linux/i2c/twl.h> 29#include <linux/i2c/twl.h>
30#include <linux/mfd/twl6040.h>
32 31
33#include <sound/core.h> 32#include <sound/core.h>
34#include <sound/pcm.h> 33#include <sound/pcm.h>
@@ -77,14 +76,19 @@ struct twl6040_jack_data {
77 76
78/* codec private data */ 77/* codec private data */
79struct twl6040_data { 78struct twl6040_data {
80 int audpwron; 79 int plug_irq;
81 int naudint;
82 int codec_powered; 80 int codec_powered;
83 int pll; 81 int pll;
84 int non_lp; 82 int non_lp;
83 int pll_power_mode;
84 int hs_power_mode;
85 int hs_power_mode_locked;
86 unsigned int clk_in;
85 unsigned int sysclk; 87 unsigned int sysclk;
86 struct snd_pcm_hw_constraint_list *sysclk_constraints; 88 u16 hs_left_step;
87 struct completion ready; 89 u16 hs_right_step;
90 u16 hf_left_step;
91 u16 hf_right_step;
88 struct twl6040_jack_data hs_jack; 92 struct twl6040_jack_data hs_jack;
89 struct snd_soc_codec *codec; 93 struct snd_soc_codec *codec;
90 struct workqueue_struct *workqueue; 94 struct workqueue_struct *workqueue;
@@ -206,6 +210,32 @@ static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
206 TWL6040_REG_DLB, 210 TWL6040_REG_DLB,
207}; 211};
208 212
213/* set of rates for each pll: low-power and high-performance */
214static unsigned int lp_rates[] = {
215 8000,
216 11250,
217 16000,
218 22500,
219 32000,
220 44100,
221 48000,
222 88200,
223 96000,
224};
225
226static unsigned int hp_rates[] = {
227 8000,
228 16000,
229 32000,
230 48000,
231 96000,
232};
233
234static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
235 { .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },
236 { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
237};
238
209/* 239/*
210 * read twl6040 register cache 240 * read twl6040 register cache
211 */ 241 */
@@ -239,12 +269,13 @@ static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
239static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, 269static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
240 unsigned int reg) 270 unsigned int reg)
241{ 271{
272 struct twl6040 *twl6040 = codec->control_data;
242 u8 value; 273 u8 value;
243 274
244 if (reg >= TWL6040_CACHEREGNUM) 275 if (reg >= TWL6040_CACHEREGNUM)
245 return -EIO; 276 return -EIO;
246 277
247 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &value, reg); 278 value = twl6040_reg_read(twl6040, reg);
248 twl6040_write_reg_cache(codec, reg, value); 279 twl6040_write_reg_cache(codec, reg, value);
249 280
250 return value; 281 return value;
@@ -256,11 +287,13 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
256static int twl6040_write(struct snd_soc_codec *codec, 287static int twl6040_write(struct snd_soc_codec *codec,
257 unsigned int reg, unsigned int value) 288 unsigned int reg, unsigned int value)
258{ 289{
290 struct twl6040 *twl6040 = codec->control_data;
291
259 if (reg >= TWL6040_CACHEREGNUM) 292 if (reg >= TWL6040_CACHEREGNUM)
260 return -EIO; 293 return -EIO;
261 294
262 twl6040_write_reg_cache(codec, reg, value); 295 twl6040_write_reg_cache(codec, reg, value);
263 return twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, value, reg); 296 return twl6040_reg_write(twl6040, reg, value);
264} 297}
265 298
266static void twl6040_init_vio_regs(struct snd_soc_codec *codec) 299static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
@@ -268,15 +301,21 @@ static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
268 u8 *cache = codec->reg_cache; 301 u8 *cache = codec->reg_cache;
269 int reg, i; 302 int reg, i;
270 303
271 /* allow registers to be accessed by i2c */
272 twl6040_write(codec, TWL6040_REG_ACCCTL, cache[TWL6040_REG_ACCCTL]);
273
274 for (i = 0; i < TWL6040_VIOREGNUM; i++) { 304 for (i = 0; i < TWL6040_VIOREGNUM; i++) {
275 reg = twl6040_vio_reg[i]; 305 reg = twl6040_vio_reg[i];
276 /* skip read-only registers (ASICID, ASICREV, STATUS) */ 306 /*
307 * skip read-only registers (ASICID, ASICREV, STATUS)
308 * and registers shared among MFD children
309 */
277 switch (reg) { 310 switch (reg) {
278 case TWL6040_REG_ASICID: 311 case TWL6040_REG_ASICID:
279 case TWL6040_REG_ASICREV: 312 case TWL6040_REG_ASICREV:
313 case TWL6040_REG_INTID:
314 case TWL6040_REG_INTMR:
315 case TWL6040_REG_NCPCTL:
316 case TWL6040_REG_LDOCTL:
317 case TWL6040_REG_GPOCTL:
318 case TWL6040_REG_ACCCTL:
280 case TWL6040_REG_STATUS: 319 case TWL6040_REG_STATUS:
281 continue; 320 continue;
282 default: 321 default:
@@ -293,6 +332,20 @@ static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
293 332
294 for (i = 0; i < TWL6040_VDDREGNUM; i++) { 333 for (i = 0; i < TWL6040_VDDREGNUM; i++) {
295 reg = twl6040_vdd_reg[i]; 334 reg = twl6040_vdd_reg[i];
335 /* skip vibra and PLL registers */
336 switch (reg) {
337 case TWL6040_REG_VIBCTLL:
338 case TWL6040_REG_VIBDATL:
339 case TWL6040_REG_VIBCTLR:
340 case TWL6040_REG_VIBDATR:
341 case TWL6040_REG_HPPLLCTL:
342 case TWL6040_REG_LPPLLCTL:
343 case TWL6040_REG_LPPLLDIV:
344 continue;
345 default:
346 break;
347 }
348
296 twl6040_write(codec, reg, cache[reg]); 349 twl6040_write(codec, reg, cache[reg]);
297 } 350 }
298} 351}
@@ -317,7 +370,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
317 if (headset->ramp == TWL6040_RAMP_UP) { 370 if (headset->ramp == TWL6040_RAMP_UP) {
318 /* ramp step up */ 371 /* ramp step up */
319 if (val < headset->left_vol) { 372 if (val < headset->left_vol) {
320 val += left_step; 373 if (val + left_step > headset->left_vol)
374 val = headset->left_vol;
375 else
376 val += left_step;
377
321 reg &= ~TWL6040_HSL_VOL_MASK; 378 reg &= ~TWL6040_HSL_VOL_MASK;
322 twl6040_write(codec, TWL6040_REG_HSGAIN, 379 twl6040_write(codec, TWL6040_REG_HSGAIN,
323 (reg | (~val & TWL6040_HSL_VOL_MASK))); 380 (reg | (~val & TWL6040_HSL_VOL_MASK)));
@@ -327,7 +384,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
327 } else if (headset->ramp == TWL6040_RAMP_DOWN) { 384 } else if (headset->ramp == TWL6040_RAMP_DOWN) {
328 /* ramp step down */ 385 /* ramp step down */
329 if (val > 0x0) { 386 if (val > 0x0) {
330 val -= left_step; 387 if ((int)val - (int)left_step < 0)
388 val = 0;
389 else
390 val -= left_step;
391
331 reg &= ~TWL6040_HSL_VOL_MASK; 392 reg &= ~TWL6040_HSL_VOL_MASK;
332 twl6040_write(codec, TWL6040_REG_HSGAIN, reg | 393 twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
333 (~val & TWL6040_HSL_VOL_MASK)); 394 (~val & TWL6040_HSL_VOL_MASK));
@@ -344,7 +405,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
344 if (headset->ramp == TWL6040_RAMP_UP) { 405 if (headset->ramp == TWL6040_RAMP_UP) {
345 /* ramp step up */ 406 /* ramp step up */
346 if (val < headset->right_vol) { 407 if (val < headset->right_vol) {
347 val += right_step; 408 if (val + right_step > headset->right_vol)
409 val = headset->right_vol;
410 else
411 val += right_step;
412
348 reg &= ~TWL6040_HSR_VOL_MASK; 413 reg &= ~TWL6040_HSR_VOL_MASK;
349 twl6040_write(codec, TWL6040_REG_HSGAIN, 414 twl6040_write(codec, TWL6040_REG_HSGAIN,
350 (reg | (~val << TWL6040_HSR_VOL_SHIFT))); 415 (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
@@ -354,7 +419,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
354 } else if (headset->ramp == TWL6040_RAMP_DOWN) { 419 } else if (headset->ramp == TWL6040_RAMP_DOWN) {
355 /* ramp step down */ 420 /* ramp step down */
356 if (val > 0x0) { 421 if (val > 0x0) {
357 val -= right_step; 422 if ((int)val - (int)right_step < 0)
423 val = 0;
424 else
425 val -= right_step;
426
358 reg &= ~TWL6040_HSR_VOL_MASK; 427 reg &= ~TWL6040_HSR_VOL_MASK;
359 twl6040_write(codec, TWL6040_REG_HSGAIN, 428 twl6040_write(codec, TWL6040_REG_HSGAIN,
360 reg | (~val << TWL6040_HSR_VOL_SHIFT)); 429 reg | (~val << TWL6040_HSR_VOL_SHIFT));
@@ -385,7 +454,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
385 if (handsfree->ramp == TWL6040_RAMP_UP) { 454 if (handsfree->ramp == TWL6040_RAMP_UP) {
386 /* ramp step up */ 455 /* ramp step up */
387 if (val < handsfree->left_vol) { 456 if (val < handsfree->left_vol) {
388 val += left_step; 457 if (val + left_step > handsfree->left_vol)
458 val = handsfree->left_vol;
459 else
460 val += left_step;
461
389 reg &= ~TWL6040_HF_VOL_MASK; 462 reg &= ~TWL6040_HF_VOL_MASK;
390 twl6040_write(codec, TWL6040_REG_HFLGAIN, 463 twl6040_write(codec, TWL6040_REG_HFLGAIN,
391 reg | (0x1D - val)); 464 reg | (0x1D - val));
@@ -395,7 +468,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
395 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) { 468 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
396 /* ramp step down */ 469 /* ramp step down */
397 if (val > 0) { 470 if (val > 0) {
398 val -= left_step; 471 if ((int)val - (int)left_step < 0)
472 val = 0;
473 else
474 val -= left_step;
475
399 reg &= ~TWL6040_HF_VOL_MASK; 476 reg &= ~TWL6040_HF_VOL_MASK;
400 twl6040_write(codec, TWL6040_REG_HFLGAIN, 477 twl6040_write(codec, TWL6040_REG_HFLGAIN,
401 reg | (0x1D - val)); 478 reg | (0x1D - val));
@@ -412,7 +489,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
412 if (handsfree->ramp == TWL6040_RAMP_UP) { 489 if (handsfree->ramp == TWL6040_RAMP_UP) {
413 /* ramp step up */ 490 /* ramp step up */
414 if (val < handsfree->right_vol) { 491 if (val < handsfree->right_vol) {
415 val += right_step; 492 if (val + right_step > handsfree->right_vol)
493 val = handsfree->right_vol;
494 else
495 val += right_step;
496
416 reg &= ~TWL6040_HF_VOL_MASK; 497 reg &= ~TWL6040_HF_VOL_MASK;
417 twl6040_write(codec, TWL6040_REG_HFRGAIN, 498 twl6040_write(codec, TWL6040_REG_HFRGAIN,
418 reg | (0x1D - val)); 499 reg | (0x1D - val));
@@ -422,7 +503,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
422 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) { 503 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
423 /* ramp step down */ 504 /* ramp step down */
424 if (val > 0) { 505 if (val > 0) {
425 val -= right_step; 506 if ((int)val - (int)right_step < 0)
507 val = 0;
508 else
509 val -= right_step;
510
426 reg &= ~TWL6040_HF_VOL_MASK; 511 reg &= ~TWL6040_HF_VOL_MASK;
427 twl6040_write(codec, TWL6040_REG_HFRGAIN, 512 twl6040_write(codec, TWL6040_REG_HFRGAIN,
428 reg | (0x1D - val)); 513 reg | (0x1D - val));
@@ -451,11 +536,9 @@ static void twl6040_pga_hs_work(struct work_struct *work)
451 536
452 /* HS PGA volumes have 4 bits of resolution to ramp */ 537 /* HS PGA volumes have 4 bits of resolution to ramp */
453 for (i = 0; i <= 16; i++) { 538 for (i = 0; i <= 16; i++) {
454 headset_complete = 1; 539 headset_complete = twl6040_hs_ramp_step(codec,
455 if (headset->ramp != TWL6040_RAMP_NONE) 540 headset->left_step,
456 headset_complete = twl6040_hs_ramp_step(codec, 541 headset->right_step);
457 headset->left_step,
458 headset->right_step);
459 542
460 /* ramp finished ? */ 543 /* ramp finished ? */
461 if (headset_complete) 544 if (headset_complete)
@@ -496,11 +579,9 @@ static void twl6040_pga_hf_work(struct work_struct *work)
496 579
497 /* HF PGA volumes have 5 bits of resolution to ramp */ 580 /* HF PGA volumes have 5 bits of resolution to ramp */
498 for (i = 0; i <= 32; i++) { 581 for (i = 0; i <= 32; i++) {
499 handsfree_complete = 1; 582 handsfree_complete = twl6040_hf_ramp_step(codec,
500 if (handsfree->ramp != TWL6040_RAMP_NONE) 583 handsfree->left_step,
501 handsfree_complete = twl6040_hf_ramp_step(codec, 584 handsfree->right_step);
502 handsfree->left_step,
503 handsfree->right_step);
504 585
505 /* ramp finished ? */ 586 /* ramp finished ? */
506 if (handsfree_complete) 587 if (handsfree_complete)
@@ -541,12 +622,16 @@ static int pga_event(struct snd_soc_dapm_widget *w,
541 out = &priv->headset; 622 out = &priv->headset;
542 work = &priv->hs_delayed_work; 623 work = &priv->hs_delayed_work;
543 queue = priv->hs_workqueue; 624 queue = priv->hs_workqueue;
625 out->left_step = priv->hs_left_step;
626 out->right_step = priv->hs_right_step;
544 out->step_delay = 5; /* 5 ms between volume ramp steps */ 627 out->step_delay = 5; /* 5 ms between volume ramp steps */
545 break; 628 break;
546 case 4: 629 case 4:
547 out = &priv->handsfree; 630 out = &priv->handsfree;
548 work = &priv->hf_delayed_work; 631 work = &priv->hf_delayed_work;
549 queue = priv->hf_workqueue; 632 queue = priv->hf_workqueue;
633 out->left_step = priv->hf_left_step;
634 out->right_step = priv->hf_right_step;
550 out->step_delay = 5; /* 5 ms between volume ramp steps */ 635 out->step_delay = 5; /* 5 ms between volume ramp steps */
551 if (SND_SOC_DAPM_EVENT_ON(event)) 636 if (SND_SOC_DAPM_EVENT_ON(event))
552 priv->non_lp++; 637 priv->non_lp++;
@@ -579,8 +664,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
579 664
580 if (!delayed_work_pending(work)) { 665 if (!delayed_work_pending(work)) {
581 /* use volume ramp for power-down */ 666 /* use volume ramp for power-down */
582 out->left_step = 1;
583 out->right_step = 1;
584 out->ramp = TWL6040_RAMP_DOWN; 667 out->ramp = TWL6040_RAMP_DOWN;
585 INIT_COMPLETION(out->ramp_done); 668 INIT_COMPLETION(out->ramp_done);
586 669
@@ -596,88 +679,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
596 return 0; 679 return 0;
597} 680}
598 681
599/* twl6040 codec manual power-up sequence */
600static void twl6040_power_up(struct snd_soc_codec *codec)
601{
602 u8 ncpctl, ldoctl, lppllctl, accctl;
603
604 ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
605 ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
606 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
607 accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
608
609 /* enable reference system */
610 ldoctl |= TWL6040_REFENA;
611 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
612 msleep(10);
613 /* enable internal oscillator */
614 ldoctl |= TWL6040_OSCENA;
615 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
616 udelay(10);
617 /* enable high-side ldo */
618 ldoctl |= TWL6040_HSLDOENA;
619 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
620 udelay(244);
621 /* enable negative charge pump */
622 ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
623 twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
624 udelay(488);
625 /* enable low-side ldo */
626 ldoctl |= TWL6040_LSLDOENA;
627 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
628 udelay(244);
629 /* enable low-power pll */
630 lppllctl |= TWL6040_LPLLENA;
631 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
632 /* reset state machine */
633 accctl |= TWL6040_RESETSPLIT;
634 twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
635 mdelay(5);
636 accctl &= ~TWL6040_RESETSPLIT;
637 twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
638 /* disable internal oscillator */
639 ldoctl &= ~TWL6040_OSCENA;
640 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
641}
642
643/* twl6040 codec manual power-down sequence */
644static void twl6040_power_down(struct snd_soc_codec *codec)
645{
646 u8 ncpctl, ldoctl, lppllctl, accctl;
647
648 ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
649 ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
650 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
651 accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
652
653 /* enable internal oscillator */
654 ldoctl |= TWL6040_OSCENA;
655 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
656 udelay(10);
657 /* disable low-power pll */
658 lppllctl &= ~TWL6040_LPLLENA;
659 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
660 /* disable low-side ldo */
661 ldoctl &= ~TWL6040_LSLDOENA;
662 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
663 udelay(244);
664 /* disable negative charge pump */
665 ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN);
666 twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
667 udelay(488);
668 /* disable high-side ldo */
669 ldoctl &= ~TWL6040_HSLDOENA;
670 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
671 udelay(244);
672 /* disable internal oscillator */
673 ldoctl &= ~TWL6040_OSCENA;
674 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
675 /* disable reference system */
676 ldoctl &= ~TWL6040_REFENA;
677 twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
678 msleep(10);
679}
680
681/* set headset dac and driver power mode */ 682/* set headset dac and driver power mode */
682static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) 683static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
683{ 684{
@@ -713,15 +714,26 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
713{ 714{
714 struct snd_soc_codec *codec = w->codec; 715 struct snd_soc_codec *codec = w->codec;
715 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 716 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
717 int ret = 0;
716 718
717 if (SND_SOC_DAPM_EVENT_ON(event)) 719 if (SND_SOC_DAPM_EVENT_ON(event)) {
718 priv->non_lp++; 720 priv->non_lp++;
719 else 721 if (!strcmp(w->name, "Earphone Driver")) {
722 /* Earphone doesn't support low power mode */
723 priv->hs_power_mode_locked = 1;
724 ret = headset_power_mode(codec, 1);
725 }
726 } else {
720 priv->non_lp--; 727 priv->non_lp--;
728 if (!strcmp(w->name, "Earphone Driver")) {
729 priv->hs_power_mode_locked = 0;
730 ret = headset_power_mode(codec, priv->hs_power_mode);
731 }
732 }
721 733
722 msleep(1); 734 msleep(1);
723 735
724 return 0; 736 return ret;
725} 737}
726 738
727static void twl6040_hs_jack_report(struct snd_soc_codec *codec, 739static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
@@ -766,33 +778,19 @@ static void twl6040_accessory_work(struct work_struct *work)
766} 778}
767 779
768/* audio interrupt handler */ 780/* audio interrupt handler */
769static irqreturn_t twl6040_naudint_handler(int irq, void *data) 781static irqreturn_t twl6040_audio_handler(int irq, void *data)
770{ 782{
771 struct snd_soc_codec *codec = data; 783 struct snd_soc_codec *codec = data;
784 struct twl6040 *twl6040 = codec->control_data;
772 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 785 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
773 u8 intid; 786 u8 intid;
774 787
775 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID); 788 intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
776
777 if (intid & TWL6040_THINT)
778 dev_alert(codec->dev, "die temp over-limit detection\n");
779 789
780 if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT)) 790 if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT))
781 queue_delayed_work(priv->workqueue, &priv->delayed_work, 791 queue_delayed_work(priv->workqueue, &priv->delayed_work,
782 msecs_to_jiffies(200)); 792 msecs_to_jiffies(200));
783 793
784 if (intid & TWL6040_HOOKINT)
785 dev_info(codec->dev, "hook detection\n");
786
787 if (intid & TWL6040_HFINT)
788 dev_alert(codec->dev, "hf drivers over current detection\n");
789
790 if (intid & TWL6040_VIBINT)
791 dev_alert(codec->dev, "vib drivers over current detection\n");
792
793 if (intid & TWL6040_READYINT)
794 complete(&priv->ready);
795
796 return IRQ_HANDLED; 794 return IRQ_HANDLED;
797} 795}
798 796
@@ -1040,6 +1038,73 @@ static const struct snd_kcontrol_new hfr_mux_controls =
1040static const struct snd_kcontrol_new ep_driver_switch_controls = 1038static const struct snd_kcontrol_new ep_driver_switch_controls =
1041 SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); 1039 SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
1042 1040
1041/* Headset power mode */
1042static const char *twl6040_power_mode_texts[] = {
1043 "Low-Power", "High-Perfomance",
1044};
1045
1046static const struct soc_enum twl6040_power_mode_enum =
1047 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_power_mode_texts),
1048 twl6040_power_mode_texts);
1049
1050static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
1051 struct snd_ctl_elem_value *ucontrol)
1052{
1053 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1054 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1055
1056 ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
1057
1058 return 0;
1059}
1060
1061static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
1062 struct snd_ctl_elem_value *ucontrol)
1063{
1064 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1065 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1066 int high_perf = ucontrol->value.enumerated.item[0];
1067 int ret = 0;
1068
1069 if (!priv->hs_power_mode_locked)
1070 ret = headset_power_mode(codec, high_perf);
1071
1072 if (!ret)
1073 priv->hs_power_mode = high_perf;
1074
1075 return ret;
1076}
1077
1078static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
1079 struct snd_ctl_elem_value *ucontrol)
1080{
1081 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1082 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1083
1084 ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
1085
1086 return 0;
1087}
1088
1089static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
1090 struct snd_ctl_elem_value *ucontrol)
1091{
1092 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1093 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1094
1095 priv->pll_power_mode = ucontrol->value.enumerated.item[0];
1096
1097 return 0;
1098}
1099
1100int twl6040_get_clk_id(struct snd_soc_codec *codec)
1101{
1102 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1103
1104 return priv->pll_power_mode;
1105}
1106EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
1107
1043static const struct snd_kcontrol_new twl6040_snd_controls[] = { 1108static const struct snd_kcontrol_new twl6040_snd_controls[] = {
1044 /* Capture gains */ 1109 /* Capture gains */
1045 SOC_DOUBLE_TLV("Capture Preamplifier Volume", 1110 SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1058,6 +1123,13 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
1058 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv), 1123 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
1059 SOC_SINGLE_TLV("Earphone Playback Volume", 1124 SOC_SINGLE_TLV("Earphone Playback Volume",
1060 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv), 1125 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
1126
1127 SOC_ENUM_EXT("Headset Power Mode", twl6040_power_mode_enum,
1128 twl6040_headset_power_get_enum,
1129 twl6040_headset_power_put_enum),
1130
1131 SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum,
1132 twl6040_pll_get_enum, twl6040_pll_put_enum),
1061}; 1133};
1062 1134
1063static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { 1135static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
@@ -1231,36 +1303,11 @@ static int twl6040_add_widgets(struct snd_soc_codec *codec)
1231 return 0; 1303 return 0;
1232} 1304}
1233 1305
1234static int twl6040_power_up_completion(struct snd_soc_codec *codec,
1235 int naudint)
1236{
1237 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1238 int time_left;
1239 u8 intid;
1240
1241 time_left = wait_for_completion_timeout(&priv->ready,
1242 msecs_to_jiffies(144));
1243
1244 if (!time_left) {
1245 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid,
1246 TWL6040_REG_INTID);
1247 if (!(intid & TWL6040_READYINT)) {
1248 dev_err(codec->dev, "timeout waiting for READYINT\n");
1249 return -ETIMEDOUT;
1250 }
1251 }
1252
1253 priv->codec_powered = 1;
1254
1255 return 0;
1256}
1257
1258static int twl6040_set_bias_level(struct snd_soc_codec *codec, 1306static int twl6040_set_bias_level(struct snd_soc_codec *codec,
1259 enum snd_soc_bias_level level) 1307 enum snd_soc_bias_level level)
1260{ 1308{
1309 struct twl6040 *twl6040 = codec->control_data;
1261 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1310 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1262 int audpwron = priv->audpwron;
1263 int naudint = priv->naudint;
1264 int ret; 1311 int ret;
1265 1312
1266 switch (level) { 1313 switch (level) {
@@ -1272,58 +1319,23 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
1272 if (priv->codec_powered) 1319 if (priv->codec_powered)
1273 break; 1320 break;
1274 1321
1275 if (gpio_is_valid(audpwron)) { 1322 ret = twl6040_power(twl6040, 1);
1276 /* use AUDPWRON line */ 1323 if (ret)
1277 gpio_set_value(audpwron, 1); 1324 return ret;
1278 1325
1279 /* wait for power-up completion */ 1326 priv->codec_powered = 1;
1280 ret = twl6040_power_up_completion(codec, naudint);
1281 if (ret)
1282 return ret;
1283
1284 /* sync registers updated during power-up sequence */
1285 twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
1286 twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
1287 twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL);
1288 } else {
1289 /* use manual power-up sequence */
1290 twl6040_power_up(codec);
1291 priv->codec_powered = 1;
1292 }
1293 1327
1294 /* initialize vdd/vss registers with reg_cache */ 1328 /* initialize vdd/vss registers with reg_cache */
1295 twl6040_init_vdd_regs(codec); 1329 twl6040_init_vdd_regs(codec);
1296 1330
1297 /* Set external boost GPO */ 1331 /* Set external boost GPO */
1298 twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02); 1332 twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
1299
1300 /* Set initial minimal gain values */
1301 twl6040_write(codec, TWL6040_REG_HSGAIN, 0xFF);
1302 twl6040_write(codec, TWL6040_REG_EARCTL, 0x1E);
1303 twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1D);
1304 twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1D);
1305 break; 1333 break;
1306 case SND_SOC_BIAS_OFF: 1334 case SND_SOC_BIAS_OFF:
1307 if (!priv->codec_powered) 1335 if (!priv->codec_powered)
1308 break; 1336 break;
1309 1337
1310 if (gpio_is_valid(audpwron)) { 1338 twl6040_power(twl6040, 0);
1311 /* use AUDPWRON line */
1312 gpio_set_value(audpwron, 0);
1313
1314 /* power-down sequence latency */
1315 udelay(500);
1316
1317 /* sync registers updated during power-down sequence */
1318 twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
1319 twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
1320 twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL,
1321 0x00);
1322 } else {
1323 /* use manual power-down sequence */
1324 twl6040_power_down(codec);
1325 }
1326
1327 priv->codec_powered = 0; 1339 priv->codec_powered = 0;
1328 break; 1340 break;
1329 } 1341 }
@@ -1333,27 +1345,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
1333 return 0; 1345 return 0;
1334} 1346}
1335 1347
1336/* set of rates for each pll: low-power and high-performance */
1337
1338static unsigned int lp_rates[] = {
1339 88200,
1340 96000,
1341};
1342
1343static struct snd_pcm_hw_constraint_list lp_constraints = {
1344 .count = ARRAY_SIZE(lp_rates),
1345 .list = lp_rates,
1346};
1347
1348static unsigned int hp_rates[] = {
1349 96000,
1350};
1351
1352static struct snd_pcm_hw_constraint_list hp_constraints = {
1353 .count = ARRAY_SIZE(hp_rates),
1354 .list = hp_rates,
1355};
1356
1357static int twl6040_startup(struct snd_pcm_substream *substream, 1348static int twl6040_startup(struct snd_pcm_substream *substream,
1358 struct snd_soc_dai *dai) 1349 struct snd_soc_dai *dai)
1359{ 1350{
@@ -1363,7 +1354,7 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
1363 1354
1364 snd_pcm_hw_constraint_list(substream->runtime, 0, 1355 snd_pcm_hw_constraint_list(substream->runtime, 0,
1365 SNDRV_PCM_HW_PARAM_RATE, 1356 SNDRV_PCM_HW_PARAM_RATE,
1366 priv->sysclk_constraints); 1357 &sysclk_constraints[priv->pll_power_mode]);
1367 1358
1368 return 0; 1359 return 0;
1369} 1360}
@@ -1375,22 +1366,27 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
1375 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1366 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1376 struct snd_soc_codec *codec = rtd->codec; 1367 struct snd_soc_codec *codec = rtd->codec;
1377 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1368 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1378 u8 lppllctl;
1379 int rate; 1369 int rate;
1380 1370
1381 /* nothing to do for high-perf pll, it supports only 48 kHz */
1382 if (priv->pll == TWL6040_HPPLL_ID)
1383 return 0;
1384
1385 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
1386
1387 rate = params_rate(params); 1371 rate = params_rate(params);
1388 switch (rate) { 1372 switch (rate) {
1389 case 11250: 1373 case 11250:
1390 case 22500: 1374 case 22500:
1391 case 44100: 1375 case 44100:
1392 case 88200: 1376 case 88200:
1393 lppllctl |= TWL6040_LPLLFIN; 1377 /* These rates are not supported when HPPLL is in use */
1378 if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
1379 dev_err(codec->dev, "HPPLL does not support rate %d\n",
1380 rate);
1381 return -EINVAL;
1382 }
1383 /* Capture is not supported with 17.64MHz sysclk */
1384 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1385 dev_err(codec->dev,
1386 "capture mode is not supported at %dHz\n",
1387 rate);
1388 return -EINVAL;
1389 }
1394 priv->sysclk = 17640000; 1390 priv->sysclk = 17640000;
1395 break; 1391 break;
1396 case 8000: 1392 case 8000:
@@ -1398,7 +1394,6 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
1398 case 32000: 1394 case 32000:
1399 case 48000: 1395 case 48000:
1400 case 96000: 1396 case 96000:
1401 lppllctl &= ~TWL6040_LPLLFIN;
1402 priv->sysclk = 19200000; 1397 priv->sysclk = 19200000;
1403 break; 1398 break;
1404 default: 1399 default:
@@ -1406,8 +1401,6 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
1406 return -EINVAL; 1401 return -EINVAL;
1407 } 1402 }
1408 1403
1409 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1410
1411 return 0; 1404 return 0;
1412} 1405}
1413 1406
@@ -1416,7 +1409,9 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
1416{ 1409{
1417 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1410 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1418 struct snd_soc_codec *codec = rtd->codec; 1411 struct snd_soc_codec *codec = rtd->codec;
1412 struct twl6040 *twl6040 = codec->control_data;
1419 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1413 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1414 int ret;
1420 1415
1421 if (!priv->sysclk) { 1416 if (!priv->sysclk) {
1422 dev_err(codec->dev, 1417 dev_err(codec->dev,
@@ -1424,24 +1419,19 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
1424 return -EINVAL; 1419 return -EINVAL;
1425 } 1420 }
1426 1421
1427 /*
1428 * capture is not supported at 17.64 MHz,
1429 * it's reserved for headset low-power playback scenario
1430 */
1431 if ((priv->sysclk == 17640000) &&
1432 substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1433 dev_err(codec->dev,
1434 "capture mode is not supported at %dHz\n",
1435 priv->sysclk);
1436 return -EINVAL;
1437 }
1438
1439 if ((priv->sysclk == 17640000) && priv->non_lp) { 1422 if ((priv->sysclk == 17640000) && priv->non_lp) {
1440 dev_err(codec->dev, 1423 dev_err(codec->dev,
1441 "some enabled paths aren't supported at %dHz\n", 1424 "some enabled paths aren't supported at %dHz\n",
1442 priv->sysclk); 1425 priv->sysclk);
1443 return -EPERM; 1426 return -EPERM;
1444 } 1427 }
1428
1429 ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
1430 if (ret) {
1431 dev_err(codec->dev, "Can not set PLL (%d)\n", ret);
1432 return -EPERM;
1433 }
1434
1445 return 0; 1435 return 0;
1446} 1436}
1447 1437
@@ -1450,99 +1440,12 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1450{ 1440{
1451 struct snd_soc_codec *codec = codec_dai->codec; 1441 struct snd_soc_codec *codec = codec_dai->codec;
1452 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1442 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1453 u8 hppllctl, lppllctl;
1454
1455 hppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_HPPLLCTL);
1456 lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
1457 1443
1458 switch (clk_id) { 1444 switch (clk_id) {
1459 case TWL6040_SYSCLK_SEL_LPPLL: 1445 case TWL6040_SYSCLK_SEL_LPPLL:
1460 switch (freq) {
1461 case 32768:
1462 /* headset dac and driver must be in low-power mode */
1463 headset_power_mode(codec, 0);
1464
1465 /* clk32k input requires low-power pll */
1466 lppllctl |= TWL6040_LPLLENA;
1467 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1468 mdelay(5);
1469 lppllctl &= ~TWL6040_HPLLSEL;
1470 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1471 hppllctl &= ~TWL6040_HPLLENA;
1472 twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
1473 break;
1474 default:
1475 dev_err(codec->dev, "unknown mclk freq %d\n", freq);
1476 return -EINVAL;
1477 }
1478
1479 /* lppll divider */
1480 switch (priv->sysclk) {
1481 case 17640000:
1482 lppllctl |= TWL6040_LPLLFIN;
1483 break;
1484 case 19200000:
1485 lppllctl &= ~TWL6040_LPLLFIN;
1486 break;
1487 default:
1488 /* sysclk not yet configured */
1489 lppllctl &= ~TWL6040_LPLLFIN;
1490 priv->sysclk = 19200000;
1491 break;
1492 }
1493
1494 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1495
1496 priv->pll = TWL6040_LPPLL_ID;
1497 priv->sysclk_constraints = &lp_constraints;
1498 break;
1499 case TWL6040_SYSCLK_SEL_HPPLL: 1446 case TWL6040_SYSCLK_SEL_HPPLL:
1500 hppllctl &= ~TWL6040_MCLK_MSK; 1447 priv->pll = clk_id;
1501 1448 priv->clk_in = freq;
1502 switch (freq) {
1503 case 12000000:
1504 /* mclk input, pll enabled */
1505 hppllctl |= TWL6040_MCLK_12000KHZ |
1506 TWL6040_HPLLSQRBP |
1507 TWL6040_HPLLENA;
1508 break;
1509 case 19200000:
1510 /* mclk input, pll disabled */
1511 hppllctl |= TWL6040_MCLK_19200KHZ |
1512 TWL6040_HPLLSQRENA |
1513 TWL6040_HPLLBP;
1514 break;
1515 case 26000000:
1516 /* mclk input, pll enabled */
1517 hppllctl |= TWL6040_MCLK_26000KHZ |
1518 TWL6040_HPLLSQRBP |
1519 TWL6040_HPLLENA;
1520 break;
1521 case 38400000:
1522 /* clk slicer, pll disabled */
1523 hppllctl |= TWL6040_MCLK_38400KHZ |
1524 TWL6040_HPLLSQRENA |
1525 TWL6040_HPLLBP;
1526 break;
1527 default:
1528 dev_err(codec->dev, "unknown mclk freq %d\n", freq);
1529 return -EINVAL;
1530 }
1531
1532 /* headset dac and driver must be in high-performance mode */
1533 headset_power_mode(codec, 1);
1534
1535 twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
1536 udelay(500);
1537 lppllctl |= TWL6040_HPLLSEL;
1538 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1539 lppllctl &= ~TWL6040_LPLLENA;
1540 twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
1541
1542 /* high-performance pll can provide only 19.2 MHz */
1543 priv->pll = TWL6040_HPPLL_ID;
1544 priv->sysclk = 19200000;
1545 priv->sysclk_constraints = &hp_constraints;
1546 break; 1449 break;
1547 default: 1450 default:
1548 dev_err(codec->dev, "unknown clk_id %d\n", clk_id); 1451 dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
@@ -1559,15 +1462,27 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
1559 .set_sysclk = twl6040_set_dai_sysclk, 1462 .set_sysclk = twl6040_set_dai_sysclk,
1560}; 1463};
1561 1464
1562static struct snd_soc_dai_driver twl6040_dai = { 1465static struct snd_soc_dai_driver twl6040_dai[] = {
1466{
1563 .name = "twl6040-hifi", 1467 .name = "twl6040-hifi",
1564 .playback = { 1468 .playback = {
1565 .stream_name = "Playback", 1469 .stream_name = "Playback",
1566 .channels_min = 1, 1470 .channels_min = 1,
1567 .channels_max = 4, 1471 .channels_max = 2,
1472 .rates = TWL6040_RATES,
1473 .formats = TWL6040_FORMATS,
1474 },
1475 .capture = {
1476 .stream_name = "Capture",
1477 .channels_min = 1,
1478 .channels_max = 2,
1568 .rates = TWL6040_RATES, 1479 .rates = TWL6040_RATES,
1569 .formats = TWL6040_FORMATS, 1480 .formats = TWL6040_FORMATS,
1570 }, 1481 },
1482 .ops = &twl6040_dai_ops,
1483},
1484{
1485 .name = "twl6040-ul",
1571 .capture = { 1486 .capture = {
1572 .stream_name = "Capture", 1487 .stream_name = "Capture",
1573 .channels_min = 1, 1488 .channels_min = 1,
@@ -1576,6 +1491,40 @@ static struct snd_soc_dai_driver twl6040_dai = {
1576 .formats = TWL6040_FORMATS, 1491 .formats = TWL6040_FORMATS,
1577 }, 1492 },
1578 .ops = &twl6040_dai_ops, 1493 .ops = &twl6040_dai_ops,
1494},
1495{
1496 .name = "twl6040-dl1",
1497 .playback = {
1498 .stream_name = "Headset Playback",
1499 .channels_min = 1,
1500 .channels_max = 2,
1501 .rates = TWL6040_RATES,
1502 .formats = TWL6040_FORMATS,
1503 },
1504 .ops = &twl6040_dai_ops,
1505},
1506{
1507 .name = "twl6040-dl2",
1508 .playback = {
1509 .stream_name = "Handsfree Playback",
1510 .channels_min = 1,
1511 .channels_max = 2,
1512 .rates = TWL6040_RATES,
1513 .formats = TWL6040_FORMATS,
1514 },
1515 .ops = &twl6040_dai_ops,
1516},
1517{
1518 .name = "twl6040-vib",
1519 .playback = {
1520 .stream_name = "Vibra Playback",
1521 .channels_min = 2,
1522 .channels_max = 2,
1523 .rates = SNDRV_PCM_RATE_CONTINUOUS,
1524 .formats = TWL6040_FORMATS,
1525 },
1526 .ops = &twl6040_dai_ops,
1527},
1579}; 1528};
1580 1529
1581#ifdef CONFIG_PM 1530#ifdef CONFIG_PM
@@ -1600,11 +1549,11 @@ static int twl6040_resume(struct snd_soc_codec *codec)
1600 1549
1601static int twl6040_probe(struct snd_soc_codec *codec) 1550static int twl6040_probe(struct snd_soc_codec *codec)
1602{ 1551{
1603 struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
1604 struct twl6040_data *priv; 1552 struct twl6040_data *priv;
1605 int audpwron, naudint; 1553 struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
1554 struct platform_device *pdev = container_of(codec->dev,
1555 struct platform_device, dev);
1606 int ret = 0; 1556 int ret = 0;
1607 u8 icrev, intmr = TWL6040_ALLINT_MSK;
1608 1557
1609 priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL); 1558 priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
1610 if (priv == NULL) 1559 if (priv == NULL)
@@ -1612,23 +1561,32 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1612 snd_soc_codec_set_drvdata(codec, priv); 1561 snd_soc_codec_set_drvdata(codec, priv);
1613 1562
1614 priv->codec = codec; 1563 priv->codec = codec;
1564 codec->control_data = dev_get_drvdata(codec->dev->parent);
1615 1565
1616 twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &icrev, TWL6040_REG_ASICREV); 1566 if (pdata && pdata->hs_left_step && pdata->hs_right_step) {
1567 priv->hs_left_step = pdata->hs_left_step;
1568 priv->hs_right_step = pdata->hs_right_step;
1569 } else {
1570 priv->hs_left_step = 1;
1571 priv->hs_right_step = 1;
1572 }
1617 1573
1618 if (twl_codec && (icrev > 0)) 1574 if (pdata && pdata->hf_left_step && pdata->hf_right_step) {
1619 audpwron = twl_codec->audpwron_gpio; 1575 priv->hf_left_step = pdata->hf_left_step;
1620 else 1576 priv->hf_right_step = pdata->hf_right_step;
1621 audpwron = -EINVAL; 1577 } else {
1578 priv->hf_left_step = 1;
1579 priv->hf_right_step = 1;
1580 }
1622 1581
1623 if (twl_codec) 1582 priv->plug_irq = platform_get_irq(pdev, 0);
1624 naudint = twl_codec->naudint_irq; 1583 if (priv->plug_irq < 0) {
1625 else 1584 dev_err(codec->dev, "invalid irq\n");
1626 naudint = 0; 1585 ret = -EINVAL;
1586 goto work_err;
1587 }
1627 1588
1628 priv->audpwron = audpwron;
1629 priv->naudint = naudint;
1630 priv->workqueue = create_singlethread_workqueue("twl6040-codec"); 1589 priv->workqueue = create_singlethread_workqueue("twl6040-codec");
1631
1632 if (!priv->workqueue) { 1590 if (!priv->workqueue) {
1633 ret = -ENOMEM; 1591 ret = -ENOMEM;
1634 goto work_err; 1592 goto work_err;
@@ -1638,56 +1596,33 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1638 1596
1639 mutex_init(&priv->mutex); 1597 mutex_init(&priv->mutex);
1640 1598
1641 init_completion(&priv->ready);
1642 init_completion(&priv->headset.ramp_done); 1599 init_completion(&priv->headset.ramp_done);
1643 init_completion(&priv->handsfree.ramp_done); 1600 init_completion(&priv->handsfree.ramp_done);
1644 1601
1645 if (gpio_is_valid(audpwron)) {
1646 ret = gpio_request(audpwron, "audpwron");
1647 if (ret)
1648 goto gpio1_err;
1649
1650 ret = gpio_direction_output(audpwron, 0);
1651 if (ret)
1652 goto gpio2_err;
1653
1654 priv->codec_powered = 0;
1655
1656 /* enable only codec ready interrupt */
1657 intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK);
1658
1659 /* reset interrupt status to allow correct power up sequence */
1660 twl6040_read_reg_volatile(codec, TWL6040_REG_INTID);
1661 }
1662 twl6040_write(codec, TWL6040_REG_INTMR, intmr);
1663
1664 if (naudint) {
1665 /* audio interrupt */
1666 ret = request_threaded_irq(naudint, NULL,
1667 twl6040_naudint_handler,
1668 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
1669 "twl6040_codec", codec);
1670 if (ret)
1671 goto gpio2_err;
1672 }
1673
1674 /* init vio registers */
1675 twl6040_init_vio_regs(codec);
1676
1677 priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf"); 1602 priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
1678 if (priv->hf_workqueue == NULL) { 1603 if (priv->hf_workqueue == NULL) {
1679 ret = -ENOMEM; 1604 ret = -ENOMEM;
1680 goto irq_err; 1605 goto hfwq_err;
1681 } 1606 }
1682 priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs"); 1607 priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
1683 if (priv->hs_workqueue == NULL) { 1608 if (priv->hs_workqueue == NULL) {
1684 ret = -ENOMEM; 1609 ret = -ENOMEM;
1685 goto wq_err; 1610 goto hswq_err;
1686 } 1611 }
1687 1612
1688 INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work); 1613 INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
1689 INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work); 1614 INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
1690 1615
1616 ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
1617 0, "twl6040_irq_plug", codec);
1618 if (ret) {
1619 dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
1620 goto plugirq_err;
1621 }
1622
1623 /* init vio registers */
1624 twl6040_init_vio_regs(codec);
1625
1691 /* power on device */ 1626 /* power on device */
1692 ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1627 ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1693 if (ret) 1628 if (ret)
@@ -1700,16 +1635,12 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1700 return 0; 1635 return 0;
1701 1636
1702bias_err: 1637bias_err:
1638 free_irq(priv->plug_irq, codec);
1639plugirq_err:
1703 destroy_workqueue(priv->hs_workqueue); 1640 destroy_workqueue(priv->hs_workqueue);
1704wq_err: 1641hswq_err:
1705 destroy_workqueue(priv->hf_workqueue); 1642 destroy_workqueue(priv->hf_workqueue);
1706irq_err: 1643hfwq_err:
1707 if (naudint)
1708 free_irq(naudint, codec);
1709gpio2_err:
1710 if (gpio_is_valid(audpwron))
1711 gpio_free(audpwron);
1712gpio1_err:
1713 destroy_workqueue(priv->workqueue); 1644 destroy_workqueue(priv->workqueue);
1714work_err: 1645work_err:
1715 kfree(priv); 1646 kfree(priv);
@@ -1719,17 +1650,9 @@ work_err:
1719static int twl6040_remove(struct snd_soc_codec *codec) 1650static int twl6040_remove(struct snd_soc_codec *codec)
1720{ 1651{
1721 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); 1652 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
1722 int audpwron = priv->audpwron;
1723 int naudint = priv->naudint;
1724 1653
1725 twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); 1654 twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
1726 1655 free_irq(priv->plug_irq, codec);
1727 if (gpio_is_valid(audpwron))
1728 gpio_free(audpwron);
1729
1730 if (naudint)
1731 free_irq(naudint, codec);
1732
1733 destroy_workqueue(priv->workqueue); 1656 destroy_workqueue(priv->workqueue);
1734 destroy_workqueue(priv->hf_workqueue); 1657 destroy_workqueue(priv->hf_workqueue);
1735 destroy_workqueue(priv->hs_workqueue); 1658 destroy_workqueue(priv->hs_workqueue);
@@ -1753,8 +1676,8 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
1753 1676
1754static int __devinit twl6040_codec_probe(struct platform_device *pdev) 1677static int __devinit twl6040_codec_probe(struct platform_device *pdev)
1755{ 1678{
1756 return snd_soc_register_codec(&pdev->dev, 1679 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040,
1757 &soc_codec_dev_twl6040, &twl6040_dai, 1); 1680 twl6040_dai, ARRAY_SIZE(twl6040_dai));
1758} 1681}
1759 1682
1760static int __devexit twl6040_codec_remove(struct platform_device *pdev) 1683static int __devexit twl6040_codec_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index 23aeed0963e6..d8de67869dd9 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -22,125 +22,8 @@
22#ifndef __TWL6040_H__ 22#ifndef __TWL6040_H__
23#define __TWL6040_H__ 23#define __TWL6040_H__
24 24
25#define TWL6040_REG_ASICID 0x01
26#define TWL6040_REG_ASICREV 0x02
27#define TWL6040_REG_INTID 0x03
28#define TWL6040_REG_INTMR 0x04
29#define TWL6040_REG_NCPCTL 0x05
30#define TWL6040_REG_LDOCTL 0x06
31#define TWL6040_REG_HPPLLCTL 0x07
32#define TWL6040_REG_LPPLLCTL 0x08
33#define TWL6040_REG_LPPLLDIV 0x09
34#define TWL6040_REG_AMICBCTL 0x0A
35#define TWL6040_REG_DMICBCTL 0x0B
36#define TWL6040_REG_MICLCTL 0x0C
37#define TWL6040_REG_MICRCTL 0x0D
38#define TWL6040_REG_MICGAIN 0x0E
39#define TWL6040_REG_LINEGAIN 0x0F
40#define TWL6040_REG_HSLCTL 0x10
41#define TWL6040_REG_HSRCTL 0x11
42#define TWL6040_REG_HSGAIN 0x12
43#define TWL6040_REG_EARCTL 0x13
44#define TWL6040_REG_HFLCTL 0x14
45#define TWL6040_REG_HFLGAIN 0x15
46#define TWL6040_REG_HFRCTL 0x16
47#define TWL6040_REG_HFRGAIN 0x17
48#define TWL6040_REG_VIBCTLL 0x18
49#define TWL6040_REG_VIBDATL 0x19
50#define TWL6040_REG_VIBCTLR 0x1A
51#define TWL6040_REG_VIBDATR 0x1B
52#define TWL6040_REG_HKCTL1 0x1C
53#define TWL6040_REG_HKCTL2 0x1D
54#define TWL6040_REG_GPOCTL 0x1E
55#define TWL6040_REG_ALB 0x1F
56#define TWL6040_REG_DLB 0x20
57#define TWL6040_REG_TRIM1 0x28
58#define TWL6040_REG_TRIM2 0x29
59#define TWL6040_REG_TRIM3 0x2A
60#define TWL6040_REG_HSOTRIM 0x2B
61#define TWL6040_REG_HFOTRIM 0x2C
62#define TWL6040_REG_ACCCTL 0x2D
63#define TWL6040_REG_STATUS 0x2E
64
65#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
66
67#define TWL6040_VIOREGNUM 18
68#define TWL6040_VDDREGNUM 21
69
70/* INTID (0x03) fields */
71
72#define TWL6040_THINT 0x01
73#define TWL6040_PLUGINT 0x02
74#define TWL6040_UNPLUGINT 0x04
75#define TWL6040_HOOKINT 0x08
76#define TWL6040_HFINT 0x10
77#define TWL6040_VIBINT 0x20
78#define TWL6040_READYINT 0x40
79
80/* INTMR (0x04) fields */
81
82#define TWL6040_PLUGMSK 0x02
83#define TWL6040_READYMSK 0x40
84#define TWL6040_ALLINT_MSK 0x7B
85
86/* NCPCTL (0x05) fields */
87
88#define TWL6040_NCPENA 0x01
89#define TWL6040_NCPOPEN 0x40
90
91/* LDOCTL (0x06) fields */
92
93#define TWL6040_LSLDOENA 0x01
94#define TWL6040_HSLDOENA 0x04
95#define TWL6040_REFENA 0x40
96#define TWL6040_OSCENA 0x80
97
98/* HPPLLCTL (0x07) fields */
99
100#define TWL6040_HPLLENA 0x01
101#define TWL6040_HPLLRST 0x02
102#define TWL6040_HPLLBP 0x04
103#define TWL6040_HPLLSQRENA 0x08
104#define TWL6040_HPLLSQRBP 0x10
105#define TWL6040_MCLK_12000KHZ (0 << 5)
106#define TWL6040_MCLK_19200KHZ (1 << 5)
107#define TWL6040_MCLK_26000KHZ (2 << 5)
108#define TWL6040_MCLK_38400KHZ (3 << 5)
109#define TWL6040_MCLK_MSK 0x60
110
111/* LPPLLCTL (0x08) fields */
112
113#define TWL6040_LPLLENA 0x01
114#define TWL6040_LPLLRST 0x02
115#define TWL6040_LPLLSEL 0x04
116#define TWL6040_LPLLFIN 0x08
117#define TWL6040_HPLLSEL 0x10
118
119/* HSLCTL (0x10) fields */
120
121#define TWL6040_HSDACMODEL 0x02
122#define TWL6040_HSDRVMODEL 0x08
123
124/* HSRCTL (0x11) fields */
125
126#define TWL6040_HSDACMODER 0x02
127#define TWL6040_HSDRVMODER 0x08
128
129/* ACCCTL (0x2D) fields */
130
131#define TWL6040_RESETSPLIT 0x04
132
133#define TWL6040_SYSCLK_SEL_LPPLL 1
134#define TWL6040_SYSCLK_SEL_HPPLL 2
135
136#define TWL6040_HPPLL_ID 1
137#define TWL6040_LPPLL_ID 2
138
139/* STATUS (0x2E) fields */
140
141#define TWL6040_PLUGCOMP 0x02
142
143void twl6040_hs_jack_detect(struct snd_soc_codec *codec, 25void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
144 struct snd_soc_jack *jack, int report); 26 struct snd_soc_jack *jack, int report);
27int twl6040_get_clk_id(struct snd_soc_codec *codec);
145 28
146#endif /* End of __TWL6040_H__ */ 29#endif /* End of __TWL6040_H__ */
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 3f72d17d1ef0..9f6a758029d1 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -36,7 +36,7 @@
36#include <plat/mcbsp.h> 36#include <plat/mcbsp.h>
37 37
38/* Register descriptions for twl4030 codec part */ 38/* Register descriptions for twl4030 codec part */
39#include <linux/mfd/twl4030-codec.h> 39#include <linux/mfd/twl4030-audio.h>
40 40
41#include "omap-mcbsp.h" 41#include "omap-mcbsp.h"
42#include "omap-pcm.h" 42#include "omap-pcm.h"
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 189e03900637..b80efb02bfca 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -21,6 +21,8 @@
21 21
22#include <linux/clk.h> 22#include <linux/clk.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/mfd/twl6040.h>
25
24#include <sound/core.h> 26#include <sound/core.h>
25#include <sound/pcm.h> 27#include <sound/pcm.h>
26#include <sound/soc.h> 28#include <sound/soc.h>
@@ -34,8 +36,6 @@
34#include "omap-pcm.h" 36#include "omap-pcm.h"
35#include "../codecs/twl6040.h" 37#include "../codecs/twl6040.h"
36 38
37static int twl6040_power_mode;
38
39static int sdp4430_hw_params(struct snd_pcm_substream *substream, 39static int sdp4430_hw_params(struct snd_pcm_substream *substream,
40 struct snd_pcm_hw_params *params) 40 struct snd_pcm_hw_params *params)
41{ 41{
@@ -44,13 +44,13 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
44 int clk_id, freq; 44 int clk_id, freq;
45 int ret; 45 int ret;
46 46
47 if (twl6040_power_mode) { 47 clk_id = twl6040_get_clk_id(rtd->codec);
48 clk_id = TWL6040_SYSCLK_SEL_HPPLL; 48 if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
49 freq = 38400000; 49 freq = 38400000;
50 } else { 50 else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
51 clk_id = TWL6040_SYSCLK_SEL_LPPLL;
52 freq = 32768; 51 freq = 32768;
53 } 52 else
53 return -EINVAL;
54 54
55 /* set the codec mclk */ 55 /* set the codec mclk */
56 ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq, 56 ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
@@ -81,35 +81,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
81 }, 81 },
82}; 82};
83 83
84static int sdp4430_get_power_mode(struct snd_kcontrol *kcontrol,
85 struct snd_ctl_elem_value *ucontrol)
86{
87 ucontrol->value.integer.value[0] = twl6040_power_mode;
88 return 0;
89}
90
91static int sdp4430_set_power_mode(struct snd_kcontrol *kcontrol,
92 struct snd_ctl_elem_value *ucontrol)
93{
94 if (twl6040_power_mode == ucontrol->value.integer.value[0])
95 return 0;
96
97 twl6040_power_mode = ucontrol->value.integer.value[0];
98
99 return 1;
100}
101
102static const char *power_texts[] = {"Low-Power", "High-Performance"};
103
104static const struct soc_enum sdp4430_enum[] = {
105 SOC_ENUM_SINGLE_EXT(2, power_texts),
106};
107
108static const struct snd_kcontrol_new sdp4430_controls[] = {
109 SOC_ENUM_EXT("TWL6040 Power Mode", sdp4430_enum[0],
110 sdp4430_get_power_mode, sdp4430_set_power_mode),
111};
112
113/* SDP4430 machine DAPM */ 84/* SDP4430 machine DAPM */
114static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = { 85static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
115 SND_SOC_DAPM_MIC("Ext Mic", NULL), 86 SND_SOC_DAPM_MIC("Ext Mic", NULL),
@@ -152,12 +123,6 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
152 struct snd_soc_dapm_context *dapm = &codec->dapm; 123 struct snd_soc_dapm_context *dapm = &codec->dapm;
153 int ret; 124 int ret;
154 125
155 /* Add SDP4430 specific controls */
156 ret = snd_soc_add_controls(codec, sdp4430_controls,
157 ARRAY_SIZE(sdp4430_controls));
158 if (ret)
159 return ret;
160
161 /* Add SDP4430 specific widgets */ 126 /* Add SDP4430 specific widgets */
162 ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets, 127 ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
163 ARRAY_SIZE(sdp4430_twl6040_dapm_widgets)); 128 ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
@@ -237,9 +202,6 @@ static int __init sdp4430_soc_init(void)
237 if (ret) 202 if (ret)
238 goto err; 203 goto err;
239 204
240 /* Codec starts in HP mode */
241 twl6040_power_mode = 1;
242
243 return 0; 205 return 0;
244 206
245err: 207err:
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 01709940a43c..9a2666ffc16c 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -32,7 +32,7 @@
32#include <plat/mcbsp.h> 32#include <plat/mcbsp.h>
33 33
34/* Register descriptions for twl4030 codec part */ 34/* Register descriptions for twl4030 codec part */
35#include <linux/mfd/twl4030-codec.h> 35#include <linux/mfd/twl4030-audio.h>
36 36
37#include "omap-mcbsp.h" 37#include "omap-mcbsp.h"
38#include "omap-pcm.h" 38#include "omap-pcm.h"