diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 177 | ||||
-rw-r--r-- | sound/soc/codecs/twl4030.h | 16 |
2 files changed, 190 insertions, 3 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ffd5120697a2..3c9fdf2c6c7b 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -46,9 +46,9 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
46 | 0xc3, /* REG_OPTION (0x2) */ | 46 | 0xc3, /* REG_OPTION (0x2) */ |
47 | 0x00, /* REG_UNKNOWN (0x3) */ | 47 | 0x00, /* REG_UNKNOWN (0x3) */ |
48 | 0x00, /* REG_MICBIAS_CTL (0x4) */ | 48 | 0x00, /* REG_MICBIAS_CTL (0x4) */ |
49 | 0x24, /* REG_ANAMICL (0x5) */ | 49 | 0x20, /* REG_ANAMICL (0x5) */ |
50 | 0x04, /* REG_ANAMICR (0x6) */ | 50 | 0x00, /* REG_ANAMICR (0x6) */ |
51 | 0x0a, /* REG_AVADC_CTL (0x7) */ | 51 | 0x00, /* REG_AVADC_CTL (0x7) */ |
52 | 0x00, /* REG_ADCMICSEL (0x8) */ | 52 | 0x00, /* REG_ADCMICSEL (0x8) */ |
53 | 0x00, /* REG_DIGMIXING (0x9) */ | 53 | 0x00, /* REG_DIGMIXING (0x9) */ |
54 | 0x0c, /* REG_ATXL1PGA (0xA) */ | 54 | 0x0c, /* REG_ATXL1PGA (0xA) */ |
@@ -347,6 +347,162 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, | |||
347 | return err; | 347 | return err; |
348 | } | 348 | } |
349 | 349 | ||
350 | static int twl4030_get_left_input(struct snd_kcontrol *kcontrol, | ||
351 | struct snd_ctl_elem_value *ucontrol) | ||
352 | { | ||
353 | struct snd_soc_codec *codec = kcontrol->private_data; | ||
354 | u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | ||
355 | int result = 0; | ||
356 | |||
357 | /* one bit must be set a time */ | ||
358 | reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN | ||
359 | | TWL4030_MAINMIC_EN; | ||
360 | if (reg != 0) { | ||
361 | result++; | ||
362 | while ((reg & 1) == 0) { | ||
363 | result++; | ||
364 | reg >>= 1; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | ucontrol->value.integer.value[0] = result; | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int twl4030_put_left_input(struct snd_kcontrol *kcontrol, | ||
373 | struct snd_ctl_elem_value *ucontrol) | ||
374 | { | ||
375 | struct snd_soc_codec *codec = kcontrol->private_data; | ||
376 | int value = ucontrol->value.integer.value[0]; | ||
377 | u8 anamicl, micbias, avadc_ctl; | ||
378 | |||
379 | anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | ||
380 | anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN | ||
381 | | TWL4030_MAINMIC_EN); | ||
382 | micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); | ||
383 | micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN); | ||
384 | avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); | ||
385 | |||
386 | switch (value) { | ||
387 | case 1: | ||
388 | anamicl |= TWL4030_MAINMIC_EN; | ||
389 | micbias |= TWL4030_MICBIAS1_EN; | ||
390 | break; | ||
391 | case 2: | ||
392 | anamicl |= TWL4030_HSMIC_EN; | ||
393 | micbias |= TWL4030_HSMICBIAS_EN; | ||
394 | break; | ||
395 | case 3: | ||
396 | anamicl |= TWL4030_AUXL_EN; | ||
397 | break; | ||
398 | case 4: | ||
399 | anamicl |= TWL4030_CKMIC_EN; | ||
400 | break; | ||
401 | default: | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | /* If some input is selected, enable amp and ADC */ | ||
406 | if (value != 0) { | ||
407 | anamicl |= TWL4030_MICAMPL_EN; | ||
408 | avadc_ctl |= TWL4030_ADCL_EN; | ||
409 | } else { | ||
410 | anamicl &= ~TWL4030_MICAMPL_EN; | ||
411 | avadc_ctl &= ~TWL4030_ADCL_EN; | ||
412 | } | ||
413 | |||
414 | twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl); | ||
415 | twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); | ||
416 | twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); | ||
417 | |||
418 | return 1; | ||
419 | } | ||
420 | |||
421 | static int twl4030_get_right_input(struct snd_kcontrol *kcontrol, | ||
422 | struct snd_ctl_elem_value *ucontrol) | ||
423 | { | ||
424 | struct snd_soc_codec *codec = kcontrol->private_data; | ||
425 | u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); | ||
426 | int value = 0; | ||
427 | |||
428 | reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN; | ||
429 | switch (reg) { | ||
430 | case TWL4030_SUBMIC_EN: | ||
431 | value = 1; | ||
432 | break; | ||
433 | case TWL4030_AUXR_EN: | ||
434 | value = 2; | ||
435 | break; | ||
436 | default: | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | ucontrol->value.integer.value[0] = value; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int twl4030_put_right_input(struct snd_kcontrol *kcontrol, | ||
445 | struct snd_ctl_elem_value *ucontrol) | ||
446 | { | ||
447 | struct snd_soc_codec *codec = kcontrol->private_data; | ||
448 | int value = ucontrol->value.integer.value[0]; | ||
449 | u8 anamicr, micbias, avadc_ctl; | ||
450 | |||
451 | anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); | ||
452 | anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN); | ||
453 | micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); | ||
454 | micbias &= ~TWL4030_MICBIAS2_EN; | ||
455 | avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); | ||
456 | |||
457 | switch (value) { | ||
458 | case 1: | ||
459 | anamicr |= TWL4030_SUBMIC_EN; | ||
460 | micbias |= TWL4030_MICBIAS2_EN; | ||
461 | break; | ||
462 | case 2: | ||
463 | anamicr |= TWL4030_AUXR_EN; | ||
464 | break; | ||
465 | default: | ||
466 | break; | ||
467 | } | ||
468 | |||
469 | if (value != 0) { | ||
470 | anamicr |= TWL4030_MICAMPR_EN; | ||
471 | avadc_ctl |= TWL4030_ADCR_EN; | ||
472 | } else { | ||
473 | anamicr &= ~TWL4030_MICAMPR_EN; | ||
474 | avadc_ctl &= ~TWL4030_ADCR_EN; | ||
475 | } | ||
476 | |||
477 | twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr); | ||
478 | twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); | ||
479 | twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); | ||
480 | |||
481 | return 1; | ||
482 | } | ||
483 | |||
484 | static const char *twl4030_left_in_sel[] = { | ||
485 | "None", | ||
486 | "Main Mic", | ||
487 | "Headset Mic", | ||
488 | "Line In", | ||
489 | "Carkit Mic", | ||
490 | }; | ||
491 | |||
492 | static const char *twl4030_right_in_sel[] = { | ||
493 | "None", | ||
494 | "Sub Mic", | ||
495 | "Line In", | ||
496 | }; | ||
497 | |||
498 | static const struct soc_enum twl4030_left_input_mux = | ||
499 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel), | ||
500 | twl4030_left_in_sel); | ||
501 | |||
502 | static const struct soc_enum twl4030_right_input_mux = | ||
503 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel), | ||
504 | twl4030_right_in_sel); | ||
505 | |||
350 | /* | 506 | /* |
351 | * FGAIN volume control: | 507 | * FGAIN volume control: |
352 | * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) | 508 | * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) |
@@ -378,6 +534,12 @@ static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); | |||
378 | */ | 534 | */ |
379 | static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); | 535 | static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); |
380 | 536 | ||
537 | /* | ||
538 | * Gain control for input amplifiers | ||
539 | * 0 dB to 30 dB in 6 dB steps | ||
540 | */ | ||
541 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); | ||
542 | |||
381 | static const struct snd_kcontrol_new twl4030_snd_controls[] = { | 543 | static const struct snd_kcontrol_new twl4030_snd_controls[] = { |
382 | /* Common playback gain controls */ | 544 | /* Common playback gain controls */ |
383 | SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", | 545 | SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", |
@@ -420,6 +582,15 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { | |||
420 | SOC_DOUBLE_R_TLV("Capture Volume", | 582 | SOC_DOUBLE_R_TLV("Capture Volume", |
421 | TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, | 583 | TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, |
422 | 0, 0x1f, 0, digital_capture_tlv), | 584 | 0, 0x1f, 0, digital_capture_tlv), |
585 | |||
586 | SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN, | ||
587 | 0, 3, 5, 0, input_gain_tlv), | ||
588 | |||
589 | /* Input source controls */ | ||
590 | SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux, | ||
591 | twl4030_get_left_input, twl4030_put_left_input), | ||
592 | SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux, | ||
593 | twl4030_get_right_input, twl4030_put_right_input), | ||
423 | }; | 594 | }; |
424 | 595 | ||
425 | /* add non dapm controls */ | 596 | /* add non dapm controls */ |
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 09865d9f5203..a2065d417c2e 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h | |||
@@ -113,7 +113,16 @@ | |||
113 | #define TWL4030_CODECPDZ 0x02 | 113 | #define TWL4030_CODECPDZ 0x02 |
114 | #define TWL4030_OPT_MODE 0x01 | 114 | #define TWL4030_OPT_MODE 0x01 |
115 | 115 | ||
116 | /* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ | ||
117 | |||
118 | #define TWL4030_MICBIAS2_CTL 0x40 | ||
119 | #define TWL4030_MICBIAS1_CTL 0x20 | ||
120 | #define TWL4030_HSMICBIAS_EN 0x04 | ||
121 | #define TWL4030_MICBIAS2_EN 0x02 | ||
122 | #define TWL4030_MICBIAS1_EN 0x01 | ||
123 | |||
116 | /* ANAMICL (0x05) Fields */ | 124 | /* ANAMICL (0x05) Fields */ |
125 | |||
117 | #define TWL4030_CNCL_OFFSET_START 0x80 | 126 | #define TWL4030_CNCL_OFFSET_START 0x80 |
118 | #define TWL4030_OFFSET_CNCL_SEL 0x60 | 127 | #define TWL4030_OFFSET_CNCL_SEL 0x60 |
119 | #define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 | 128 | #define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 |
@@ -127,10 +136,17 @@ | |||
127 | #define TWL4030_MAINMIC_EN 0x01 | 136 | #define TWL4030_MAINMIC_EN 0x01 |
128 | 137 | ||
129 | /* ANAMICR (0x06) Fields */ | 138 | /* ANAMICR (0x06) Fields */ |
139 | |||
130 | #define TWL4030_MICAMPR_EN 0x10 | 140 | #define TWL4030_MICAMPR_EN 0x10 |
131 | #define TWL4030_AUXR_EN 0x04 | 141 | #define TWL4030_AUXR_EN 0x04 |
132 | #define TWL4030_SUBMIC_EN 0x01 | 142 | #define TWL4030_SUBMIC_EN 0x01 |
133 | 143 | ||
144 | /* AVADC_CTL (0x07) Fields */ | ||
145 | |||
146 | #define TWL4030_ADCL_EN 0x08 | ||
147 | #define TWL4030_AVADC_CLK_PRIORITY 0x04 | ||
148 | #define TWL4030_ADCR_EN 0x02 | ||
149 | |||
134 | /* AUDIO_IF (0x0E) Fields */ | 150 | /* AUDIO_IF (0x0E) Fields */ |
135 | 151 | ||
136 | #define TWL4030_AIF_SLAVE_EN 0x80 | 152 | #define TWL4030_AIF_SLAVE_EN 0x80 |