aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl6040.c
diff options
context:
space:
mode:
authorMargarita Olaya Cabrera <magi.olaya@ti.com>2010-12-14 20:00:21 -0500
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-12-16 07:02:34 -0500
commit1bf84759bdcc08933b22ee70722f1575ad84f9b9 (patch)
tree9e8f77eb84b19d05b2b1e70f16ac25753548c6b8 /sound/soc/codecs/twl6040.c
parent65b7cecc85b9bb7bb8ce74c6a3b280464b00c86c (diff)
ASoC: twl6040: Add ramp up/down volume for HS and HF
Add ramp functions for the headset and handsfree outputs in order to reduce the pops during power on/off sequences. In order to give more control to volume ramp, step size and delay between steps can be specified. The patches are based on wm8350 implementation from Liam Girdwood. Signed-off-by: Margarita Olaya Cabrera <magi.olaya@ti.com> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/twl6040.c')
-rw-r--r--sound/soc/codecs/twl6040.c533
1 files changed, 521 insertions, 12 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index b252cf8f0ce1..2f68f5949a63 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -40,7 +40,35 @@
40#include "twl6040.h" 40#include "twl6040.h"
41 41
42#define TWL6040_RATES SNDRV_PCM_RATE_8000_96000 42#define TWL6040_RATES SNDRV_PCM_RATE_8000_96000
43#define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) 43#define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
44
45#define TWL6040_OUTHS_0dB 0x00
46#define TWL6040_OUTHS_M30dB 0x0F
47#define TWL6040_OUTHF_0dB 0x03
48#define TWL6040_OUTHF_M52dB 0x1D
49
50#define TWL6040_RAMP_NONE 0
51#define TWL6040_RAMP_UP 1
52#define TWL6040_RAMP_DOWN 2
53
54#define TWL6040_HSL_VOL_MASK 0x0F
55#define TWL6040_HSL_VOL_SHIFT 0
56#define TWL6040_HSR_VOL_MASK 0xF0
57#define TWL6040_HSR_VOL_SHIFT 4
58#define TWL6040_HF_VOL_MASK 0x1F
59#define TWL6040_HF_VOL_SHIFT 0
60
61struct twl6040_output {
62 u16 active;
63 u16 left_vol;
64 u16 right_vol;
65 u16 left_step;
66 u16 right_step;
67 unsigned int step_delay;
68 u16 ramp;
69 u16 mute;
70 struct completion ramp_done;
71};
44 72
45struct twl6040_jack_data { 73struct twl6040_jack_data {
46 struct snd_soc_jack *jack; 74 struct snd_soc_jack *jack;
@@ -62,6 +90,12 @@ struct twl6040_data {
62 struct workqueue_struct *workqueue; 90 struct workqueue_struct *workqueue;
63 struct delayed_work delayed_work; 91 struct delayed_work delayed_work;
64 struct mutex mutex; 92 struct mutex mutex;
93 struct twl6040_output headset;
94 struct twl6040_output handsfree;
95 struct workqueue_struct *hf_workqueue;
96 struct workqueue_struct *hs_workqueue;
97 struct delayed_work hs_delayed_work;
98 struct delayed_work hf_delayed_work;
65}; 99};
66 100
67/* 101/*
@@ -263,6 +297,305 @@ static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
263 } 297 }
264} 298}
265 299
300/*
301 * Ramp HS PGA volume to minimise pops at stream startup and shutdown.
302 */
303static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
304 unsigned int left_step, unsigned int right_step)
305{
306
307 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
308 struct twl6040_output *headset = &priv->headset;
309 int left_complete = 0, right_complete = 0;
310 u8 reg, val;
311
312 /* left channel */
313 left_step = (left_step > 0xF) ? 0xF : left_step;
314 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
315 val = (~reg & TWL6040_HSL_VOL_MASK);
316
317 if (headset->ramp == TWL6040_RAMP_UP) {
318 /* ramp step up */
319 if (val < headset->left_vol) {
320 val += left_step;
321 reg &= ~TWL6040_HSL_VOL_MASK;
322 twl6040_write(codec, TWL6040_REG_HSGAIN,
323 (reg | (~val & TWL6040_HSL_VOL_MASK)));
324 } else {
325 left_complete = 1;
326 }
327 } else if (headset->ramp == TWL6040_RAMP_DOWN) {
328 /* ramp step down */
329 if (val > 0x0) {
330 val -= left_step;
331 reg &= ~TWL6040_HSL_VOL_MASK;
332 twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
333 (~val & TWL6040_HSL_VOL_MASK));
334 } else {
335 left_complete = 1;
336 }
337 }
338
339 /* right channel */
340 right_step = (right_step > 0xF) ? 0xF : right_step;
341 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
342 val = (~reg & TWL6040_HSR_VOL_MASK) >> TWL6040_HSR_VOL_SHIFT;
343
344 if (headset->ramp == TWL6040_RAMP_UP) {
345 /* ramp step up */
346 if (val < headset->right_vol) {
347 val += right_step;
348 reg &= ~TWL6040_HSR_VOL_MASK;
349 twl6040_write(codec, TWL6040_REG_HSGAIN,
350 (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
351 } else {
352 right_complete = 1;
353 }
354 } else if (headset->ramp == TWL6040_RAMP_DOWN) {
355 /* ramp step down */
356 if (val > 0x0) {
357 val -= right_step;
358 reg &= ~TWL6040_HSR_VOL_MASK;
359 twl6040_write(codec, TWL6040_REG_HSGAIN,
360 reg | (~val << TWL6040_HSR_VOL_SHIFT));
361 } else {
362 right_complete = 1;
363 }
364 }
365
366 return left_complete & right_complete;
367}
368
369/*
370 * Ramp HF PGA volume to minimise pops at stream startup and shutdown.
371 */
372static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
373 unsigned int left_step, unsigned int right_step)
374{
375 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
376 struct twl6040_output *handsfree = &priv->handsfree;
377 int left_complete = 0, right_complete = 0;
378 u16 reg, val;
379
380 /* left channel */
381 left_step = (left_step > 0x1D) ? 0x1D : left_step;
382 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
383 reg = 0x1D - reg;
384 val = (reg & TWL6040_HF_VOL_MASK);
385 if (handsfree->ramp == TWL6040_RAMP_UP) {
386 /* ramp step up */
387 if (val < handsfree->left_vol) {
388 val += left_step;
389 reg &= ~TWL6040_HF_VOL_MASK;
390 twl6040_write(codec, TWL6040_REG_HFLGAIN,
391 reg | (0x1D - val));
392 } else {
393 left_complete = 1;
394 }
395 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
396 /* ramp step down */
397 if (val > 0) {
398 val -= left_step;
399 reg &= ~TWL6040_HF_VOL_MASK;
400 twl6040_write(codec, TWL6040_REG_HFLGAIN,
401 reg | (0x1D - val));
402 } else {
403 left_complete = 1;
404 }
405 }
406
407 /* right channel */
408 right_step = (right_step > 0x1D) ? 0x1D : right_step;
409 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
410 reg = 0x1D - reg;
411 val = (reg & TWL6040_HF_VOL_MASK);
412 if (handsfree->ramp == TWL6040_RAMP_UP) {
413 /* ramp step up */
414 if (val < handsfree->right_vol) {
415 val += right_step;
416 reg &= ~TWL6040_HF_VOL_MASK;
417 twl6040_write(codec, TWL6040_REG_HFRGAIN,
418 reg | (0x1D - val));
419 } else {
420 right_complete = 1;
421 }
422 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
423 /* ramp step down */
424 if (val > 0) {
425 val -= right_step;
426 reg &= ~TWL6040_HF_VOL_MASK;
427 twl6040_write(codec, TWL6040_REG_HFRGAIN,
428 reg | (0x1D - val));
429 }
430 }
431
432 return left_complete & right_complete;
433}
434
435/*
436 * This work ramps both output PGAs at stream start/stop time to
437 * minimise pop associated with DAPM power switching.
438 */
439static void twl6040_pga_hs_work(struct work_struct *work)
440{
441 struct twl6040_data *priv =
442 container_of(work, struct twl6040_data, hs_delayed_work.work);
443 struct snd_soc_codec *codec = priv->codec;
444 struct twl6040_output *headset = &priv->headset;
445 unsigned int delay = headset->step_delay;
446 int i, headset_complete;
447
448 /* do we need to ramp at all ? */
449 if (headset->ramp == TWL6040_RAMP_NONE)
450 return;
451
452 /* HS PGA volumes have 4 bits of resolution to ramp */
453 for (i = 0; i <= 16; i++) {
454 headset_complete = 1;
455 if (headset->ramp != TWL6040_RAMP_NONE)
456 headset_complete = twl6040_hs_ramp_step(codec,
457 headset->left_step,
458 headset->right_step);
459
460 /* ramp finished ? */
461 if (headset_complete)
462 break;
463
464 /*
465 * TODO: tune: delay is longer over 0dB
466 * as increases are larger.
467 */
468 if (i >= 8)
469 schedule_timeout_interruptible(msecs_to_jiffies(delay +
470 (delay >> 1)));
471 else
472 schedule_timeout_interruptible(msecs_to_jiffies(delay));
473 }
474
475 if (headset->ramp == TWL6040_RAMP_DOWN) {
476 headset->active = 0;
477 complete(&headset->ramp_done);
478 } else {
479 headset->active = 1;
480 }
481 headset->ramp = TWL6040_RAMP_NONE;
482}
483
484static void twl6040_pga_hf_work(struct work_struct *work)
485{
486 struct twl6040_data *priv =
487 container_of(work, struct twl6040_data, hf_delayed_work.work);
488 struct snd_soc_codec *codec = priv->codec;
489 struct twl6040_output *handsfree = &priv->handsfree;
490 unsigned int delay = handsfree->step_delay;
491 int i, handsfree_complete;
492
493 /* do we need to ramp at all ? */
494 if (handsfree->ramp == TWL6040_RAMP_NONE)
495 return;
496
497 /* HF PGA volumes have 5 bits of resolution to ramp */
498 for (i = 0; i <= 32; i++) {
499 handsfree_complete = 1;
500 if (handsfree->ramp != TWL6040_RAMP_NONE)
501 handsfree_complete = twl6040_hf_ramp_step(codec,
502 handsfree->left_step,
503 handsfree->right_step);
504
505 /* ramp finished ? */
506 if (handsfree_complete)
507 break;
508
509 /*
510 * TODO: tune: delay is longer over 0dB
511 * as increases are larger.
512 */
513 if (i >= 16)
514 schedule_timeout_interruptible(msecs_to_jiffies(delay +
515 (delay >> 1)));
516 else
517 schedule_timeout_interruptible(msecs_to_jiffies(delay));
518 }
519
520
521 if (handsfree->ramp == TWL6040_RAMP_DOWN) {
522 handsfree->active = 0;
523 complete(&handsfree->ramp_done);
524 } else
525 handsfree->active = 1;
526 handsfree->ramp = TWL6040_RAMP_NONE;
527}
528
529static int pga_event(struct snd_soc_dapm_widget *w,
530 struct snd_kcontrol *kcontrol, int event)
531{
532 struct snd_soc_codec *codec = w->codec;
533 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
534 struct twl6040_output *out;
535 struct delayed_work *work;
536 struct workqueue_struct *queue;
537
538 switch (w->shift) {
539 case 2:
540 case 3:
541 out = &priv->headset;
542 work = &priv->hs_delayed_work;
543 queue = priv->hs_workqueue;
544 out->step_delay = 5; /* 5 ms between volume ramp steps */
545 break;
546 case 4:
547 out = &priv->handsfree;
548 work = &priv->hf_delayed_work;
549 queue = priv->hf_workqueue;
550 out->step_delay = 5; /* 5 ms between volume ramp steps */
551 if (SND_SOC_DAPM_EVENT_ON(event))
552 priv->non_lp++;
553 else
554 priv->non_lp--;
555 break;
556 default:
557 return -1;
558 }
559
560 switch (event) {
561 case SND_SOC_DAPM_POST_PMU:
562 if (out->active)
563 break;
564
565 /* don't use volume ramp for power-up */
566 out->left_step = out->left_vol;
567 out->right_step = out->right_vol;
568
569 if (!delayed_work_pending(work)) {
570 out->ramp = TWL6040_RAMP_UP;
571 queue_delayed_work(queue, work,
572 msecs_to_jiffies(1));
573 }
574 break;
575
576 case SND_SOC_DAPM_PRE_PMD:
577 if (!out->active)
578 break;
579
580 if (!delayed_work_pending(work)) {
581 /* use volume ramp for power-down */
582 out->left_step = 1;
583 out->right_step = 1;
584 out->ramp = TWL6040_RAMP_DOWN;
585 INIT_COMPLETION(out->ramp_done);
586
587 queue_delayed_work(queue, work,
588 msecs_to_jiffies(1));
589
590 wait_for_completion_timeout(&out->ramp_done,
591 msecs_to_jiffies(2000));
592 }
593 break;
594 }
595
596 return 0;
597}
598
266/* twl6040 codec manual power-up sequence */ 599/* twl6040 codec manual power-up sequence */
267static void twl6040_power_up(struct snd_soc_codec *codec) 600static void twl6040_power_up(struct snd_soc_codec *codec)
268{ 601{
@@ -463,6 +796,156 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data)
463 return IRQ_HANDLED; 796 return IRQ_HANDLED;
464} 797}
465 798
799static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
800 struct snd_ctl_elem_value *ucontrol)
801{
802 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
803 struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
804 struct twl6040_output *out = NULL;
805 struct soc_mixer_control *mc =
806 (struct soc_mixer_control *)kcontrol->private_value;
807 int ret;
808 unsigned int reg = mc->reg;
809
810 /* For HS and HF we shadow the values and only actually write
811 * them out when active in order to ensure the amplifier comes on
812 * as quietly as possible. */
813 switch (reg) {
814 case TWL6040_REG_HSGAIN:
815 out = &twl6040_priv->headset;
816 break;
817 default:
818 break;
819 }
820
821 if (out) {
822 out->left_vol = ucontrol->value.integer.value[0];
823 out->right_vol = ucontrol->value.integer.value[1];
824 if (!out->active)
825 return 1;
826 }
827
828 ret = snd_soc_put_volsw(kcontrol, ucontrol);
829 if (ret < 0)
830 return ret;
831
832 return 1;
833}
834
835static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
836 struct snd_ctl_elem_value *ucontrol)
837{
838 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
839 struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
840 struct twl6040_output *out = &twl6040_priv->headset;
841 struct soc_mixer_control *mc =
842 (struct soc_mixer_control *)kcontrol->private_value;
843 unsigned int reg = mc->reg;
844
845 switch (reg) {
846 case TWL6040_REG_HSGAIN:
847 out = &twl6040_priv->headset;
848 ucontrol->value.integer.value[0] = out->left_vol;
849 ucontrol->value.integer.value[1] = out->right_vol;
850 return 0;
851
852 default:
853 break;
854 }
855
856 return snd_soc_get_volsw(kcontrol, ucontrol);
857}
858
859static int twl6040_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
860 struct snd_ctl_elem_value *ucontrol)
861{
862 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
863 struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
864 struct twl6040_output *out = NULL;
865 struct soc_mixer_control *mc =
866 (struct soc_mixer_control *)kcontrol->private_value;
867 int ret;
868 unsigned int reg = mc->reg;
869
870 /* For HS and HF we shadow the values and only actually write
871 * them out when active in order to ensure the amplifier comes on
872 * as quietly as possible. */
873 switch (reg) {
874 case TWL6040_REG_HFLGAIN:
875 case TWL6040_REG_HFRGAIN:
876 out = &twl6040_priv->handsfree;
877 break;
878 default:
879 break;
880 }
881
882 if (out) {
883 out->left_vol = ucontrol->value.integer.value[0];
884 out->right_vol = ucontrol->value.integer.value[1];
885 if (!out->active)
886 return 1;
887 }
888
889 ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
890 if (ret < 0)
891 return ret;
892
893 return 1;
894}
895
896static int twl6040_get_volsw_2r(struct snd_kcontrol *kcontrol,
897 struct snd_ctl_elem_value *ucontrol)
898{
899 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
900 struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
901 struct twl6040_output *out = &twl6040_priv->handsfree;
902 struct soc_mixer_control *mc =
903 (struct soc_mixer_control *)kcontrol->private_value;
904 unsigned int reg = mc->reg;
905
906 /* If these are cached registers use the cache */
907 switch (reg) {
908 case TWL6040_REG_HFLGAIN:
909 case TWL6040_REG_HFRGAIN:
910 out = &twl6040_priv->handsfree;
911 ucontrol->value.integer.value[0] = out->left_vol;
912 ucontrol->value.integer.value[1] = out->right_vol;
913 return 0;
914
915 default:
916 break;
917 }
918
919 return snd_soc_get_volsw_2r(kcontrol, ucontrol);
920}
921
922/* double control with volume update */
923#define SOC_TWL6040_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax,\
924 xinvert, tlv_array)\
925{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
926 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
927 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
928 .tlv.p = (tlv_array), \
929 .info = snd_soc_info_volsw, .get = twl6040_get_volsw, \
930 .put = twl6040_put_volsw, \
931 .private_value = (unsigned long)&(struct soc_mixer_control) \
932 {.reg = xreg, .shift = shift_left, .rshift = shift_right,\
933 .max = xmax, .platform_max = xmax, .invert = xinvert} }
934
935/* double control with volume update */
936#define SOC_TWL6040_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax,\
937 xinvert, tlv_array)\
938{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
939 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
940 SNDRV_CTL_ELEM_ACCESS_READWRITE | \
941 SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
942 .tlv.p = (tlv_array), \
943 .info = snd_soc_info_volsw_2r, \
944 .get = twl6040_get_volsw_2r, .put = twl6040_put_volsw_2r_vu, \
945 .private_value = (unsigned long)&(struct soc_mixer_control) \
946 {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
947 .rshift = xshift, .max = xmax, .invert = xinvert}, }
948
466/* 949/*
467 * MICATT volume control: 950 * MICATT volume control:
468 * from -6 to 0 dB in 6 dB steps 951 * from -6 to 0 dB in 6 dB steps
@@ -569,9 +1052,9 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
569 TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv), 1052 TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv),
570 1053
571 /* Playback gains */ 1054 /* Playback gains */
572 SOC_DOUBLE_TLV("Headset Playback Volume", 1055 SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
573 TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv), 1056 TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
574 SOC_DOUBLE_R_TLV("Handsfree Playback Volume", 1057 SOC_TWL6040_DOUBLE_R_TLV("Handsfree Playback Volume",
575 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv), 1058 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
576 SOC_SINGLE_TLV("Earphone Playback Volume", 1059 SOC_SINGLE_TLV("Earphone Playback Volume",
577 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv), 1060 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
@@ -657,16 +1140,20 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
657 /* Analog playback drivers */ 1140 /* Analog playback drivers */
658 SND_SOC_DAPM_PGA_E("Handsfree Left Driver", 1141 SND_SOC_DAPM_PGA_E("Handsfree Left Driver",
659 TWL6040_REG_HFLCTL, 4, 0, NULL, 0, 1142 TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
660 twl6040_power_mode_event, 1143 pga_event,
661 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 1144 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
662 SND_SOC_DAPM_PGA_E("Handsfree Right Driver", 1145 SND_SOC_DAPM_PGA_E("Handsfree Right Driver",
663 TWL6040_REG_HFRCTL, 4, 0, NULL, 0, 1146 TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
664 twl6040_power_mode_event, 1147 pga_event,
665 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 1148 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
666 SND_SOC_DAPM_PGA("Headset Left Driver", 1149 SND_SOC_DAPM_PGA_E("Headset Left Driver",
667 TWL6040_REG_HSLCTL, 2, 0, NULL, 0), 1150 TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
668 SND_SOC_DAPM_PGA("Headset Right Driver", 1151 pga_event,
669 TWL6040_REG_HSRCTL, 2, 0, NULL, 0), 1152 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1153 SND_SOC_DAPM_PGA_E("Headset Right Driver",
1154 TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
1155 pga_event,
1156 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
670 SND_SOC_DAPM_SWITCH_E("Earphone Driver", 1157 SND_SOC_DAPM_SWITCH_E("Earphone Driver",
671 SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, 1158 SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls,
672 twl6040_power_mode_event, 1159 twl6040_power_mode_event,
@@ -1150,6 +1637,8 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1150 mutex_init(&priv->mutex); 1637 mutex_init(&priv->mutex);
1151 1638
1152 init_completion(&priv->ready); 1639 init_completion(&priv->ready);
1640 init_completion(&priv->headset.ramp_done);
1641 init_completion(&priv->handsfree.ramp_done);
1153 1642
1154 if (gpio_is_valid(audpwron)) { 1643 if (gpio_is_valid(audpwron)) {
1155 ret = gpio_request(audpwron, "audpwron"); 1644 ret = gpio_request(audpwron, "audpwron");
@@ -1183,10 +1672,24 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1183 /* init vio registers */ 1672 /* init vio registers */
1184 twl6040_init_vio_regs(codec); 1673 twl6040_init_vio_regs(codec);
1185 1674
1675 priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
1676 if (priv->hf_workqueue == NULL) {
1677 ret = -ENOMEM;
1678 goto irq_err;
1679 }
1680 priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
1681 if (priv->hs_workqueue == NULL) {
1682 ret = -ENOMEM;
1683 goto wq_err;
1684 }
1685
1686 INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
1687 INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
1688
1186 /* power on device */ 1689 /* power on device */
1187 ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1690 ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1188 if (ret) 1691 if (ret)
1189 goto irq_err; 1692 goto bias_err;
1190 1693
1191 snd_soc_add_controls(codec, twl6040_snd_controls, 1694 snd_soc_add_controls(codec, twl6040_snd_controls,
1192 ARRAY_SIZE(twl6040_snd_controls)); 1695 ARRAY_SIZE(twl6040_snd_controls));
@@ -1194,6 +1697,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1194 1697
1195 return 0; 1698 return 0;
1196 1699
1700bias_err:
1701 destroy_workqueue(priv->hs_workqueue);
1702wq_err:
1703 destroy_workqueue(priv->hf_workqueue);
1197irq_err: 1704irq_err:
1198 if (naudint) 1705 if (naudint)
1199 free_irq(naudint, codec); 1706 free_irq(naudint, codec);
@@ -1222,6 +1729,8 @@ static int twl6040_remove(struct snd_soc_codec *codec)
1222 free_irq(naudint, codec); 1729 free_irq(naudint, codec);
1223 1730
1224 destroy_workqueue(priv->workqueue); 1731 destroy_workqueue(priv->workqueue);
1732 destroy_workqueue(priv->hf_workqueue);
1733 destroy_workqueue(priv->hs_workqueue);
1225 kfree(priv); 1734 kfree(priv);
1226 1735
1227 return 0; 1736 return 0;