aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl6040.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2012-05-04 08:17:20 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-05-07 13:27:36 -0400
commit3bb8a819c6995478f5e76d62726caae92d3123b4 (patch)
tree9a3e5c7820582583295d20d4be845ee5ad68c304 /sound/soc/codecs/twl6040.c
parentd93ca1ae61adf67104a78739b793b27a7886c489 (diff)
ASoC: twl6040: Remove HS/HF gain ramp feature
None of the machines uses the gain ramp possibility for HS/HF. This code path is mostly unused and it does not reduces the pop noise on the output (it alters it to sound a bit different). The preferred method to reduce pop noise is to use ABE. Remove the gain ramp, and related features form the driver. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/twl6040.c')
-rw-r--r--sound/soc/codecs/twl6040.c441
1 files changed, 12 insertions, 429 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index ccbc88aa8497..d3807a354941 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -47,17 +47,6 @@
47#define TWL6040_OUTHF_0dB 0x03 47#define TWL6040_OUTHF_0dB 0x03
48#define TWL6040_OUTHF_M52dB 0x1D 48#define TWL6040_OUTHF_M52dB 0x1D
49 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
61/* Shadow register used by the driver */ 50/* Shadow register used by the driver */
62#define TWL6040_REG_SW_SHADOW 0x2F 51#define TWL6040_REG_SW_SHADOW 0x2F
63#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1) 52#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
@@ -65,18 +54,6 @@
65/* TWL6040_REG_SW_SHADOW (0x2F) fields */ 54/* TWL6040_REG_SW_SHADOW (0x2F) fields */
66#define TWL6040_EAR_PATH_ENABLE 0x01 55#define TWL6040_EAR_PATH_ENABLE 0x01
67 56
68struct twl6040_output {
69 u16 active;
70 u16 left_vol;
71 u16 right_vol;
72 u16 left_step;
73 u16 right_step;
74 unsigned int step_delay;
75 u16 ramp;
76 struct delayed_work work;
77 struct completion ramp_done;
78};
79
80struct twl6040_jack_data { 57struct twl6040_jack_data {
81 struct snd_soc_jack *jack; 58 struct snd_soc_jack *jack;
82 struct delayed_work work; 59 struct delayed_work work;
@@ -101,8 +78,6 @@ struct twl6040_data {
101 struct snd_soc_codec *codec; 78 struct snd_soc_codec *codec;
102 struct workqueue_struct *workqueue; 79 struct workqueue_struct *workqueue;
103 struct mutex mutex; 80 struct mutex mutex;
104 struct twl6040_output headset;
105 struct twl6040_output handsfree;
106}; 81};
107 82
108/* 83/*
@@ -312,318 +287,6 @@ static void twl6040_restore_regs(struct snd_soc_codec *codec)
312 } 287 }
313} 288}
314 289
315/*
316 * Ramp HS PGA volume to minimise pops at stream startup and shutdown.
317 */
318static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
319 unsigned int left_step, unsigned int right_step)
320{
321
322 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
323 struct twl6040_output *headset = &priv->headset;
324 int left_complete = 0, right_complete = 0;
325 u8 reg, val;
326
327 /* left channel */
328 left_step = (left_step > 0xF) ? 0xF : left_step;
329 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
330 val = (~reg & TWL6040_HSL_VOL_MASK);
331
332 if (headset->ramp == TWL6040_RAMP_UP) {
333 /* ramp step up */
334 if (val < headset->left_vol) {
335 if (val + left_step > headset->left_vol)
336 val = headset->left_vol;
337 else
338 val += left_step;
339
340 reg &= ~TWL6040_HSL_VOL_MASK;
341 twl6040_write(codec, TWL6040_REG_HSGAIN,
342 (reg | (~val & TWL6040_HSL_VOL_MASK)));
343 } else {
344 left_complete = 1;
345 }
346 } else if (headset->ramp == TWL6040_RAMP_DOWN) {
347 /* ramp step down */
348 if (val > 0x0) {
349 if ((int)val - (int)left_step < 0)
350 val = 0;
351 else
352 val -= left_step;
353
354 reg &= ~TWL6040_HSL_VOL_MASK;
355 twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
356 (~val & TWL6040_HSL_VOL_MASK));
357 } else {
358 left_complete = 1;
359 }
360 }
361
362 /* right channel */
363 right_step = (right_step > 0xF) ? 0xF : right_step;
364 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
365 val = (~reg & TWL6040_HSR_VOL_MASK) >> TWL6040_HSR_VOL_SHIFT;
366
367 if (headset->ramp == TWL6040_RAMP_UP) {
368 /* ramp step up */
369 if (val < headset->right_vol) {
370 if (val + right_step > headset->right_vol)
371 val = headset->right_vol;
372 else
373 val += right_step;
374
375 reg &= ~TWL6040_HSR_VOL_MASK;
376 twl6040_write(codec, TWL6040_REG_HSGAIN,
377 (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
378 } else {
379 right_complete = 1;
380 }
381 } else if (headset->ramp == TWL6040_RAMP_DOWN) {
382 /* ramp step down */
383 if (val > 0x0) {
384 if ((int)val - (int)right_step < 0)
385 val = 0;
386 else
387 val -= right_step;
388
389 reg &= ~TWL6040_HSR_VOL_MASK;
390 twl6040_write(codec, TWL6040_REG_HSGAIN,
391 reg | (~val << TWL6040_HSR_VOL_SHIFT));
392 } else {
393 right_complete = 1;
394 }
395 }
396
397 return left_complete & right_complete;
398}
399
400/*
401 * Ramp HF PGA volume to minimise pops at stream startup and shutdown.
402 */
403static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
404 unsigned int left_step, unsigned int right_step)
405{
406 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
407 struct twl6040_output *handsfree = &priv->handsfree;
408 int left_complete = 0, right_complete = 0;
409 u16 reg, val;
410
411 /* left channel */
412 left_step = (left_step > 0x1D) ? 0x1D : left_step;
413 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
414 reg = 0x1D - reg;
415 val = (reg & TWL6040_HF_VOL_MASK);
416 if (handsfree->ramp == TWL6040_RAMP_UP) {
417 /* ramp step up */
418 if (val < handsfree->left_vol) {
419 if (val + left_step > handsfree->left_vol)
420 val = handsfree->left_vol;
421 else
422 val += left_step;
423
424 reg &= ~TWL6040_HF_VOL_MASK;
425 twl6040_write(codec, TWL6040_REG_HFLGAIN,
426 reg | (0x1D - val));
427 } else {
428 left_complete = 1;
429 }
430 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
431 /* ramp step down */
432 if (val > 0) {
433 if ((int)val - (int)left_step < 0)
434 val = 0;
435 else
436 val -= left_step;
437
438 reg &= ~TWL6040_HF_VOL_MASK;
439 twl6040_write(codec, TWL6040_REG_HFLGAIN,
440 reg | (0x1D - val));
441 } else {
442 left_complete = 1;
443 }
444 }
445
446 /* right channel */
447 right_step = (right_step > 0x1D) ? 0x1D : right_step;
448 reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
449 reg = 0x1D - reg;
450 val = (reg & TWL6040_HF_VOL_MASK);
451 if (handsfree->ramp == TWL6040_RAMP_UP) {
452 /* ramp step up */
453 if (val < handsfree->right_vol) {
454 if (val + right_step > handsfree->right_vol)
455 val = handsfree->right_vol;
456 else
457 val += right_step;
458
459 reg &= ~TWL6040_HF_VOL_MASK;
460 twl6040_write(codec, TWL6040_REG_HFRGAIN,
461 reg | (0x1D - val));
462 } else {
463 right_complete = 1;
464 }
465 } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
466 /* ramp step down */
467 if (val > 0) {
468 if ((int)val - (int)right_step < 0)
469 val = 0;
470 else
471 val -= right_step;
472
473 reg &= ~TWL6040_HF_VOL_MASK;
474 twl6040_write(codec, TWL6040_REG_HFRGAIN,
475 reg | (0x1D - val));
476 }
477 }
478
479 return left_complete & right_complete;
480}
481
482/*
483 * This work ramps both output PGAs at stream start/stop time to
484 * minimise pop associated with DAPM power switching.
485 */
486static void twl6040_pga_hs_work(struct work_struct *work)
487{
488 struct twl6040_data *priv =
489 container_of(work, struct twl6040_data, headset.work.work);
490 struct snd_soc_codec *codec = priv->codec;
491 struct twl6040_output *headset = &priv->headset;
492 int i, headset_complete;
493
494 /* do we need to ramp at all ? */
495 if (headset->ramp == TWL6040_RAMP_NONE)
496 return;
497
498 /* HS PGA gain range: 0x0 - 0xf (0 - 15) */
499 for (i = 0; i < 16; i++) {
500 headset_complete = twl6040_hs_ramp_step(codec,
501 headset->left_step,
502 headset->right_step);
503
504 /* ramp finished ? */
505 if (headset_complete)
506 break;
507
508 schedule_timeout_interruptible(
509 msecs_to_jiffies(headset->step_delay));
510 }
511
512 if (headset->ramp == TWL6040_RAMP_DOWN) {
513 headset->active = 0;
514 complete(&headset->ramp_done);
515 } else {
516 headset->active = 1;
517 }
518 headset->ramp = TWL6040_RAMP_NONE;
519}
520
521static void twl6040_pga_hf_work(struct work_struct *work)
522{
523 struct twl6040_data *priv =
524 container_of(work, struct twl6040_data, handsfree.work.work);
525 struct snd_soc_codec *codec = priv->codec;
526 struct twl6040_output *handsfree = &priv->handsfree;
527 int i, handsfree_complete;
528
529 /* do we need to ramp at all ? */
530 if (handsfree->ramp == TWL6040_RAMP_NONE)
531 return;
532
533 /*
534 * HF PGA gain range: 0x00 - 0x1d (0 - 29) */
535 for (i = 0; i < 30; i++) {
536 handsfree_complete = twl6040_hf_ramp_step(codec,
537 handsfree->left_step,
538 handsfree->right_step);
539
540 /* ramp finished ? */
541 if (handsfree_complete)
542 break;
543
544 schedule_timeout_interruptible(
545 msecs_to_jiffies(handsfree->step_delay));
546 }
547
548
549 if (handsfree->ramp == TWL6040_RAMP_DOWN) {
550 handsfree->active = 0;
551 complete(&handsfree->ramp_done);
552 } else
553 handsfree->active = 1;
554 handsfree->ramp = TWL6040_RAMP_NONE;
555}
556
557static int out_drv_event(struct snd_soc_dapm_widget *w,
558 struct snd_kcontrol *kcontrol, int event)
559{
560 struct snd_soc_codec *codec = w->codec;
561 struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
562 struct twl6040_output *out;
563 struct delayed_work *work;
564
565 switch (w->shift) {
566 case 2: /* Headset output driver */
567 out = &priv->headset;
568 work = &out->work;
569 /*
570 * Make sure, that we do not mess up variables for already
571 * executing work.
572 */
573 cancel_delayed_work_sync(work);
574
575 out->left_step = priv->hs_left_step;
576 out->right_step = priv->hs_right_step;
577 out->step_delay = 5; /* 5 ms between volume ramp steps */
578 break;
579 case 4: /* Handsfree output driver */
580 out = &priv->handsfree;
581 work = &out->work;
582 /*
583 * Make sure, that we do not mess up variables for already
584 * executing work.
585 */
586 cancel_delayed_work_sync(work);
587
588 out->left_step = priv->hf_left_step;
589 out->right_step = priv->hf_right_step;
590 out->step_delay = 5; /* 5 ms between volume ramp steps */
591 break;
592 default:
593 return -1;
594 }
595
596 switch (event) {
597 case SND_SOC_DAPM_POST_PMU:
598 if (out->active)
599 break;
600
601 /* don't use volume ramp for power-up */
602 out->ramp = TWL6040_RAMP_UP;
603 out->left_step = out->left_vol;
604 out->right_step = out->right_vol;
605
606 queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
607 break;
608
609 case SND_SOC_DAPM_PRE_PMD:
610 if (!out->active)
611 break;
612
613 /* use volume ramp for power-down */
614 out->ramp = TWL6040_RAMP_DOWN;
615 INIT_COMPLETION(out->ramp_done);
616
617 queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
618
619 wait_for_completion_timeout(&out->ramp_done,
620 msecs_to_jiffies(2000));
621 break;
622 }
623
624 return 0;
625}
626
627/* set headset dac and driver power mode */ 290/* set headset dac and driver power mode */
628static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) 291static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
629{ 292{
@@ -748,71 +411,6 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
748 return IRQ_HANDLED; 411 return IRQ_HANDLED;
749} 412}
750 413
751static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
752 struct snd_ctl_elem_value *ucontrol)
753{
754 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
755 struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
756 struct twl6040_output *out = NULL;
757 struct soc_mixer_control *mc =
758 (struct soc_mixer_control *)kcontrol->private_value;
759 int ret;
760
761 /* For HS and HF we shadow the values and only actually write
762 * them out when active in order to ensure the amplifier comes on
763 * as quietly as possible. */
764 switch (mc->reg) {
765 case TWL6040_REG_HSGAIN:
766 out = &twl6040_priv->headset;
767 break;
768 case TWL6040_REG_HFLGAIN:
769 out = &twl6040_priv->handsfree;
770 break;
771 default:
772 dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
773 __func__, mc->reg);
774 return -EINVAL;
775 }
776
777 out->left_vol = ucontrol->value.integer.value[0];
778 out->right_vol = ucontrol->value.integer.value[1];
779 if (!out->active)
780 return 1;
781
782 ret = snd_soc_put_volsw(kcontrol, ucontrol);
783 if (ret < 0)
784 return ret;
785
786 return 1;
787}
788
789static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
790 struct snd_ctl_elem_value *ucontrol)
791{
792 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
793 struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
794 struct twl6040_output *out = &twl6040_priv->headset;
795 struct soc_mixer_control *mc =
796 (struct soc_mixer_control *)kcontrol->private_value;
797
798 switch (mc->reg) {
799 case TWL6040_REG_HSGAIN:
800 out = &twl6040_priv->headset;
801 break;
802 case TWL6040_REG_HFLGAIN:
803 out = &twl6040_priv->handsfree;
804 break;
805 default:
806 dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
807 __func__, mc->reg);
808 return -EINVAL;
809 }
810
811 ucontrol->value.integer.value[0] = out->left_vol;
812 ucontrol->value.integer.value[1] = out->right_vol;
813 return 0;
814}
815
816static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, 414static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
817 struct snd_ctl_elem_value *ucontrol) 415 struct snd_ctl_elem_value *ucontrol)
818{ 416{
@@ -1077,12 +675,10 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
1077 TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv), 675 TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
1078 676
1079 /* Playback gains */ 677 /* Playback gains */
1080 SOC_DOUBLE_EXT_TLV("Headset Playback Volume", 678 SOC_DOUBLE_TLV("Headset Playback Volume",
1081 TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, twl6040_get_volsw, 679 TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
1082 twl6040_put_volsw, hs_tlv), 680 SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
1083 SOC_DOUBLE_R_EXT_TLV("Handsfree Playback Volume", 681 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
1084 TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1,
1085 twl6040_get_volsw, twl6040_put_volsw, hf_tlv),
1086 SOC_SINGLE_TLV("Earphone Playback Volume", 682 SOC_SINGLE_TLV("Earphone Playback Volume",
1087 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv), 683 TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
1088 684
@@ -1181,22 +777,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
1181 &auxr_switch_control), 777 &auxr_switch_control),
1182 778
1183 /* Analog playback drivers */ 779 /* Analog playback drivers */
1184 SND_SOC_DAPM_OUT_DRV_E("HF Left Driver", 780 SND_SOC_DAPM_OUT_DRV("HF Left Driver",
1185 TWL6040_REG_HFLCTL, 4, 0, NULL, 0, 781 TWL6040_REG_HFLCTL, 4, 0, NULL, 0),
1186 out_drv_event, 782 SND_SOC_DAPM_OUT_DRV("HF Right Driver",
1187 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 783 TWL6040_REG_HFRCTL, 4, 0, NULL, 0),
1188 SND_SOC_DAPM_OUT_DRV_E("HF Right Driver", 784 SND_SOC_DAPM_OUT_DRV("HS Left Driver",
1189 TWL6040_REG_HFRCTL, 4, 0, NULL, 0, 785 TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
1190 out_drv_event, 786 SND_SOC_DAPM_OUT_DRV("HS Right Driver",
1191 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 787 TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
1192 SND_SOC_DAPM_OUT_DRV_E("HS Left Driver",
1193 TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
1194 out_drv_event,
1195 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1196 SND_SOC_DAPM_OUT_DRV_E("HS Right Driver",
1197 TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
1198 out_drv_event,
1199 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1200 SND_SOC_DAPM_OUT_DRV_E("Earphone Driver", 788 SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
1201 TWL6040_REG_EARCTL, 0, 0, NULL, 0, 789 TWL6040_REG_EARCTL, 0, 0, NULL, 0,
1202 twl6040_ep_drv_event, 790 twl6040_ep_drv_event,
@@ -1568,14 +1156,9 @@ static int twl6040_probe(struct snd_soc_codec *codec)
1568 } 1156 }
1569 1157
1570 INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work); 1158 INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
1571 INIT_DELAYED_WORK(&priv->headset.work, twl6040_pga_hs_work);
1572 INIT_DELAYED_WORK(&priv->handsfree.work, twl6040_pga_hf_work);
1573 1159
1574 mutex_init(&priv->mutex); 1160 mutex_init(&priv->mutex);
1575 1161
1576 init_completion(&priv->headset.ramp_done);
1577 init_completion(&priv->handsfree.ramp_done);
1578
1579 ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler, 1162 ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
1580 0, "twl6040_irq_plug", codec); 1163 0, "twl6040_irq_plug", codec);
1581 if (ret) { 1164 if (ret) {