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