diff options
Diffstat (limited to 'sound/soc/codecs/wm_hubs.c')
| -rw-r--r-- | sound/soc/codecs/wm_hubs.c | 222 |
1 files changed, 186 insertions, 36 deletions
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index e542027eea89..e1f225a3ac46 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
| @@ -62,36 +62,108 @@ static const char *speaker_mode_text[] = { | |||
| 62 | static const struct soc_enum speaker_mode = | 62 | static const struct soc_enum speaker_mode = |
| 63 | SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); | 63 | SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); |
| 64 | 64 | ||
| 65 | static void wait_for_dc_servo(struct snd_soc_codec *codec) | 65 | static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) |
| 66 | { | 66 | { |
| 67 | unsigned int reg; | 67 | unsigned int reg; |
| 68 | int count = 0; | 68 | int count = 0; |
| 69 | unsigned int val; | ||
| 70 | |||
| 71 | val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1; | ||
| 72 | |||
| 73 | /* Trigger the command */ | ||
| 74 | snd_soc_write(codec, WM8993_DC_SERVO_0, val); | ||
| 69 | 75 | ||
| 70 | dev_dbg(codec->dev, "Waiting for DC servo...\n"); | 76 | dev_dbg(codec->dev, "Waiting for DC servo...\n"); |
| 77 | |||
| 71 | do { | 78 | do { |
| 72 | count++; | 79 | count++; |
| 73 | msleep(1); | 80 | msleep(1); |
| 74 | reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); | 81 | reg = snd_soc_read(codec, WM8993_DC_SERVO_0); |
| 75 | dev_dbg(codec->dev, "DC servo status: %x\n", reg); | 82 | dev_dbg(codec->dev, "DC servo: %x\n", reg); |
| 76 | } while ((reg & WM8993_DCS_CAL_COMPLETE_MASK) | 83 | } while (reg & op && count < 400); |
| 77 | != WM8993_DCS_CAL_COMPLETE_MASK && count < 1000); | ||
| 78 | 84 | ||
| 79 | if ((reg & WM8993_DCS_CAL_COMPLETE_MASK) | 85 | if (reg & op) |
| 80 | != WM8993_DCS_CAL_COMPLETE_MASK) | ||
| 81 | dev_err(codec->dev, "Timed out waiting for DC Servo\n"); | 86 | dev_err(codec->dev, "Timed out waiting for DC Servo\n"); |
| 82 | } | 87 | } |
| 83 | 88 | ||
| 84 | /* | 89 | /* |
| 90 | * Startup calibration of the DC servo | ||
| 91 | */ | ||
| 92 | static void calibrate_dc_servo(struct snd_soc_codec *codec) | ||
| 93 | { | ||
| 94 | struct wm_hubs_data *hubs = codec->private_data; | ||
| 95 | u16 reg, reg_l, reg_r, dcs_cfg; | ||
| 96 | |||
| 97 | /* Set for 32 series updates */ | ||
| 98 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, | ||
| 99 | WM8993_DCS_SERIES_NO_01_MASK, | ||
| 100 | 32 << WM8993_DCS_SERIES_NO_01_SHIFT); | ||
| 101 | wait_for_dc_servo(codec, | ||
| 102 | WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1); | ||
| 103 | |||
| 104 | /* Apply correction to DC servo result */ | ||
| 105 | if (hubs->dcs_codes) { | ||
| 106 | dev_dbg(codec->dev, "Applying %d code DC servo correction\n", | ||
| 107 | hubs->dcs_codes); | ||
| 108 | |||
| 109 | /* Different chips in the family support different | ||
| 110 | * readback methods. | ||
| 111 | */ | ||
| 112 | switch (hubs->dcs_readback_mode) { | ||
| 113 | case 0: | ||
| 114 | reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) | ||
| 115 | & WM8993_DCS_INTEG_CHAN_0_MASK;; | ||
| 116 | reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) | ||
| 117 | & WM8993_DCS_INTEG_CHAN_1_MASK; | ||
| 118 | break; | ||
| 119 | case 1: | ||
| 120 | reg = snd_soc_read(codec, WM8993_DC_SERVO_3); | ||
| 121 | reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) | ||
| 122 | >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; | ||
| 123 | reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; | ||
| 124 | break; | ||
| 125 | default: | ||
| 126 | WARN(1, "Unknown DCS readback method"); | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* HPOUT1L */ | ||
| 131 | if (reg_l + hubs->dcs_codes > 0 && | ||
| 132 | reg_l + hubs->dcs_codes < 0xff) | ||
| 133 | reg_l += hubs->dcs_codes; | ||
| 134 | dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT; | ||
| 135 | |||
| 136 | /* HPOUT1R */ | ||
| 137 | if (reg_r + hubs->dcs_codes > 0 && | ||
| 138 | reg_r + hubs->dcs_codes < 0xff) | ||
| 139 | reg_r += hubs->dcs_codes; | ||
| 140 | dcs_cfg |= reg_r; | ||
| 141 | |||
| 142 | /* Do it */ | ||
| 143 | snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg); | ||
| 144 | wait_for_dc_servo(codec, | ||
| 145 | WM8993_DCS_TRIG_DAC_WR_0 | | ||
| 146 | WM8993_DCS_TRIG_DAC_WR_1); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | /* | ||
| 85 | * Update the DC servo calibration on gain changes | 151 | * Update the DC servo calibration on gain changes |
| 86 | */ | 152 | */ |
| 87 | static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, | 153 | static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, |
| 88 | struct snd_ctl_elem_value *ucontrol) | 154 | struct snd_ctl_elem_value *ucontrol) |
| 89 | { | 155 | { |
| 90 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 156 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 157 | struct wm_hubs_data *hubs = codec->private_data; | ||
| 91 | int ret; | 158 | int ret; |
| 92 | 159 | ||
| 93 | ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); | 160 | ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); |
| 94 | 161 | ||
| 162 | /* If we're applying an offset correction then updating the | ||
| 163 | * callibration would be likely to introduce further offsets. */ | ||
| 164 | if (hubs->dcs_codes) | ||
| 165 | return ret; | ||
| 166 | |||
| 95 | /* Only need to do this if the outputs are active */ | 167 | /* Only need to do this if the outputs are active */ |
| 96 | if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1) | 168 | if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1) |
| 97 | & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA)) | 169 | & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA)) |
| @@ -251,6 +323,47 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1, | |||
| 251 | line_tlv), | 323 | line_tlv), |
| 252 | }; | 324 | }; |
| 253 | 325 | ||
| 326 | static int hp_supply_event(struct snd_soc_dapm_widget *w, | ||
| 327 | struct snd_kcontrol *kcontrol, int event) | ||
| 328 | { | ||
| 329 | struct snd_soc_codec *codec = w->codec; | ||
| 330 | struct wm_hubs_data *hubs = codec->private_data; | ||
| 331 | |||
| 332 | switch (event) { | ||
| 333 | case SND_SOC_DAPM_PRE_PMU: | ||
| 334 | switch (hubs->hp_startup_mode) { | ||
| 335 | case 0: | ||
| 336 | break; | ||
| 337 | case 1: | ||
| 338 | /* Enable the headphone amp */ | ||
| 339 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | ||
| 340 | WM8993_HPOUT1L_ENA | | ||
| 341 | WM8993_HPOUT1R_ENA, | ||
| 342 | WM8993_HPOUT1L_ENA | | ||
| 343 | WM8993_HPOUT1R_ENA); | ||
| 344 | |||
| 345 | /* Enable the second stage */ | ||
| 346 | snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, | ||
| 347 | WM8993_HPOUT1L_DLY | | ||
| 348 | WM8993_HPOUT1R_DLY, | ||
| 349 | WM8993_HPOUT1L_DLY | | ||
| 350 | WM8993_HPOUT1R_DLY); | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | dev_err(codec->dev, "Unknown HP startup mode %d\n", | ||
| 354 | hubs->hp_startup_mode); | ||
| 355 | break; | ||
| 356 | } | ||
| 357 | |||
| 358 | case SND_SOC_DAPM_PRE_PMD: | ||
| 359 | snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, | ||
| 360 | WM8993_CP_ENA, 0); | ||
| 361 | break; | ||
| 362 | } | ||
| 363 | |||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 254 | static int hp_event(struct snd_soc_dapm_widget *w, | 367 | static int hp_event(struct snd_soc_dapm_widget *w, |
| 255 | struct snd_kcontrol *kcontrol, int event) | 368 | struct snd_kcontrol *kcontrol, int event) |
| 256 | { | 369 | { |
| @@ -271,14 +384,11 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
| 271 | reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; | 384 | reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; |
| 272 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); | 385 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); |
| 273 | 386 | ||
| 274 | /* Start the DC servo */ | 387 | /* Smallest supported update interval */ |
| 275 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | 388 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, |
| 276 | 0xFFFF, | 389 | WM8993_DCS_TIMER_PERIOD_01_MASK, 1); |
| 277 | WM8993_DCS_ENA_CHAN_0 | | 390 | |
| 278 | WM8993_DCS_ENA_CHAN_1 | | 391 | calibrate_dc_servo(codec); |
| 279 | WM8993_DCS_TRIG_STARTUP_1 | | ||
| 280 | WM8993_DCS_TRIG_STARTUP_0); | ||
| 281 | wait_for_dc_servo(codec); | ||
| 282 | 392 | ||
| 283 | reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | | 393 | reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | |
| 284 | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; | 394 | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; |
| @@ -286,23 +396,19 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
| 286 | break; | 396 | break; |
| 287 | 397 | ||
| 288 | case SND_SOC_DAPM_PRE_PMD: | 398 | case SND_SOC_DAPM_PRE_PMD: |
| 289 | reg &= ~(WM8993_HPOUT1L_RMV_SHORT | | 399 | snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, |
| 290 | WM8993_HPOUT1L_DLY | | 400 | WM8993_HPOUT1L_DLY | |
| 291 | WM8993_HPOUT1L_OUTP | | 401 | WM8993_HPOUT1R_DLY | |
| 292 | WM8993_HPOUT1R_RMV_SHORT | | 402 | WM8993_HPOUT1L_RMV_SHORT | |
| 293 | WM8993_HPOUT1R_DLY | | 403 | WM8993_HPOUT1R_RMV_SHORT, 0); |
| 294 | WM8993_HPOUT1R_OUTP); | ||
| 295 | 404 | ||
| 296 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | 405 | snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0, |
| 297 | 0xffff, 0); | 406 | WM8993_HPOUT1L_OUTP | |
| 407 | WM8993_HPOUT1R_OUTP, 0); | ||
| 298 | 408 | ||
| 299 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); | ||
| 300 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 409 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
| 301 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, | 410 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, |
| 302 | 0); | 411 | 0); |
| 303 | |||
| 304 | snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1, | ||
| 305 | WM8993_CP_ENA, 0); | ||
| 306 | break; | 412 | break; |
| 307 | } | 413 | } |
| 308 | 414 | ||
| @@ -438,11 +544,11 @@ static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = { | |||
| 438 | SND_SOC_DAPM_INPUT("IN1LN"), | 544 | SND_SOC_DAPM_INPUT("IN1LN"), |
| 439 | SND_SOC_DAPM_INPUT("IN1LP"), | 545 | SND_SOC_DAPM_INPUT("IN1LP"), |
| 440 | SND_SOC_DAPM_INPUT("IN2LN"), | 546 | SND_SOC_DAPM_INPUT("IN2LN"), |
| 441 | SND_SOC_DAPM_INPUT("IN2LP/VXRN"), | 547 | SND_SOC_DAPM_INPUT("IN2LP:VXRN"), |
| 442 | SND_SOC_DAPM_INPUT("IN1RN"), | 548 | SND_SOC_DAPM_INPUT("IN1RN"), |
| 443 | SND_SOC_DAPM_INPUT("IN1RP"), | 549 | SND_SOC_DAPM_INPUT("IN1RP"), |
| 444 | SND_SOC_DAPM_INPUT("IN2RN"), | 550 | SND_SOC_DAPM_INPUT("IN2RN"), |
| 445 | SND_SOC_DAPM_INPUT("IN2RP/VXRP"), | 551 | SND_SOC_DAPM_INPUT("IN2RP:VXRP"), |
| 446 | 552 | ||
| 447 | SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), | 553 | SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), |
| 448 | SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), | 554 | SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), |
| @@ -473,6 +579,8 @@ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, | |||
| 473 | SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), | 579 | SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0), |
| 474 | SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), | 580 | SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0), |
| 475 | 581 | ||
| 582 | SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, | ||
| 583 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), | ||
| 476 | SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, | 584 | SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, |
| 477 | NULL, 0, | 585 | NULL, 0, |
| 478 | hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 586 | hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
| @@ -537,14 +645,14 @@ static const struct snd_soc_dapm_route analogue_routes[] = { | |||
| 537 | { "IN1R PGA", "IN1RP Switch", "IN1RP" }, | 645 | { "IN1R PGA", "IN1RP Switch", "IN1RP" }, |
| 538 | { "IN1R PGA", "IN1RN Switch", "IN1RN" }, | 646 | { "IN1R PGA", "IN1RN Switch", "IN1RN" }, |
| 539 | 647 | ||
| 540 | { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" }, | 648 | { "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" }, |
| 541 | { "IN2L PGA", "IN2LN Switch", "IN2LN" }, | 649 | { "IN2L PGA", "IN2LN Switch", "IN2LN" }, |
| 542 | 650 | ||
| 543 | { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" }, | 651 | { "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" }, |
| 544 | { "IN2R PGA", "IN2RN Switch", "IN2RN" }, | 652 | { "IN2R PGA", "IN2RN Switch", "IN2RN" }, |
| 545 | 653 | ||
| 546 | { "Direct Voice", NULL, "IN2LP/VXRN" }, | 654 | { "Direct Voice", NULL, "IN2LP:VXRN" }, |
| 547 | { "Direct Voice", NULL, "IN2RP/VXRP" }, | 655 | { "Direct Voice", NULL, "IN2RP:VXRP" }, |
| 548 | 656 | ||
| 549 | { "MIXINL", "IN1L Switch", "IN1L PGA" }, | 657 | { "MIXINL", "IN1L Switch", "IN1L PGA" }, |
| 550 | { "MIXINL", "IN2L Switch", "IN2L PGA" }, | 658 | { "MIXINL", "IN2L Switch", "IN2L PGA" }, |
| @@ -565,7 +673,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { | |||
| 565 | { "Left Output Mixer", "Right Input Switch", "MIXINR" }, | 673 | { "Left Output Mixer", "Right Input Switch", "MIXINR" }, |
| 566 | { "Left Output Mixer", "IN2RN Switch", "IN2RN" }, | 674 | { "Left Output Mixer", "IN2RN Switch", "IN2RN" }, |
| 567 | { "Left Output Mixer", "IN2LN Switch", "IN2LN" }, | 675 | { "Left Output Mixer", "IN2LN Switch", "IN2LN" }, |
| 568 | { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" }, | 676 | { "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" }, |
| 569 | { "Left Output Mixer", "IN1L Switch", "IN1L PGA" }, | 677 | { "Left Output Mixer", "IN1L Switch", "IN1L PGA" }, |
| 570 | { "Left Output Mixer", "IN1R Switch", "IN1R PGA" }, | 678 | { "Left Output Mixer", "IN1R Switch", "IN1R PGA" }, |
| 571 | 679 | ||
| @@ -573,7 +681,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { | |||
| 573 | { "Right Output Mixer", "Right Input Switch", "MIXINR" }, | 681 | { "Right Output Mixer", "Right Input Switch", "MIXINR" }, |
| 574 | { "Right Output Mixer", "IN2LN Switch", "IN2LN" }, | 682 | { "Right Output Mixer", "IN2LN Switch", "IN2LN" }, |
| 575 | { "Right Output Mixer", "IN2RN Switch", "IN2RN" }, | 683 | { "Right Output Mixer", "IN2RN Switch", "IN2RN" }, |
| 576 | { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" }, | 684 | { "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" }, |
| 577 | { "Right Output Mixer", "IN1L Switch", "IN1L PGA" }, | 685 | { "Right Output Mixer", "IN1L Switch", "IN1L PGA" }, |
| 578 | { "Right Output Mixer", "IN1R Switch", "IN1R PGA" }, | 686 | { "Right Output Mixer", "IN1R Switch", "IN1R PGA" }, |
| 579 | 687 | ||
| @@ -626,6 +734,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { | |||
| 626 | { "Headphone PGA", NULL, "Left Headphone Mux" }, | 734 | { "Headphone PGA", NULL, "Left Headphone Mux" }, |
| 627 | { "Headphone PGA", NULL, "Right Headphone Mux" }, | 735 | { "Headphone PGA", NULL, "Right Headphone Mux" }, |
| 628 | { "Headphone PGA", NULL, "CLK_SYS" }, | 736 | { "Headphone PGA", NULL, "CLK_SYS" }, |
| 737 | { "Headphone PGA", NULL, "Headphone Supply" }, | ||
| 629 | 738 | ||
| 630 | { "HPOUT1L", NULL, "Headphone PGA" }, | 739 | { "HPOUT1L", NULL, "Headphone PGA" }, |
| 631 | { "HPOUT1R", NULL, "Headphone PGA" }, | 740 | { "HPOUT1R", NULL, "Headphone PGA" }, |
| @@ -738,6 +847,47 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, | |||
| 738 | } | 847 | } |
| 739 | EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes); | 848 | EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes); |
| 740 | 849 | ||
| 850 | int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, | ||
| 851 | int lineout1_diff, int lineout2_diff, | ||
| 852 | int lineout1fb, int lineout2fb, | ||
| 853 | int jd_scthr, int jd_thr, int micbias1_lvl, | ||
| 854 | int micbias2_lvl) | ||
| 855 | { | ||
| 856 | if (!lineout1_diff) | ||
| 857 | snd_soc_update_bits(codec, WM8993_LINE_MIXER1, | ||
| 858 | WM8993_LINEOUT1_MODE, | ||
| 859 | WM8993_LINEOUT1_MODE); | ||
| 860 | if (!lineout2_diff) | ||
| 861 | snd_soc_update_bits(codec, WM8993_LINE_MIXER2, | ||
| 862 | WM8993_LINEOUT2_MODE, | ||
| 863 | WM8993_LINEOUT2_MODE); | ||
| 864 | |||
| 865 | /* If the line outputs are differential then we aren't presenting | ||
| 866 | * VMID as an output and can disable it. | ||
| 867 | */ | ||
| 868 | if (lineout1_diff && lineout2_diff) | ||
| 869 | codec->idle_bias_off = 1; | ||
| 870 | |||
| 871 | if (lineout1fb) | ||
| 872 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | ||
| 873 | WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); | ||
| 874 | |||
| 875 | if (lineout2fb) | ||
| 876 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | ||
| 877 | WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); | ||
| 878 | |||
| 879 | snd_soc_update_bits(codec, WM8993_MICBIAS, | ||
| 880 | WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | | ||
| 881 | WM8993_MICB1_LVL | WM8993_MICB2_LVL, | ||
| 882 | jd_scthr << WM8993_JD_SCTHR_SHIFT | | ||
| 883 | jd_thr << WM8993_JD_THR_SHIFT | | ||
| 884 | micbias1_lvl | | ||
| 885 | micbias2_lvl << WM8993_MICB2_LVL_SHIFT); | ||
| 886 | |||
| 887 | return 0; | ||
| 888 | } | ||
| 889 | EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); | ||
| 890 | |||
| 741 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); | 891 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); |
| 742 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 892 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
| 743 | MODULE_LICENSE("GPL"); | 893 | MODULE_LICENSE("GPL"); |
