1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. 3 4 #include <linux/module.h> 5 #include <linux/init.h> 6 #include <linux/slab.h> 7 #include <linux/device.h> 8 #include <linux/pm_runtime.h> 9 #include <linux/printk.h> 10 #include <linux/delay.h> 11 #include <linux/kernel.h> 12 #include <sound/soc.h> 13 #include <sound/jack.h> 14 #include "wcd-mbhc-v2.h" 15 16 #define HS_DETECT_PLUG_TIME_MS (3 * 1000) 17 #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250 18 #define GND_MIC_SWAP_THRESHOLD 4 19 #define GND_MIC_USBC_SWAP_THRESHOLD 2 20 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100 21 #define HPHL_CROSS_CONN_THRESHOLD 100 22 #define HS_VREF_MIN_VAL 1400 23 #define FAKE_REM_RETRY_ATTEMPTS 3 24 #define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700 25 #define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75 26 #define WCD_MBHC_ADC_MICBIAS_MV 1800 27 #define WCD_MBHC_FAKE_INS_RETRY 4 28 29 #define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \ 30 SND_JACK_MECHANICAL) 31 32 #define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \ 33 SND_JACK_BTN_2 | SND_JACK_BTN_3 | \ 34 SND_JACK_BTN_4 | SND_JACK_BTN_5) 35 36 enum wcd_mbhc_adc_mux_ctl { 37 MUX_CTL_AUTO = 0, 38 MUX_CTL_IN2P, 39 MUX_CTL_IN3P, 40 MUX_CTL_IN4P, 41 MUX_CTL_HPH_L, 42 MUX_CTL_HPH_R, 43 MUX_CTL_NONE, 44 }; 45 46 struct wcd_mbhc { 47 struct device *dev; 48 struct snd_soc_component *component; 49 struct snd_soc_jack *jack; 50 struct wcd_mbhc_config *cfg; 51 const struct wcd_mbhc_cb *mbhc_cb; 52 const struct wcd_mbhc_intr *intr_ids; 53 const struct wcd_mbhc_field *fields; 54 /* Delayed work to report long button press */ 55 struct delayed_work mbhc_btn_dwork; 56 /* Work to handle plug report */ 57 struct work_struct mbhc_plug_detect_work; 58 /* Work to correct accessory type */ 59 struct work_struct correct_plug_swch; 60 struct mutex lock; 61 int buttons_pressed; 62 u32 hph_status; /* track headhpone status */ 63 u8 current_plug; 64 unsigned int swap_thr; 65 bool is_btn_press; 66 bool in_swch_irq_handler; 67 bool hs_detect_work_stop; 68 bool is_hs_recording; 69 bool extn_cable_hph_rem; 70 bool force_linein; 71 bool impedance_detect; 72 unsigned long event_state; 73 unsigned long jiffies_atreport; 74 /* impedance of hphl and hphr */ 75 uint32_t zl, zr; 76 /* Holds type of Headset - Mono/Stereo */ 77 enum wcd_mbhc_hph_type hph_type; 78 /* Holds mbhc detection method - ADC/Legacy */ 79 int mbhc_detection_logic; 80 }; 81 82 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc, 83 int field, int val) 84 { 85 if (!mbhc->fields[field].reg) 86 return 0; 87 88 return snd_soc_component_write_field(mbhc->component, 89 mbhc->fields[field].reg, 90 mbhc->fields[field].mask, val); 91 } 92 93 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field) 94 { 95 if (!mbhc->fields[field].reg) 96 return 0; 97 98 return snd_soc_component_read_field(mbhc->component, 99 mbhc->fields[field].reg, 100 mbhc->fields[field].mask); 101 } 102 103 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc) 104 { 105 u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100); 106 107 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val); 108 } 109 110 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias) 111 { 112 struct snd_soc_component *component = mbhc->component; 113 114 mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low, 115 mbhc->cfg->btn_high, 116 mbhc->cfg->num_btn, micbias); 117 } 118 119 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc, 120 const enum wcd_mbhc_cs_mb_en_flag cs_mb_en) 121 { 122 123 /* 124 * Some codecs handle micbias/pullup enablement in codec 125 * drivers itself and micbias is not needed for regular 126 * plug type detection. So if micbias_control callback function 127 * is defined, just return. 128 */ 129 if (mbhc->mbhc_cb->mbhc_micbias_control) 130 return; 131 132 switch (cs_mb_en) { 133 case WCD_MBHC_EN_CS: 134 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); 135 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); 136 /* Program Button threshold registers as per CS */ 137 wcd_program_btn_threshold(mbhc, false); 138 break; 139 case WCD_MBHC_EN_MB: 140 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); 141 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 142 /* Disable PULL_UP_EN & enable MICBIAS */ 143 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2); 144 /* Program Button threshold registers as per MICBIAS */ 145 wcd_program_btn_threshold(mbhc, true); 146 break; 147 case WCD_MBHC_EN_PULLUP: 148 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); 149 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 150 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1); 151 /* Program Button threshold registers as per MICBIAS */ 152 wcd_program_btn_threshold(mbhc, true); 153 break; 154 case WCD_MBHC_EN_NONE: 155 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); 156 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 157 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); 158 break; 159 default: 160 dev_err(mbhc->dev, "%s: Invalid parameter", __func__); 161 break; 162 } 163 } 164 165 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event) 166 { 167 168 struct snd_soc_component *component; 169 bool micbias2 = false; 170 171 if (!mbhc) 172 return 0; 173 174 component = mbhc->component; 175 176 if (mbhc->mbhc_cb->micbias_enable_status) 177 micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2); 178 179 switch (event) { 180 /* MICBIAS usage change */ 181 case WCD_EVENT_POST_DAPM_MICBIAS_2_ON: 182 mbhc->is_hs_recording = true; 183 break; 184 case WCD_EVENT_POST_MICBIAS_2_ON: 185 /* Disable current source if micbias2 enabled */ 186 if (mbhc->mbhc_cb->mbhc_micbias_control) { 187 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN)) 188 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); 189 } else { 190 mbhc->is_hs_recording = true; 191 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); 192 } 193 break; 194 case WCD_EVENT_PRE_MICBIAS_2_OFF: 195 /* 196 * Before MICBIAS_2 is turned off, if FSM is enabled, 197 * make sure current source is enabled so as to detect 198 * button press/release events 199 */ 200 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) { 201 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN)) 202 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); 203 } 204 break; 205 /* MICBIAS usage change */ 206 case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: 207 mbhc->is_hs_recording = false; 208 break; 209 case WCD_EVENT_POST_MICBIAS_2_OFF: 210 if (!mbhc->mbhc_cb->mbhc_micbias_control) 211 mbhc->is_hs_recording = false; 212 213 /* Enable PULL UP if PA's are enabled */ 214 if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || 215 (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state))) 216 /* enable pullup and cs, disable mb */ 217 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); 218 else 219 /* enable current source and disable mb, pullup*/ 220 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); 221 222 break; 223 case WCD_EVENT_POST_HPHL_PA_OFF: 224 clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); 225 226 /* check if micbias is enabled */ 227 if (micbias2) 228 /* Disable cs, pullup & enable micbias */ 229 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); 230 else 231 /* Disable micbias, pullup & enable cs */ 232 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); 233 break; 234 case WCD_EVENT_POST_HPHR_PA_OFF: 235 clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); 236 /* check if micbias is enabled */ 237 if (micbias2) 238 /* Disable cs, pullup & enable micbias */ 239 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); 240 else 241 /* Disable micbias, pullup & enable cs */ 242 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); 243 break; 244 case WCD_EVENT_PRE_HPHL_PA_ON: 245 set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); 246 /* check if micbias is enabled */ 247 if (micbias2) 248 /* Disable cs, pullup & enable micbias */ 249 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); 250 else 251 /* Disable micbias, enable pullup & cs */ 252 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); 253 break; 254 case WCD_EVENT_PRE_HPHR_PA_ON: 255 set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); 256 /* check if micbias is enabled */ 257 if (micbias2) 258 /* Disable cs, pullup & enable micbias */ 259 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); 260 else 261 /* Disable micbias, enable pullup & cs */ 262 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); 263 break; 264 default: 265 break; 266 } 267 return 0; 268 } 269 EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify); 270 271 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc) 272 { 273 return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork); 274 } 275 276 static void wcd_micbias_disable(struct wcd_mbhc *mbhc) 277 { 278 struct snd_soc_component *component = mbhc->component; 279 280 if (mbhc->mbhc_cb->mbhc_micbias_control) 281 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE); 282 283 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) 284 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false); 285 286 if (mbhc->mbhc_cb->set_micbias_value) { 287 mbhc->mbhc_cb->set_micbias_value(component); 288 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); 289 } 290 } 291 292 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc, 293 enum snd_jack_types jack_type) 294 { 295 mbhc->hph_status &= ~jack_type; 296 /* 297 * cancel possibly scheduled btn work and 298 * report release if we reported button press 299 */ 300 if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) { 301 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); 302 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; 303 } 304 305 wcd_micbias_disable(mbhc); 306 mbhc->hph_type = WCD_MBHC_HPH_NONE; 307 mbhc->zl = mbhc->zr = 0; 308 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK); 309 mbhc->current_plug = MBHC_PLUG_TYPE_NONE; 310 mbhc->force_linein = false; 311 } 312 313 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc) 314 { 315 316 if (!mbhc->impedance_detect) 317 return; 318 319 if (mbhc->cfg->linein_th != 0) { 320 u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN); 321 /* Set MUX_CTL to AUTO for Z-det */ 322 323 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); 324 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); 325 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 326 mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr); 327 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en); 328 } 329 } 330 331 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc, 332 enum snd_jack_types jack_type) 333 { 334 bool is_pa_on; 335 /* 336 * Report removal of current jack type. 337 * Headphone to headset shouldn't report headphone 338 * removal. 339 */ 340 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET && 341 jack_type == SND_JACK_HEADPHONE) 342 mbhc->hph_status &= ~SND_JACK_HEADSET; 343 344 /* Report insertion */ 345 switch (jack_type) { 346 case SND_JACK_HEADPHONE: 347 mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE; 348 break; 349 case SND_JACK_HEADSET: 350 mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET; 351 mbhc->jiffies_atreport = jiffies; 352 break; 353 case SND_JACK_LINEOUT: 354 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; 355 break; 356 default: 357 break; 358 } 359 360 361 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); 362 363 if (!is_pa_on) { 364 wcd_mbhc_compute_impedance(mbhc); 365 if ((mbhc->zl > mbhc->cfg->linein_th) && 366 (mbhc->zr > mbhc->cfg->linein_th) && 367 (jack_type == SND_JACK_HEADPHONE)) { 368 jack_type = SND_JACK_LINEOUT; 369 mbhc->force_linein = true; 370 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; 371 if (mbhc->hph_status) { 372 mbhc->hph_status &= ~(SND_JACK_HEADSET | 373 SND_JACK_LINEOUT); 374 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, 375 WCD_MBHC_JACK_MASK); 376 } 377 } 378 } 379 380 /* Do not calculate impedance again for lineout 381 * as during playback pa is on and impedance values 382 * will not be correct resulting in lineout detected 383 * as headphone. 384 */ 385 if (is_pa_on && mbhc->force_linein) { 386 jack_type = SND_JACK_LINEOUT; 387 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; 388 if (mbhc->hph_status) { 389 mbhc->hph_status &= ~(SND_JACK_HEADSET | 390 SND_JACK_LINEOUT); 391 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, 392 WCD_MBHC_JACK_MASK); 393 } 394 } 395 396 mbhc->hph_status |= jack_type; 397 398 if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control) 399 mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false); 400 401 snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL), 402 WCD_MBHC_JACK_MASK); 403 } 404 405 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, 406 enum snd_jack_types jack_type) 407 { 408 409 WARN_ON(!mutex_is_locked(&mbhc->lock)); 410 411 if (!insertion) /* Report removal */ 412 wcd_mbhc_report_plug_removal(mbhc, jack_type); 413 else 414 wcd_mbhc_report_plug_insertion(mbhc, jack_type); 415 416 } 417 418 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc, 419 struct work_struct *work) 420 { 421 mbhc->hs_detect_work_stop = true; 422 mutex_unlock(&mbhc->lock); 423 cancel_work_sync(work); 424 mutex_lock(&mbhc->lock); 425 } 426 427 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc) 428 { 429 /* cancel pending button press */ 430 wcd_cancel_btn_work(mbhc); 431 /* cancel correct work function */ 432 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); 433 } 434 435 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc) 436 { 437 wcd_mbhc_cancel_pending_work(mbhc); 438 /* Report extension cable */ 439 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); 440 /* 441 * Disable HPHL trigger and MIC Schmitt triggers. 442 * Setup for insertion detection. 443 */ 444 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); 445 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE); 446 /* Disable HW FSM */ 447 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); 448 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3); 449 450 /* Set the detection type appropriately */ 451 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1); 452 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr); 453 } 454 455 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc, 456 enum wcd_mbhc_plug_type plug_type) 457 { 458 if (mbhc->current_plug == plug_type) 459 return; 460 461 mutex_lock(&mbhc->lock); 462 463 switch (plug_type) { 464 case MBHC_PLUG_TYPE_HEADPHONE: 465 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE); 466 break; 467 case MBHC_PLUG_TYPE_HEADSET: 468 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET); 469 break; 470 case MBHC_PLUG_TYPE_HIGH_HPH: 471 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); 472 break; 473 case MBHC_PLUG_TYPE_GND_MIC_SWAP: 474 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) 475 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); 476 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) 477 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); 478 break; 479 default: 480 WARN(1, "Unexpected current plug_type %d, plug_type %d\n", 481 mbhc->current_plug, plug_type); 482 break; 483 } 484 mutex_unlock(&mbhc->lock); 485 } 486 487 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc, 488 struct work_struct *work) 489 { 490 WARN_ON(!mutex_is_locked(&mbhc->lock)); 491 mbhc->hs_detect_work_stop = false; 492 schedule_work(work); 493 } 494 495 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc) 496 { 497 struct snd_soc_component *component = mbhc->component; 498 499 WARN_ON(!mutex_is_locked(&mbhc->lock)); 500 501 if (mbhc->mbhc_cb->hph_pull_down_ctrl) 502 mbhc->mbhc_cb->hph_pull_down_ctrl(component, false); 503 504 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); 505 506 if (mbhc->mbhc_cb->mbhc_micbias_control) { 507 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, 508 MICB_ENABLE); 509 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); 510 } 511 } 512 513 static void mbhc_plug_detect_fn(struct work_struct *work) 514 { 515 struct wcd_mbhc *mbhc = container_of(work, struct wcd_mbhc, mbhc_plug_detect_work); 516 struct snd_soc_component *component = mbhc->component; 517 enum snd_jack_types jack_type; 518 bool detection_type; 519 520 mutex_lock(&mbhc->lock); 521 522 mbhc->in_swch_irq_handler = true; 523 524 wcd_mbhc_cancel_pending_work(mbhc); 525 526 detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE); 527 528 /* Set the detection type appropriately */ 529 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type); 530 531 /* Enable micbias ramp */ 532 if (mbhc->mbhc_cb->mbhc_micb_ramp_control) 533 mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true); 534 535 if (detection_type) { 536 if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) 537 goto exit; 538 /* Make sure MASTER_BIAS_CTL is enabled */ 539 mbhc->mbhc_cb->mbhc_bias(component, true); 540 mbhc->is_btn_press = false; 541 wcd_mbhc_adc_detect_plug_type(mbhc); 542 } else { 543 /* Disable HW FSM */ 544 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); 545 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); 546 mbhc->extn_cable_hph_rem = false; 547 548 if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE) 549 goto exit; 550 551 mbhc->is_btn_press = false; 552 switch (mbhc->current_plug) { 553 case MBHC_PLUG_TYPE_HEADPHONE: 554 jack_type = SND_JACK_HEADPHONE; 555 break; 556 case MBHC_PLUG_TYPE_HEADSET: 557 jack_type = SND_JACK_HEADSET; 558 break; 559 case MBHC_PLUG_TYPE_HIGH_HPH: 560 if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC) 561 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0); 562 jack_type = SND_JACK_LINEOUT; 563 break; 564 case MBHC_PLUG_TYPE_GND_MIC_SWAP: 565 dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n"); 566 goto exit; 567 default: 568 dev_err(mbhc->dev, "Invalid current plug: %d\n", 569 mbhc->current_plug); 570 goto exit; 571 } 572 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); 573 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); 574 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1); 575 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0); 576 wcd_mbhc_report_plug(mbhc, 0, jack_type); 577 } 578 579 exit: 580 mbhc->in_swch_irq_handler = false; 581 mutex_unlock(&mbhc->lock); 582 } 583 584 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data) 585 { 586 struct wcd_mbhc *mbhc = data; 587 588 if (!mbhc->cfg->typec_analog_mux) 589 schedule_work(&mbhc->mbhc_plug_detect_work); 590 591 return IRQ_HANDLED; 592 } 593 594 int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc) 595 { 596 597 if (!mbhc || !mbhc->cfg->typec_analog_mux) 598 return -EINVAL; 599 600 if (mbhc->mbhc_cb->clk_setup) 601 mbhc->mbhc_cb->clk_setup(mbhc->component, false); 602 603 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0); 604 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, 0); 605 606 schedule_work(&mbhc->mbhc_plug_detect_work); 607 608 return 0; 609 } 610 EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_unplug); 611 612 int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc) 613 { 614 if (!mbhc || !mbhc->cfg->typec_analog_mux) 615 return -EINVAL; 616 617 if (mbhc->mbhc_cb->clk_setup) 618 mbhc->mbhc_cb->clk_setup(mbhc->component, true); 619 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); 620 621 schedule_work(&mbhc->mbhc_plug_detect_work); 622 623 return 0; 624 } 625 EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_plug); 626 627 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc) 628 { 629 int mask = 0; 630 int btn; 631 632 btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT); 633 634 switch (btn) { 635 case 0: 636 mask = SND_JACK_BTN_0; 637 break; 638 case 1: 639 mask = SND_JACK_BTN_1; 640 break; 641 case 2: 642 mask = SND_JACK_BTN_2; 643 break; 644 case 3: 645 mask = SND_JACK_BTN_3; 646 break; 647 case 4: 648 mask = SND_JACK_BTN_4; 649 break; 650 case 5: 651 mask = SND_JACK_BTN_5; 652 break; 653 default: 654 break; 655 } 656 657 return mask; 658 } 659 660 static void wcd_btn_long_press_fn(struct work_struct *work) 661 { 662 struct delayed_work *dwork = to_delayed_work(work); 663 struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork); 664 665 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) 666 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed, 667 mbhc->buttons_pressed); 668 } 669 670 static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data) 671 { 672 struct wcd_mbhc *mbhc = data; 673 int mask; 674 unsigned long msec_val; 675 676 mutex_lock(&mbhc->lock); 677 wcd_cancel_btn_work(mbhc); 678 mbhc->is_btn_press = true; 679 msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport); 680 681 /* Too short, ignore button press */ 682 if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) 683 goto done; 684 685 /* If switch interrupt already kicked in, ignore button press */ 686 if (mbhc->in_swch_irq_handler) 687 goto done; 688 689 /* Plug isn't headset, ignore button press */ 690 if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) 691 goto done; 692 693 mask = wcd_mbhc_get_button_mask(mbhc); 694 mbhc->buttons_pressed |= mask; 695 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0) 696 WARN(1, "Button pressed twice without release event\n"); 697 done: 698 mutex_unlock(&mbhc->lock); 699 return IRQ_HANDLED; 700 } 701 702 static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data) 703 { 704 struct wcd_mbhc *mbhc = data; 705 int ret; 706 707 mutex_lock(&mbhc->lock); 708 if (mbhc->is_btn_press) 709 mbhc->is_btn_press = false; 710 else /* fake btn press */ 711 goto exit; 712 713 if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK)) 714 goto exit; 715 716 ret = wcd_cancel_btn_work(mbhc); 717 if (ret == 0) { /* Reporting long button release event */ 718 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); 719 } else { 720 if (!mbhc->in_swch_irq_handler) { 721 /* Reporting btn press n Release */ 722 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed, 723 mbhc->buttons_pressed); 724 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); 725 } 726 } 727 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; 728 exit: 729 mutex_unlock(&mbhc->lock); 730 731 return IRQ_HANDLED; 732 } 733 734 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr) 735 { 736 737 /* TODO Find a better way to report this to Userspace */ 738 dev_err(mbhc->dev, "MBHC Over Current on %s detected\n", 739 hphr ? "HPHR" : "HPHL"); 740 741 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0); 742 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1); 743 744 return IRQ_HANDLED; 745 } 746 747 static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data) 748 { 749 return wcd_mbhc_hph_ocp_irq(data, false); 750 } 751 752 static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data) 753 { 754 return wcd_mbhc_hph_ocp_irq(data, true); 755 } 756 757 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) 758 { 759 struct snd_soc_component *component = mbhc->component; 760 int ret; 761 762 ret = pm_runtime_get_sync(component->dev); 763 if (ret < 0 && ret != -EACCES) { 764 dev_err_ratelimited(component->dev, 765 "pm_runtime_get_sync failed in %s, ret %d\n", 766 __func__, ret); 767 pm_runtime_put_noidle(component->dev); 768 return ret; 769 } 770 771 mutex_lock(&mbhc->lock); 772 773 if (mbhc->cfg->typec_analog_mux) 774 mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD; 775 else 776 mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD; 777 778 /* setup HS detection */ 779 if (mbhc->mbhc_cb->hph_pull_up_control_v2) 780 mbhc->mbhc_cb->hph_pull_up_control_v2(component, 781 mbhc->cfg->typec_analog_mux ? 782 HS_PULLUP_I_OFF : HS_PULLUP_I_DEFAULT); 783 else if (mbhc->mbhc_cb->hph_pull_up_control) 784 mbhc->mbhc_cb->hph_pull_up_control(component, 785 mbhc->cfg->typec_analog_mux ? 786 I_OFF : I_DEFAULT); 787 else 788 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 789 mbhc->cfg->typec_analog_mux ? 0 : 3); 790 791 wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh); 792 wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh); 793 wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1); 794 if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl) 795 mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true); 796 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1); 797 798 /* Plug detect is triggered manually if analog goes through USBCC */ 799 if (mbhc->cfg->typec_analog_mux) 800 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0); 801 else 802 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); 803 804 if (mbhc->cfg->typec_analog_mux) 805 /* Insertion debounce set to 48ms */ 806 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 4); 807 else 808 /* Insertion debounce set to 96ms */ 809 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6); 810 811 /* Button Debounce set to 16ms */ 812 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2); 813 814 /* enable bias */ 815 mbhc->mbhc_cb->mbhc_bias(component, true); 816 /* enable MBHC clock */ 817 if (mbhc->mbhc_cb->clk_setup) 818 mbhc->mbhc_cb->clk_setup(component, 819 mbhc->cfg->typec_analog_mux ? false : true); 820 821 /* program HS_VREF value */ 822 wcd_program_hs_vref(mbhc); 823 824 wcd_program_btn_threshold(mbhc, false); 825 826 mutex_unlock(&mbhc->lock); 827 828 pm_runtime_put_autosuspend(component->dev); 829 830 return 0; 831 } 832 833 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc) 834 { 835 int micbias = 0; 836 837 if (mbhc->mbhc_cb->get_micbias_val) { 838 mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias); 839 } else { 840 u8 vout_ctl = 0; 841 /* Read MBHC Micbias (Mic Bias2) voltage */ 842 vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT); 843 /* Formula for getting micbias from vout 844 * micbias = 1.0V + VOUT_CTL * 50mV 845 */ 846 micbias = 1000 + (vout_ctl * 50); 847 } 848 return micbias; 849 } 850 851 static int wcd_get_voltage_from_adc(u8 val, int micbias) 852 { 853 /* Formula for calculating voltage from ADC 854 * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8 855 */ 856 return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10)); 857 } 858 859 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc) 860 { 861 u8 adc_result; 862 int output_mv; 863 int retry = 3; 864 u8 adc_en; 865 866 /* Pre-requisites for ADC continuous measurement */ 867 /* Read legacy electircal detection and disable */ 868 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); 869 /* Set ADC to continuous measurement */ 870 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1); 871 /* Read ADC Enable bit to restore after adc measurement */ 872 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); 873 /* Disable ADC_ENABLE bit */ 874 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); 875 /* Disable MBHC FSM */ 876 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); 877 /* Set the MUX selection to IN2P */ 878 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P); 879 /* Enable MBHC FSM */ 880 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 881 /* Enable ADC_ENABLE bit */ 882 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1); 883 884 while (retry--) { 885 /* wait for 3 msec before reading ADC result */ 886 usleep_range(3000, 3100); 887 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT); 888 } 889 890 /* Restore ADC Enable */ 891 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); 892 /* Get voltage from ADC result */ 893 output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc)); 894 895 return output_mv; 896 } 897 898 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl) 899 { 900 struct device *dev = mbhc->dev; 901 u8 adc_timeout = 0; 902 u8 adc_complete = 0; 903 u8 adc_result; 904 int retry = 6; 905 int ret; 906 int output_mv = 0; 907 u8 adc_en; 908 909 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); 910 /* Read ADC Enable bit to restore after adc measurement */ 911 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); 912 /* Trigger ADC one time measurement */ 913 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); 914 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); 915 /* Set the appropriate MUX selection */ 916 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl); 917 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 918 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1); 919 920 while (retry--) { 921 /* wait for 600usec to get adc results */ 922 usleep_range(600, 610); 923 924 /* check for ADC Timeout */ 925 adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT); 926 if (adc_timeout) 927 continue; 928 929 /* Read ADC complete bit */ 930 adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE); 931 if (!adc_complete) 932 continue; 933 934 /* Read ADC result */ 935 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT); 936 937 /* Get voltage from ADC result */ 938 output_mv = wcd_get_voltage_from_adc(adc_result, 939 wcd_mbhc_get_micbias(mbhc)); 940 break; 941 } 942 943 /* Restore ADC Enable */ 944 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); 945 946 if (retry <= 0) { 947 dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n", 948 __func__, adc_complete, adc_timeout); 949 ret = -EINVAL; 950 } else { 951 ret = output_mv; 952 } 953 954 return ret; 955 } 956 957 /* To determine if cross connection occurred */ 958 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) 959 { 960 u8 adc_mode, elect_ctl, adc_en, fsm_en; 961 int hphl_adc_res, hphr_adc_res; 962 bool is_cross_conn = false; 963 964 /* If PA is enabled, dont check for cross-connection */ 965 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN)) 966 return -EINVAL; 967 968 /* Read legacy electircal detection and disable */ 969 elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC); 970 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0); 971 972 /* Read and set ADC to single measurement */ 973 adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE); 974 /* Read ADC Enable bit to restore after adc measurement */ 975 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); 976 /* Read FSM status */ 977 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN); 978 979 /* Get adc result for HPH L */ 980 hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L); 981 if (hphl_adc_res < 0) 982 return hphl_adc_res; 983 984 /* Get adc result for HPH R in mV */ 985 hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R); 986 if (hphr_adc_res < 0) 987 return hphr_adc_res; 988 989 if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD || 990 hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD) 991 is_cross_conn = true; 992 993 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); 994 /* Set the MUX selection to Auto */ 995 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); 996 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); 997 /* Restore ADC Enable */ 998 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); 999 /* Restore ADC mode */ 1000 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode); 1001 /* Restore FSM state */ 1002 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en); 1003 /* Restore electrical detection */ 1004 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); 1005 1006 return is_cross_conn; 1007 } 1008 1009 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc) 1010 { 1011 int hs_threshold, micbias_mv; 1012 1013 micbias_mv = wcd_mbhc_get_micbias(mbhc); 1014 if (mbhc->cfg->hs_thr) { 1015 if (mbhc->cfg->micb_mv == micbias_mv) 1016 hs_threshold = mbhc->cfg->hs_thr; 1017 else 1018 hs_threshold = (mbhc->cfg->hs_thr * 1019 micbias_mv) / mbhc->cfg->micb_mv; 1020 } else { 1021 hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * 1022 micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); 1023 } 1024 return hs_threshold; 1025 } 1026 1027 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc) 1028 { 1029 int hph_threshold, micbias_mv; 1030 1031 micbias_mv = wcd_mbhc_get_micbias(mbhc); 1032 if (mbhc->cfg->hph_thr) { 1033 if (mbhc->cfg->micb_mv == micbias_mv) 1034 hph_threshold = mbhc->cfg->hph_thr; 1035 else 1036 hph_threshold = (mbhc->cfg->hph_thr * 1037 micbias_mv) / mbhc->cfg->micb_mv; 1038 } else { 1039 hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV * 1040 micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); 1041 } 1042 return hph_threshold; 1043 } 1044 1045 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc, 1046 enum wcd_mbhc_plug_type plug_type) 1047 { 1048 bool micbias2 = false; 1049 1050 switch (plug_type) { 1051 case MBHC_PLUG_TYPE_HEADPHONE: 1052 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); 1053 break; 1054 case MBHC_PLUG_TYPE_HEADSET: 1055 if (mbhc->mbhc_cb->micbias_enable_status) 1056 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component, 1057 MIC_BIAS_2); 1058 1059 if (!mbhc->is_hs_recording && !micbias2) 1060 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); 1061 break; 1062 default: 1063 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); 1064 break; 1065 1066 } 1067 } 1068 1069 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable) 1070 { 1071 switch (plug_type) { 1072 case MBHC_PLUG_TYPE_HEADSET: 1073 case MBHC_PLUG_TYPE_HEADPHONE: 1074 if (mbhc->mbhc_cb->bcs_enable) 1075 mbhc->mbhc_cb->bcs_enable(mbhc->component, enable); 1076 break; 1077 default: 1078 break; 1079 } 1080 } 1081 1082 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) 1083 1084 { 1085 enum wcd_mbhc_plug_type plug_type; 1086 u32 hph_thr, hs_thr; 1087 1088 hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc); 1089 hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc); 1090 1091 if (adc_result < hph_thr) 1092 plug_type = MBHC_PLUG_TYPE_HEADPHONE; 1093 else if (adc_result > hs_thr) 1094 plug_type = MBHC_PLUG_TYPE_HIGH_HPH; 1095 else 1096 plug_type = MBHC_PLUG_TYPE_HEADSET; 1097 1098 return plug_type; 1099 } 1100 1101 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc) 1102 { 1103 int hs_threshold, micbias_mv; 1104 1105 micbias_mv = wcd_mbhc_get_micbias(mbhc); 1106 if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) { 1107 if (mbhc->cfg->micb_mv == micbias_mv) 1108 hs_threshold = mbhc->cfg->hs_thr; 1109 else 1110 hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv; 1111 } else { 1112 hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) / 1113 WCD_MBHC_ADC_MICBIAS_MV); 1114 } 1115 return hs_threshold; 1116 } 1117 1118 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc) 1119 { 1120 bool is_spl_hs = false; 1121 int output_mv, hs_threshold, hph_threshold; 1122 1123 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) 1124 return false; 1125 1126 /* Bump up MIC_BIAS2 to 2.7V */ 1127 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true); 1128 usleep_range(10000, 10100); 1129 1130 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); 1131 hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc); 1132 hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); 1133 1134 if (!(output_mv > hs_threshold || output_mv < hph_threshold)) 1135 is_spl_hs = true; 1136 1137 /* Back MIC_BIAS2 to 1.8v if the type is not special headset */ 1138 if (!is_spl_hs) { 1139 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false); 1140 /* Add 10ms delay for micbias to settle */ 1141 usleep_range(10000, 10100); 1142 } 1143 1144 return is_spl_hs; 1145 } 1146 1147 static void wcd_correct_swch_plug(struct work_struct *work) 1148 { 1149 struct wcd_mbhc *mbhc; 1150 struct snd_soc_component *component; 1151 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; 1152 unsigned long timeout; 1153 int pt_gnd_mic_swap_cnt = 0; 1154 int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv; 1155 bool is_spl_hs = false; 1156 bool is_pa_on; 1157 int ret; 1158 1159 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); 1160 component = mbhc->component; 1161 1162 ret = pm_runtime_get_sync(component->dev); 1163 if (ret < 0 && ret != -EACCES) { 1164 dev_err_ratelimited(component->dev, 1165 "pm_runtime_get_sync failed in %s, ret %d\n", 1166 __func__, ret); 1167 pm_runtime_put_noidle(component->dev); 1168 return; 1169 } 1170 micbias_mv = wcd_mbhc_get_micbias(mbhc); 1171 hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); 1172 1173 /* Mask ADC COMPLETE interrupt */ 1174 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); 1175 1176 /* Check for cross connection */ 1177 do { 1178 cross_conn = wcd_check_cross_conn(mbhc); 1179 try++; 1180 } while (try < mbhc->swap_thr); 1181 1182 if (cross_conn > 0) { 1183 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; 1184 dev_err(mbhc->dev, "cross connection found, Plug type %d\n", 1185 plug_type); 1186 goto correct_plug_type; 1187 } 1188 1189 /* Find plug type */ 1190 output_mv = wcd_measure_adc_continuous(mbhc); 1191 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); 1192 1193 /* 1194 * Report plug type if it is either headset or headphone 1195 * else start the 3 sec loop 1196 */ 1197 switch (plug_type) { 1198 case MBHC_PLUG_TYPE_HEADPHONE: 1199 wcd_mbhc_find_plug_and_report(mbhc, plug_type); 1200 break; 1201 case MBHC_PLUG_TYPE_HEADSET: 1202 wcd_mbhc_find_plug_and_report(mbhc, plug_type); 1203 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); 1204 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); 1205 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); 1206 break; 1207 default: 1208 break; 1209 } 1210 1211 correct_plug_type: 1212 1213 /* Disable BCS slow insertion detection */ 1214 wcd_mbhc_bcs_enable(mbhc, plug_type, false); 1215 1216 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS); 1217 1218 while (!time_after(jiffies, timeout)) { 1219 if (mbhc->hs_detect_work_stop) { 1220 wcd_micbias_disable(mbhc); 1221 goto exit; 1222 } 1223 1224 msleep(180); 1225 /* 1226 * Use ADC single mode to minimize the chance of missing out 1227 * btn press/release for HEADSET type during correct work. 1228 */ 1229 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); 1230 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); 1231 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); 1232 1233 if (output_mv > hs_threshold && !is_spl_hs) { 1234 is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc); 1235 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); 1236 1237 if (is_spl_hs) { 1238 hs_threshold *= wcd_mbhc_get_micbias(mbhc); 1239 hs_threshold /= micbias_mv; 1240 } 1241 } 1242 1243 if ((output_mv <= hs_threshold) && !is_pa_on) { 1244 /* Check for cross connection*/ 1245 cross_conn = wcd_check_cross_conn(mbhc); 1246 if (cross_conn > 0) { /* cross-connection */ 1247 pt_gnd_mic_swap_cnt++; 1248 if (pt_gnd_mic_swap_cnt < mbhc->swap_thr) 1249 continue; 1250 else 1251 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; 1252 } else if (!cross_conn) { /* no cross connection */ 1253 pt_gnd_mic_swap_cnt = 0; 1254 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); 1255 continue; 1256 } else /* Error if (cross_conn < 0) */ 1257 continue; 1258 1259 if (pt_gnd_mic_swap_cnt == mbhc->swap_thr) { 1260 /* US_EU gpio present, flip switch */ 1261 if (mbhc->cfg->swap_gnd_mic) { 1262 if (mbhc->cfg->swap_gnd_mic(component)) 1263 continue; 1264 } 1265 } 1266 } 1267 1268 /* cable is extension cable */ 1269 if (output_mv > hs_threshold || mbhc->force_linein) 1270 plug_type = MBHC_PLUG_TYPE_HIGH_HPH; 1271 } 1272 1273 wcd_mbhc_bcs_enable(mbhc, plug_type, true); 1274 1275 if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) { 1276 if (is_spl_hs) 1277 plug_type = MBHC_PLUG_TYPE_HEADSET; 1278 else 1279 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); 1280 } 1281 1282 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); 1283 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); 1284 wcd_mbhc_find_plug_and_report(mbhc, plug_type); 1285 1286 /* 1287 * Set DETECTION_DONE bit for HEADSET 1288 * so that btn press/release interrupt can be generated. 1289 * For other plug type, clear the bit. 1290 */ 1291 if (plug_type == MBHC_PLUG_TYPE_HEADSET) 1292 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); 1293 else 1294 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); 1295 1296 if (mbhc->mbhc_cb->mbhc_micbias_control) 1297 wcd_mbhc_adc_update_fsm_source(mbhc, plug_type); 1298 1299 exit: 1300 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) 1301 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE); 1302 1303 /* 1304 * If plug type is corrected from special headset to headphone, 1305 * clear the micbias enable flag, set micbias back to 1.8V and 1306 * disable micbias. 1307 */ 1308 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) { 1309 wcd_micbias_disable(mbhc); 1310 /* 1311 * Enable ADC COMPLETE interrupt for HEADPHONE. 1312 * Btn release may happen after the correct work, ADC COMPLETE 1313 * interrupt needs to be captured to correct plug type. 1314 */ 1315 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr); 1316 } 1317 1318 if (mbhc->mbhc_cb->hph_pull_down_ctrl) 1319 mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); 1320 1321 pm_runtime_put_autosuspend(component->dev); 1322 } 1323 1324 static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) 1325 { 1326 struct wcd_mbhc *mbhc = data; 1327 unsigned long timeout; 1328 int adc_threshold, output_mv, retry = 0; 1329 1330 mutex_lock(&mbhc->lock); 1331 timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); 1332 adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); 1333 1334 do { 1335 retry++; 1336 /* 1337 * read output_mv every 10ms to look for 1338 * any change in IN2_P 1339 */ 1340 usleep_range(10000, 10100); 1341 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); 1342 1343 /* Check for fake removal */ 1344 if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS) 1345 goto exit; 1346 } while (!time_after(jiffies, timeout)); 1347 1348 /* 1349 * ADC COMPLETE and ELEC_REM interrupts are both enabled for 1350 * HEADPHONE, need to reject the ADC COMPLETE interrupt which 1351 * follows ELEC_REM one when HEADPHONE is removed. 1352 */ 1353 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) 1354 mbhc->extn_cable_hph_rem = true; 1355 1356 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); 1357 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); 1358 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); 1359 wcd_mbhc_elec_hs_report_unplug(mbhc); 1360 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); 1361 1362 exit: 1363 mutex_unlock(&mbhc->lock); 1364 return IRQ_HANDLED; 1365 } 1366 1367 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data) 1368 { 1369 struct wcd_mbhc *mbhc = data; 1370 u8 clamp_state; 1371 u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY; 1372 1373 /* 1374 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE, 1375 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one 1376 * when HEADPHONE is removed. 1377 */ 1378 if (mbhc->extn_cable_hph_rem == true) { 1379 mbhc->extn_cable_hph_rem = false; 1380 return IRQ_HANDLED; 1381 } 1382 1383 do { 1384 clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE); 1385 if (clamp_state) 1386 return IRQ_HANDLED; 1387 /* 1388 * check clamp for 120ms but at 30ms chunks to leave 1389 * room for other interrupts to be processed 1390 */ 1391 usleep_range(30000, 30100); 1392 } while (--clamp_retry); 1393 1394 /* 1395 * If current plug is headphone then there is no chance to 1396 * get ADC complete interrupt, so connected cable should be 1397 * headset not headphone. 1398 */ 1399 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { 1400 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); 1401 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); 1402 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET); 1403 return IRQ_HANDLED; 1404 } 1405 1406 return IRQ_HANDLED; 1407 } 1408 1409 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) 1410 { 1411 *zl = mbhc->zl; 1412 *zr = mbhc->zr; 1413 1414 if (*zl && *zr) 1415 return 0; 1416 else 1417 return -EINVAL; 1418 } 1419 EXPORT_SYMBOL(wcd_mbhc_get_impedance); 1420 1421 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type) 1422 { 1423 mbhc->hph_type = hph_type; 1424 } 1425 EXPORT_SYMBOL(wcd_mbhc_set_hph_type); 1426 1427 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc) 1428 { 1429 return mbhc->hph_type; 1430 } 1431 EXPORT_SYMBOL(wcd_mbhc_get_hph_type); 1432 1433 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg, 1434 struct snd_soc_jack *jack) 1435 { 1436 if (!mbhc || !cfg || !jack) 1437 return -EINVAL; 1438 1439 mbhc->cfg = cfg; 1440 mbhc->jack = jack; 1441 1442 return wcd_mbhc_initialise(mbhc); 1443 } 1444 EXPORT_SYMBOL(wcd_mbhc_start); 1445 1446 void wcd_mbhc_stop(struct wcd_mbhc *mbhc) 1447 { 1448 mbhc->current_plug = MBHC_PLUG_TYPE_NONE; 1449 mbhc->hph_status = 0; 1450 disable_irq_nosync(mbhc->intr_ids->hph_left_ocp); 1451 disable_irq_nosync(mbhc->intr_ids->hph_right_ocp); 1452 } 1453 EXPORT_SYMBOL(wcd_mbhc_stop); 1454 1455 int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg) 1456 { 1457 struct device_node *np = dev->of_node; 1458 int ret, i, microvolt; 1459 1460 if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed")) 1461 cfg->hphl_swh = false; 1462 else 1463 cfg->hphl_swh = true; 1464 1465 if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed")) 1466 cfg->gnd_swh = false; 1467 else 1468 cfg->gnd_swh = true; 1469 1470 ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt", 1471 µvolt); 1472 if (ret) 1473 dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n"); 1474 else 1475 cfg->hs_thr = microvolt/1000; 1476 1477 ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt", 1478 µvolt); 1479 if (ret) 1480 dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n"); 1481 else 1482 cfg->hph_thr = microvolt/1000; 1483 1484 ret = of_property_read_u32_array(np, 1485 "qcom,mbhc-buttons-vthreshold-microvolt", 1486 &cfg->btn_high[0], 1487 WCD_MBHC_DEF_BUTTONS); 1488 if (ret) 1489 dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n"); 1490 1491 for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) { 1492 if (ret) /* default voltage */ 1493 cfg->btn_high[i] = 500000; 1494 else 1495 /* Micro to Milli Volts */ 1496 cfg->btn_high[i] = cfg->btn_high[i]/1000; 1497 } 1498 1499 return 0; 1500 } 1501 EXPORT_SYMBOL(wcd_dt_parse_mbhc_data); 1502 1503 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component, 1504 const struct wcd_mbhc_cb *mbhc_cb, 1505 const struct wcd_mbhc_intr *intr_ids, 1506 const struct wcd_mbhc_field *fields, 1507 bool impedance_det_en) 1508 { 1509 struct device *dev = component->dev; 1510 struct wcd_mbhc *mbhc; 1511 int ret; 1512 1513 if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) { 1514 dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__); 1515 return ERR_PTR(-EINVAL); 1516 } 1517 1518 mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL); 1519 if (!mbhc) 1520 return ERR_PTR(-ENOMEM); 1521 1522 mbhc->component = component; 1523 mbhc->dev = dev; 1524 mbhc->intr_ids = intr_ids; 1525 mbhc->mbhc_cb = mbhc_cb; 1526 mbhc->fields = fields; 1527 mbhc->mbhc_detection_logic = WCD_DETECTION_ADC; 1528 1529 if (mbhc_cb->compute_impedance) 1530 mbhc->impedance_detect = impedance_det_en; 1531 1532 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn); 1533 1534 mutex_init(&mbhc->lock); 1535 1536 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); 1537 INIT_WORK(&mbhc->mbhc_plug_detect_work, mbhc_plug_detect_fn); 1538 1539 ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL, 1540 wcd_mbhc_mech_plug_detect_irq, 1541 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1542 "mbhc sw intr", mbhc); 1543 if (ret) 1544 goto err_free_mbhc; 1545 1546 ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL, 1547 wcd_mbhc_btn_press_handler, 1548 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1549 "Button Press detect", mbhc); 1550 if (ret) 1551 goto err_free_sw_intr; 1552 1553 ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL, 1554 wcd_mbhc_btn_release_handler, 1555 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1556 "Button Release detect", mbhc); 1557 if (ret) 1558 goto err_free_btn_press_intr; 1559 1560 ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL, 1561 wcd_mbhc_adc_hs_ins_irq, 1562 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1563 "Elect Insert", mbhc); 1564 if (ret) 1565 goto err_free_btn_release_intr; 1566 1567 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); 1568 1569 ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL, 1570 wcd_mbhc_adc_hs_rem_irq, 1571 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1572 "Elect Remove", mbhc); 1573 if (ret) 1574 goto err_free_hs_ins_intr; 1575 1576 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); 1577 1578 ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL, 1579 wcd_mbhc_hphl_ocp_irq, 1580 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1581 "HPH_L OCP detect", mbhc); 1582 if (ret) 1583 goto err_free_hs_rem_intr; 1584 1585 ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL, 1586 wcd_mbhc_hphr_ocp_irq, 1587 IRQF_ONESHOT | IRQF_TRIGGER_RISING, 1588 "HPH_R OCP detect", mbhc); 1589 if (ret) 1590 goto err_free_hph_left_ocp; 1591 1592 return mbhc; 1593 1594 err_free_hph_left_ocp: 1595 free_irq(mbhc->intr_ids->hph_left_ocp, mbhc); 1596 err_free_hs_rem_intr: 1597 free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc); 1598 err_free_hs_ins_intr: 1599 free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc); 1600 err_free_btn_release_intr: 1601 free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc); 1602 err_free_btn_press_intr: 1603 free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc); 1604 err_free_sw_intr: 1605 free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); 1606 err_free_mbhc: 1607 kfree(mbhc); 1608 1609 dev_err(dev, "Failed to request mbhc interrupts %d\n", ret); 1610 1611 return ERR_PTR(ret); 1612 } 1613 EXPORT_SYMBOL(wcd_mbhc_init); 1614 1615 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) 1616 { 1617 free_irq(mbhc->intr_ids->hph_right_ocp, mbhc); 1618 free_irq(mbhc->intr_ids->hph_left_ocp, mbhc); 1619 free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc); 1620 free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc); 1621 free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc); 1622 free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc); 1623 free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); 1624 1625 mutex_lock(&mbhc->lock); 1626 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); 1627 cancel_work_sync(&mbhc->mbhc_plug_detect_work); 1628 mutex_unlock(&mbhc->lock); 1629 1630 kfree(mbhc); 1631 } 1632 EXPORT_SYMBOL(wcd_mbhc_deinit); 1633 1634 static int __init mbhc_init(void) 1635 { 1636 return 0; 1637 } 1638 1639 static void __exit mbhc_exit(void) 1640 { 1641 } 1642 1643 module_init(mbhc_init); 1644 module_exit(mbhc_exit); 1645 1646 MODULE_DESCRIPTION("wcd MBHC v2 module"); 1647 MODULE_LICENSE("GPL"); 1648