0001
0002
0003
0004 #include <linux/module.h>
0005 #include <linux/init.h>
0006 #include <linux/slab.h>
0007 #include <linux/device.h>
0008 #include <linux/pm_runtime.h>
0009 #include <linux/printk.h>
0010 #include <linux/delay.h>
0011 #include <linux/kernel.h>
0012 #include <sound/soc.h>
0013 #include <sound/jack.h>
0014 #include "wcd-mbhc-v2.h"
0015
0016 #define HS_DETECT_PLUG_TIME_MS (3 * 1000)
0017 #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
0018 #define GND_MIC_SWAP_THRESHOLD 4
0019 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100
0020 #define HPHL_CROSS_CONN_THRESHOLD 100
0021 #define HS_VREF_MIN_VAL 1400
0022 #define FAKE_REM_RETRY_ATTEMPTS 3
0023 #define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700
0024 #define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75
0025 #define WCD_MBHC_ADC_MICBIAS_MV 1800
0026 #define WCD_MBHC_FAKE_INS_RETRY 4
0027
0028 #define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \
0029 SND_JACK_MECHANICAL)
0030
0031 #define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
0032 SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
0033 SND_JACK_BTN_4 | SND_JACK_BTN_5)
0034
0035 enum wcd_mbhc_adc_mux_ctl {
0036 MUX_CTL_AUTO = 0,
0037 MUX_CTL_IN2P,
0038 MUX_CTL_IN3P,
0039 MUX_CTL_IN4P,
0040 MUX_CTL_HPH_L,
0041 MUX_CTL_HPH_R,
0042 MUX_CTL_NONE,
0043 };
0044
0045 struct wcd_mbhc {
0046 struct device *dev;
0047 struct snd_soc_component *component;
0048 struct snd_soc_jack *jack;
0049 struct wcd_mbhc_config *cfg;
0050 const struct wcd_mbhc_cb *mbhc_cb;
0051 const struct wcd_mbhc_intr *intr_ids;
0052 struct wcd_mbhc_field *fields;
0053
0054 struct delayed_work mbhc_btn_dwork;
0055
0056 struct work_struct correct_plug_swch;
0057 struct mutex lock;
0058 int buttons_pressed;
0059 u32 hph_status;
0060 u8 current_plug;
0061 bool is_btn_press;
0062 bool in_swch_irq_handler;
0063 bool hs_detect_work_stop;
0064 bool is_hs_recording;
0065 bool extn_cable_hph_rem;
0066 bool force_linein;
0067 bool impedance_detect;
0068 unsigned long event_state;
0069 unsigned long jiffies_atreport;
0070
0071 uint32_t zl, zr;
0072
0073 enum wcd_mbhc_hph_type hph_type;
0074
0075 int mbhc_detection_logic;
0076 };
0077
0078 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc,
0079 int field, int val)
0080 {
0081 if (!mbhc->fields[field].reg)
0082 return 0;
0083
0084 return snd_soc_component_write_field(mbhc->component,
0085 mbhc->fields[field].reg,
0086 mbhc->fields[field].mask, val);
0087 }
0088
0089 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field)
0090 {
0091 if (!mbhc->fields[field].reg)
0092 return 0;
0093
0094 return snd_soc_component_read_field(mbhc->component,
0095 mbhc->fields[field].reg,
0096 mbhc->fields[field].mask);
0097 }
0098
0099 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
0100 {
0101 u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
0102
0103 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val);
0104 }
0105
0106 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
0107 {
0108 struct snd_soc_component *component = mbhc->component;
0109
0110 mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low,
0111 mbhc->cfg->btn_high,
0112 mbhc->cfg->num_btn, micbias);
0113 }
0114
0115 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc,
0116 const enum wcd_mbhc_cs_mb_en_flag cs_mb_en)
0117 {
0118
0119
0120
0121
0122
0123
0124
0125 if (mbhc->mbhc_cb->mbhc_micbias_control)
0126 return;
0127
0128 switch (cs_mb_en) {
0129 case WCD_MBHC_EN_CS:
0130 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
0131 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0132
0133 wcd_program_btn_threshold(mbhc, false);
0134 break;
0135 case WCD_MBHC_EN_MB:
0136 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0137 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0138
0139 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2);
0140
0141 wcd_program_btn_threshold(mbhc, true);
0142 break;
0143 case WCD_MBHC_EN_PULLUP:
0144 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0145 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0146 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1);
0147
0148 wcd_program_btn_threshold(mbhc, true);
0149 break;
0150 case WCD_MBHC_EN_NONE:
0151 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0152 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0153 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
0154 break;
0155 default:
0156 dev_err(mbhc->dev, "%s: Invalid parameter", __func__);
0157 break;
0158 }
0159 }
0160
0161 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event)
0162 {
0163
0164 struct snd_soc_component *component;
0165 bool micbias2 = false;
0166
0167 if (!mbhc)
0168 return 0;
0169
0170 component = mbhc->component;
0171
0172 if (mbhc->mbhc_cb->micbias_enable_status)
0173 micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2);
0174
0175 switch (event) {
0176
0177 case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
0178 mbhc->is_hs_recording = true;
0179 break;
0180 case WCD_EVENT_POST_MICBIAS_2_ON:
0181
0182 if (mbhc->mbhc_cb->mbhc_micbias_control) {
0183 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
0184 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0185 } else {
0186 mbhc->is_hs_recording = true;
0187 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0188 }
0189 break;
0190 case WCD_EVENT_PRE_MICBIAS_2_OFF:
0191
0192
0193
0194
0195
0196 if (mbhc->mbhc_cb->mbhc_micbias_control) {
0197 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
0198 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0199 }
0200 break;
0201
0202 case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
0203 mbhc->is_hs_recording = false;
0204 break;
0205 case WCD_EVENT_POST_MICBIAS_2_OFF:
0206 if (!mbhc->mbhc_cb->mbhc_micbias_control)
0207 mbhc->is_hs_recording = false;
0208
0209
0210 if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
0211 (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state)))
0212
0213 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
0214 else
0215
0216 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
0217
0218 break;
0219 case WCD_EVENT_POST_HPHL_PA_OFF:
0220 clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
0221
0222
0223 if (micbias2)
0224
0225 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0226 else
0227
0228 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
0229 break;
0230 case WCD_EVENT_POST_HPHR_PA_OFF:
0231 clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
0232
0233 if (micbias2)
0234
0235 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0236 else
0237
0238 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
0239 break;
0240 case WCD_EVENT_PRE_HPHL_PA_ON:
0241 set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
0242
0243 if (micbias2)
0244
0245 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0246 else
0247
0248 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
0249 break;
0250 case WCD_EVENT_PRE_HPHR_PA_ON:
0251 set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
0252
0253 if (micbias2)
0254
0255 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0256 else
0257
0258 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
0259 break;
0260 default:
0261 break;
0262 }
0263 return 0;
0264 }
0265 EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify);
0266
0267 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
0268 {
0269 return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
0270 }
0271
0272 static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
0273 {
0274 struct snd_soc_component *component = mbhc->component;
0275
0276 if (mbhc->mbhc_cb->mbhc_micbias_control)
0277 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
0278
0279 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
0280 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false);
0281
0282 if (mbhc->mbhc_cb->set_micbias_value) {
0283 mbhc->mbhc_cb->set_micbias_value(component);
0284 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
0285 }
0286 }
0287
0288 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc,
0289 enum snd_jack_types jack_type)
0290 {
0291 mbhc->hph_status &= ~jack_type;
0292
0293
0294
0295
0296 if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) {
0297 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
0298 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
0299 }
0300
0301 wcd_micbias_disable(mbhc);
0302 mbhc->hph_type = WCD_MBHC_HPH_NONE;
0303 mbhc->zl = mbhc->zr = 0;
0304 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK);
0305 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
0306 mbhc->force_linein = false;
0307 }
0308
0309 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc)
0310 {
0311
0312 if (!mbhc->impedance_detect)
0313 return;
0314
0315 if (mbhc->cfg->linein_th != 0) {
0316 u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
0317
0318
0319 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0320 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
0321 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0322 mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr);
0323 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
0324 }
0325 }
0326
0327 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc,
0328 enum snd_jack_types jack_type)
0329 {
0330 bool is_pa_on;
0331
0332
0333
0334
0335
0336 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
0337 jack_type == SND_JACK_HEADPHONE)
0338 mbhc->hph_status &= ~SND_JACK_HEADSET;
0339
0340
0341 switch (jack_type) {
0342 case SND_JACK_HEADPHONE:
0343 mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
0344 break;
0345 case SND_JACK_HEADSET:
0346 mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
0347 mbhc->jiffies_atreport = jiffies;
0348 break;
0349 case SND_JACK_LINEOUT:
0350 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
0351 break;
0352 default:
0353 break;
0354 }
0355
0356
0357 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
0358
0359 if (!is_pa_on) {
0360 wcd_mbhc_compute_impedance(mbhc);
0361 if ((mbhc->zl > mbhc->cfg->linein_th) &&
0362 (mbhc->zr > mbhc->cfg->linein_th) &&
0363 (jack_type == SND_JACK_HEADPHONE)) {
0364 jack_type = SND_JACK_LINEOUT;
0365 mbhc->force_linein = true;
0366 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
0367 if (mbhc->hph_status) {
0368 mbhc->hph_status &= ~(SND_JACK_HEADSET |
0369 SND_JACK_LINEOUT);
0370 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
0371 WCD_MBHC_JACK_MASK);
0372 }
0373 }
0374 }
0375
0376
0377
0378
0379
0380
0381 if (is_pa_on && mbhc->force_linein) {
0382 jack_type = SND_JACK_LINEOUT;
0383 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
0384 if (mbhc->hph_status) {
0385 mbhc->hph_status &= ~(SND_JACK_HEADSET |
0386 SND_JACK_LINEOUT);
0387 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
0388 WCD_MBHC_JACK_MASK);
0389 }
0390 }
0391
0392 mbhc->hph_status |= jack_type;
0393
0394 if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control)
0395 mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false);
0396
0397 snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL),
0398 WCD_MBHC_JACK_MASK);
0399 }
0400
0401 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
0402 enum snd_jack_types jack_type)
0403 {
0404
0405 WARN_ON(!mutex_is_locked(&mbhc->lock));
0406
0407 if (!insertion)
0408 wcd_mbhc_report_plug_removal(mbhc, jack_type);
0409 else
0410 wcd_mbhc_report_plug_insertion(mbhc, jack_type);
0411
0412 }
0413
0414 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
0415 struct work_struct *work)
0416 {
0417 mbhc->hs_detect_work_stop = true;
0418 mutex_unlock(&mbhc->lock);
0419 cancel_work_sync(work);
0420 mutex_lock(&mbhc->lock);
0421 }
0422
0423 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc)
0424 {
0425
0426 wcd_cancel_btn_work(mbhc);
0427
0428 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
0429 }
0430
0431 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
0432 {
0433 wcd_mbhc_cancel_pending_work(mbhc);
0434
0435 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
0436
0437
0438
0439
0440 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
0441 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE);
0442
0443 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0444 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3);
0445
0446
0447 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
0448 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
0449 }
0450
0451 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
0452 enum wcd_mbhc_plug_type plug_type)
0453 {
0454 if (mbhc->current_plug == plug_type)
0455 return;
0456
0457 mutex_lock(&mbhc->lock);
0458
0459 switch (plug_type) {
0460 case MBHC_PLUG_TYPE_HEADPHONE:
0461 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
0462 break;
0463 case MBHC_PLUG_TYPE_HEADSET:
0464 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
0465 break;
0466 case MBHC_PLUG_TYPE_HIGH_HPH:
0467 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
0468 break;
0469 case MBHC_PLUG_TYPE_GND_MIC_SWAP:
0470 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
0471 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
0472 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
0473 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
0474 break;
0475 default:
0476 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
0477 mbhc->current_plug, plug_type);
0478 break;
0479 }
0480 mutex_unlock(&mbhc->lock);
0481 }
0482
0483 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
0484 struct work_struct *work)
0485 {
0486 WARN_ON(!mutex_is_locked(&mbhc->lock));
0487 mbhc->hs_detect_work_stop = false;
0488 schedule_work(work);
0489 }
0490
0491 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
0492 {
0493 struct snd_soc_component *component = mbhc->component;
0494
0495 WARN_ON(!mutex_is_locked(&mbhc->lock));
0496
0497 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
0498 mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
0499
0500 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
0501
0502 if (mbhc->mbhc_cb->mbhc_micbias_control) {
0503 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
0504 MICB_ENABLE);
0505 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
0506 }
0507 }
0508
0509 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
0510 {
0511 struct snd_soc_component *component;
0512 enum snd_jack_types jack_type;
0513 struct wcd_mbhc *mbhc = data;
0514 bool detection_type;
0515
0516 component = mbhc->component;
0517 mutex_lock(&mbhc->lock);
0518
0519 mbhc->in_swch_irq_handler = true;
0520
0521 wcd_mbhc_cancel_pending_work(mbhc);
0522
0523 detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE);
0524
0525
0526 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type);
0527
0528
0529 if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
0530 mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
0531
0532 if (detection_type) {
0533 if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
0534 goto exit;
0535
0536 mbhc->mbhc_cb->mbhc_bias(component, true);
0537 mbhc->is_btn_press = false;
0538 wcd_mbhc_adc_detect_plug_type(mbhc);
0539 } else {
0540
0541 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0542 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0543 mbhc->extn_cable_hph_rem = false;
0544
0545 if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE)
0546 goto exit;
0547
0548 mbhc->is_btn_press = false;
0549 switch (mbhc->current_plug) {
0550 case MBHC_PLUG_TYPE_HEADPHONE:
0551 jack_type = SND_JACK_HEADPHONE;
0552 break;
0553 case MBHC_PLUG_TYPE_HEADSET:
0554 jack_type = SND_JACK_HEADSET;
0555 break;
0556 case MBHC_PLUG_TYPE_HIGH_HPH:
0557 if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC)
0558 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0);
0559 jack_type = SND_JACK_LINEOUT;
0560 break;
0561 case MBHC_PLUG_TYPE_GND_MIC_SWAP:
0562 dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n");
0563 goto exit;
0564 default:
0565 dev_err(mbhc->dev, "Invalid current plug: %d\n",
0566 mbhc->current_plug);
0567 goto exit;
0568 }
0569 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
0570 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
0571 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
0572 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
0573 wcd_mbhc_report_plug(mbhc, 0, jack_type);
0574 }
0575
0576 exit:
0577 mbhc->in_swch_irq_handler = false;
0578 mutex_unlock(&mbhc->lock);
0579 return IRQ_HANDLED;
0580 }
0581
0582 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
0583 {
0584 int mask = 0;
0585 int btn;
0586
0587 btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT);
0588
0589 switch (btn) {
0590 case 0:
0591 mask = SND_JACK_BTN_0;
0592 break;
0593 case 1:
0594 mask = SND_JACK_BTN_1;
0595 break;
0596 case 2:
0597 mask = SND_JACK_BTN_2;
0598 break;
0599 case 3:
0600 mask = SND_JACK_BTN_3;
0601 break;
0602 case 4:
0603 mask = SND_JACK_BTN_4;
0604 break;
0605 case 5:
0606 mask = SND_JACK_BTN_5;
0607 break;
0608 default:
0609 break;
0610 }
0611
0612 return mask;
0613 }
0614
0615 static void wcd_btn_long_press_fn(struct work_struct *work)
0616 {
0617 struct delayed_work *dwork = to_delayed_work(work);
0618 struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
0619
0620 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
0621 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
0622 mbhc->buttons_pressed);
0623 }
0624
0625 static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
0626 {
0627 struct wcd_mbhc *mbhc = data;
0628 int mask;
0629 unsigned long msec_val;
0630
0631 mutex_lock(&mbhc->lock);
0632 wcd_cancel_btn_work(mbhc);
0633 mbhc->is_btn_press = true;
0634 msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
0635
0636
0637 if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN)
0638 goto done;
0639
0640
0641 if (mbhc->in_swch_irq_handler)
0642 goto done;
0643
0644
0645 if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET)
0646 goto done;
0647
0648 mask = wcd_mbhc_get_button_mask(mbhc);
0649 mbhc->buttons_pressed |= mask;
0650 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0)
0651 WARN(1, "Button pressed twice without release event\n");
0652 done:
0653 mutex_unlock(&mbhc->lock);
0654 return IRQ_HANDLED;
0655 }
0656
0657 static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data)
0658 {
0659 struct wcd_mbhc *mbhc = data;
0660 int ret;
0661
0662 mutex_lock(&mbhc->lock);
0663 if (mbhc->is_btn_press)
0664 mbhc->is_btn_press = false;
0665 else
0666 goto exit;
0667
0668 if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK))
0669 goto exit;
0670
0671 ret = wcd_cancel_btn_work(mbhc);
0672 if (ret == 0) {
0673 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
0674 } else {
0675 if (!mbhc->in_swch_irq_handler) {
0676
0677 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
0678 mbhc->buttons_pressed);
0679 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
0680 }
0681 }
0682 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
0683 exit:
0684 mutex_unlock(&mbhc->lock);
0685
0686 return IRQ_HANDLED;
0687 }
0688
0689 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr)
0690 {
0691
0692
0693 dev_err(mbhc->dev, "MBHC Over Current on %s detected\n",
0694 hphr ? "HPHR" : "HPHL");
0695
0696 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0);
0697 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1);
0698
0699 return IRQ_HANDLED;
0700 }
0701
0702 static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
0703 {
0704 return wcd_mbhc_hph_ocp_irq(data, false);
0705 }
0706
0707 static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
0708 {
0709 return wcd_mbhc_hph_ocp_irq(data, true);
0710 }
0711
0712 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
0713 {
0714 struct snd_soc_component *component = mbhc->component;
0715 int ret;
0716
0717 ret = pm_runtime_resume_and_get(component->dev);
0718 if (ret < 0 && ret != -EACCES) {
0719 dev_err_ratelimited(component->dev,
0720 "pm_runtime_resume_and_get failed in %s, ret %d\n",
0721 __func__, ret);
0722 return ret;
0723 }
0724
0725 mutex_lock(&mbhc->lock);
0726
0727
0728 if (mbhc->mbhc_cb->hph_pull_up_control_v2)
0729 mbhc->mbhc_cb->hph_pull_up_control_v2(component,
0730 HS_PULLUP_I_DEFAULT);
0731 else if (mbhc->mbhc_cb->hph_pull_up_control)
0732 mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT);
0733 else
0734 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
0735
0736 wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh);
0737 wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh);
0738 wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
0739 if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
0740 mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true);
0741 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
0742
0743 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
0744
0745
0746 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
0747
0748
0749 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
0750
0751
0752 mbhc->mbhc_cb->mbhc_bias(component, true);
0753
0754 if (mbhc->mbhc_cb->clk_setup)
0755 mbhc->mbhc_cb->clk_setup(component, true);
0756
0757
0758 wcd_program_hs_vref(mbhc);
0759
0760 wcd_program_btn_threshold(mbhc, false);
0761
0762 mutex_unlock(&mbhc->lock);
0763
0764 pm_runtime_mark_last_busy(component->dev);
0765 pm_runtime_put_autosuspend(component->dev);
0766
0767 return 0;
0768 }
0769
0770 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
0771 {
0772 int micbias = 0;
0773
0774 if (mbhc->mbhc_cb->get_micbias_val) {
0775 mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias);
0776 } else {
0777 u8 vout_ctl = 0;
0778
0779 vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT);
0780
0781
0782
0783 micbias = 1000 + (vout_ctl * 50);
0784 }
0785 return micbias;
0786 }
0787
0788 static int wcd_get_voltage_from_adc(u8 val, int micbias)
0789 {
0790
0791
0792
0793 return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
0794 }
0795
0796 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
0797 {
0798 u8 adc_result;
0799 int output_mv;
0800 int retry = 3;
0801 u8 adc_en;
0802
0803
0804
0805 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
0806
0807 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1);
0808
0809 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
0810
0811 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
0812
0813 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0814
0815 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
0816
0817 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0818
0819 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
0820
0821 while (retry--) {
0822
0823 usleep_range(3000, 3100);
0824 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
0825 }
0826
0827
0828 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
0829
0830 output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc));
0831
0832 return output_mv;
0833 }
0834
0835 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
0836 {
0837 struct device *dev = mbhc->dev;
0838 u8 adc_timeout = 0;
0839 u8 adc_complete = 0;
0840 u8 adc_result;
0841 int retry = 6;
0842 int ret;
0843 int output_mv = 0;
0844 u8 adc_en;
0845
0846 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
0847
0848 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
0849
0850 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
0851 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0852
0853 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl);
0854 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0855 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
0856
0857 while (retry--) {
0858
0859 usleep_range(600, 610);
0860
0861
0862 adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT);
0863 if (adc_timeout)
0864 continue;
0865
0866
0867 adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE);
0868 if (!adc_complete)
0869 continue;
0870
0871
0872 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
0873
0874
0875 output_mv = wcd_get_voltage_from_adc(adc_result,
0876 wcd_mbhc_get_micbias(mbhc));
0877 break;
0878 }
0879
0880
0881 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
0882
0883 if (retry <= 0) {
0884 dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n",
0885 __func__, adc_complete, adc_timeout);
0886 ret = -EINVAL;
0887 } else {
0888 ret = output_mv;
0889 }
0890
0891 return ret;
0892 }
0893
0894
0895 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
0896 {
0897 u8 adc_mode, elect_ctl, adc_en, fsm_en;
0898 int hphl_adc_res, hphr_adc_res;
0899 bool is_cross_conn = false;
0900
0901
0902 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
0903 return -EINVAL;
0904
0905
0906 elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC);
0907 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
0908
0909
0910 adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE);
0911
0912 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
0913
0914 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
0915
0916
0917 hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
0918 if (hphl_adc_res < 0)
0919 return hphl_adc_res;
0920
0921
0922 hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
0923 if (hphr_adc_res < 0)
0924 return hphr_adc_res;
0925
0926 if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD ||
0927 hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD)
0928 is_cross_conn = true;
0929
0930 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0931
0932 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
0933 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0934
0935 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
0936
0937 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode);
0938
0939 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
0940
0941 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
0942
0943 return is_cross_conn;
0944 }
0945
0946 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc)
0947 {
0948 int hs_threshold, micbias_mv;
0949
0950 micbias_mv = wcd_mbhc_get_micbias(mbhc);
0951 if (mbhc->cfg->hs_thr) {
0952 if (mbhc->cfg->micb_mv == micbias_mv)
0953 hs_threshold = mbhc->cfg->hs_thr;
0954 else
0955 hs_threshold = (mbhc->cfg->hs_thr *
0956 micbias_mv) / mbhc->cfg->micb_mv;
0957 } else {
0958 hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
0959 micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
0960 }
0961 return hs_threshold;
0962 }
0963
0964 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc)
0965 {
0966 int hph_threshold, micbias_mv;
0967
0968 micbias_mv = wcd_mbhc_get_micbias(mbhc);
0969 if (mbhc->cfg->hph_thr) {
0970 if (mbhc->cfg->micb_mv == micbias_mv)
0971 hph_threshold = mbhc->cfg->hph_thr;
0972 else
0973 hph_threshold = (mbhc->cfg->hph_thr *
0974 micbias_mv) / mbhc->cfg->micb_mv;
0975 } else {
0976 hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV *
0977 micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
0978 }
0979 return hph_threshold;
0980 }
0981
0982 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
0983 enum wcd_mbhc_plug_type plug_type)
0984 {
0985 bool micbias2 = false;
0986
0987 switch (plug_type) {
0988 case MBHC_PLUG_TYPE_HEADPHONE:
0989 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0990 break;
0991 case MBHC_PLUG_TYPE_HEADSET:
0992 if (mbhc->mbhc_cb->micbias_enable_status)
0993 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component,
0994 MIC_BIAS_2);
0995
0996 if (!mbhc->is_hs_recording && !micbias2)
0997 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0998 break;
0999 default:
1000 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1001 break;
1002
1003 }
1004 }
1005
1006 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable)
1007 {
1008 switch (plug_type) {
1009 case MBHC_PLUG_TYPE_HEADSET:
1010 case MBHC_PLUG_TYPE_HEADPHONE:
1011 if (mbhc->mbhc_cb->bcs_enable)
1012 mbhc->mbhc_cb->bcs_enable(mbhc->component, enable);
1013 break;
1014 default:
1015 break;
1016 }
1017 }
1018
1019 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
1020
1021 {
1022 enum wcd_mbhc_plug_type plug_type;
1023 u32 hph_thr, hs_thr;
1024
1025 hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc);
1026 hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc);
1027
1028 if (adc_result < hph_thr)
1029 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1030 else if (adc_result > hs_thr)
1031 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1032 else
1033 plug_type = MBHC_PLUG_TYPE_HEADSET;
1034
1035 return plug_type;
1036 }
1037
1038 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1039 {
1040 int hs_threshold, micbias_mv;
1041
1042 micbias_mv = wcd_mbhc_get_micbias(mbhc);
1043 if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) {
1044 if (mbhc->cfg->micb_mv == micbias_mv)
1045 hs_threshold = mbhc->cfg->hs_thr;
1046 else
1047 hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1048 } else {
1049 hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) /
1050 WCD_MBHC_ADC_MICBIAS_MV);
1051 }
1052 return hs_threshold;
1053 }
1054
1055 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1056 {
1057 bool is_spl_hs = false;
1058 int output_mv, hs_threshold, hph_threshold;
1059
1060 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1061 return false;
1062
1063
1064 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true);
1065 usleep_range(10000, 10100);
1066
1067 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1068 hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc);
1069 hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc);
1070
1071 if (!(output_mv > hs_threshold || output_mv < hph_threshold))
1072 is_spl_hs = true;
1073
1074
1075 if (!is_spl_hs) {
1076 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false);
1077
1078 usleep_range(10000, 10100);
1079 }
1080
1081 return is_spl_hs;
1082 }
1083
1084 static void wcd_correct_swch_plug(struct work_struct *work)
1085 {
1086 struct wcd_mbhc *mbhc;
1087 struct snd_soc_component *component;
1088 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
1089 unsigned long timeout;
1090 int pt_gnd_mic_swap_cnt = 0;
1091 int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv;
1092 bool is_spl_hs = false;
1093 bool is_pa_on;
1094 int ret;
1095
1096 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1097 component = mbhc->component;
1098
1099 ret = pm_runtime_resume_and_get(component->dev);
1100 if (ret < 0 && ret != -EACCES) {
1101 dev_err_ratelimited(component->dev,
1102 "pm_runtime_resume_and_get failed in %s, ret %d\n",
1103 __func__, ret);
1104 return;
1105 }
1106 micbias_mv = wcd_mbhc_get_micbias(mbhc);
1107 hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1108
1109
1110 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1111
1112
1113 do {
1114 cross_conn = wcd_check_cross_conn(mbhc);
1115 try++;
1116 } while (try < GND_MIC_SWAP_THRESHOLD);
1117
1118 if (cross_conn > 0) {
1119 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1120 dev_err(mbhc->dev, "cross connection found, Plug type %d\n",
1121 plug_type);
1122 goto correct_plug_type;
1123 }
1124
1125
1126 output_mv = wcd_measure_adc_continuous(mbhc);
1127 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1128
1129
1130
1131
1132
1133 switch (plug_type) {
1134 case MBHC_PLUG_TYPE_HEADPHONE:
1135 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1136 break;
1137 case MBHC_PLUG_TYPE_HEADSET:
1138 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1139 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1140 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1141 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1142 break;
1143 default:
1144 break;
1145 }
1146
1147 correct_plug_type:
1148
1149
1150 wcd_mbhc_bcs_enable(mbhc, plug_type, false);
1151
1152 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1153
1154 while (!time_after(jiffies, timeout)) {
1155 if (mbhc->hs_detect_work_stop) {
1156 wcd_micbias_disable(mbhc);
1157 goto exit;
1158 }
1159
1160 msleep(180);
1161
1162
1163
1164
1165 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1166 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1167 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
1168
1169 if (output_mv > hs_threshold && !is_spl_hs) {
1170 is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc);
1171 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1172
1173 if (is_spl_hs) {
1174 hs_threshold *= wcd_mbhc_get_micbias(mbhc);
1175 hs_threshold /= micbias_mv;
1176 }
1177 }
1178
1179 if ((output_mv <= hs_threshold) && !is_pa_on) {
1180
1181 cross_conn = wcd_check_cross_conn(mbhc);
1182 if (cross_conn > 0) {
1183 pt_gnd_mic_swap_cnt++;
1184 if (pt_gnd_mic_swap_cnt < GND_MIC_SWAP_THRESHOLD)
1185 continue;
1186 else
1187 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1188 } else if (!cross_conn) {
1189 pt_gnd_mic_swap_cnt = 0;
1190 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1191 continue;
1192 } else if (cross_conn < 0)
1193 continue;
1194
1195 if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) {
1196
1197 if (mbhc->cfg->swap_gnd_mic) {
1198 if (mbhc->cfg->swap_gnd_mic(component, true))
1199 continue;
1200 }
1201 }
1202 }
1203
1204
1205 if (output_mv > hs_threshold || mbhc->force_linein)
1206 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1207 }
1208
1209 wcd_mbhc_bcs_enable(mbhc, plug_type, true);
1210
1211 if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
1212 if (is_spl_hs)
1213 plug_type = MBHC_PLUG_TYPE_HEADSET;
1214 else
1215 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1216 }
1217
1218 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1219 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1220 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1221
1222
1223
1224
1225
1226
1227 if (plug_type == MBHC_PLUG_TYPE_HEADSET)
1228 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1229 else
1230 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1231
1232 if (mbhc->mbhc_cb->mbhc_micbias_control)
1233 wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
1234
1235 exit:
1236 if (mbhc->mbhc_cb->mbhc_micbias_control)
1237 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
1238
1239
1240
1241
1242
1243
1244 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
1245 wcd_micbias_disable(mbhc);
1246
1247
1248
1249
1250
1251 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
1252 }
1253
1254 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1255 mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
1256
1257 pm_runtime_mark_last_busy(component->dev);
1258 pm_runtime_put_autosuspend(component->dev);
1259 }
1260
1261 static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
1262 {
1263 struct wcd_mbhc *mbhc = data;
1264 unsigned long timeout;
1265 int adc_threshold, output_mv, retry = 0;
1266
1267 mutex_lock(&mbhc->lock);
1268 timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
1269 adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1270
1271 do {
1272 retry++;
1273
1274
1275
1276
1277 usleep_range(10000, 10100);
1278 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1279
1280
1281 if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS)
1282 goto exit;
1283 } while (!time_after(jiffies, timeout));
1284
1285
1286
1287
1288
1289
1290 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
1291 mbhc->extn_cable_hph_rem = true;
1292
1293 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1294 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1295 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1296 wcd_mbhc_elec_hs_report_unplug(mbhc);
1297 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1298
1299 exit:
1300 mutex_unlock(&mbhc->lock);
1301 return IRQ_HANDLED;
1302 }
1303
1304 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
1305 {
1306 struct wcd_mbhc *mbhc = data;
1307 u8 clamp_state;
1308 u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
1309
1310
1311
1312
1313
1314
1315 if (mbhc->extn_cable_hph_rem == true) {
1316 mbhc->extn_cable_hph_rem = false;
1317 return IRQ_HANDLED;
1318 }
1319
1320 do {
1321 clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE);
1322 if (clamp_state)
1323 return IRQ_HANDLED;
1324
1325
1326
1327
1328 usleep_range(30000, 30100);
1329 } while (--clamp_retry);
1330
1331
1332
1333
1334
1335
1336 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1337 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1338 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1339 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
1340 return IRQ_HANDLED;
1341 }
1342
1343 return IRQ_HANDLED;
1344 }
1345
1346 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
1347 {
1348 *zl = mbhc->zl;
1349 *zr = mbhc->zr;
1350
1351 if (*zl && *zr)
1352 return 0;
1353 else
1354 return -EINVAL;
1355 }
1356 EXPORT_SYMBOL(wcd_mbhc_get_impedance);
1357
1358 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1359 {
1360 mbhc->hph_type = hph_type;
1361 }
1362 EXPORT_SYMBOL(wcd_mbhc_set_hph_type);
1363
1364 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1365 {
1366 return mbhc->hph_type;
1367 }
1368 EXPORT_SYMBOL(wcd_mbhc_get_hph_type);
1369
1370 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg,
1371 struct snd_soc_jack *jack)
1372 {
1373 if (!mbhc || !cfg || !jack)
1374 return -EINVAL;
1375
1376 mbhc->cfg = cfg;
1377 mbhc->jack = jack;
1378
1379 return wcd_mbhc_initialise(mbhc);
1380 }
1381 EXPORT_SYMBOL(wcd_mbhc_start);
1382
1383 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
1384 {
1385 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
1386 mbhc->hph_status = 0;
1387 disable_irq_nosync(mbhc->intr_ids->hph_left_ocp);
1388 disable_irq_nosync(mbhc->intr_ids->hph_right_ocp);
1389 }
1390 EXPORT_SYMBOL(wcd_mbhc_stop);
1391
1392 int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg)
1393 {
1394 struct device_node *np = dev->of_node;
1395 int ret, i, microvolt;
1396
1397 if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed"))
1398 cfg->hphl_swh = false;
1399 else
1400 cfg->hphl_swh = true;
1401
1402 if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed"))
1403 cfg->gnd_swh = false;
1404 else
1405 cfg->gnd_swh = true;
1406
1407 ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
1408 µvolt);
1409 if (ret)
1410 dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
1411 else
1412 cfg->hs_thr = microvolt/1000;
1413
1414 ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
1415 µvolt);
1416 if (ret)
1417 dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n");
1418 else
1419 cfg->hph_thr = microvolt/1000;
1420
1421 ret = of_property_read_u32_array(np,
1422 "qcom,mbhc-buttons-vthreshold-microvolt",
1423 &cfg->btn_high[0],
1424 WCD_MBHC_DEF_BUTTONS);
1425 if (ret)
1426 dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n");
1427
1428 for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) {
1429 if (ret)
1430 cfg->btn_high[i] = 500000;
1431 else
1432
1433 cfg->btn_high[i] = cfg->btn_high[i]/1000;
1434 }
1435
1436 return 0;
1437 }
1438 EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
1439
1440 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
1441 const struct wcd_mbhc_cb *mbhc_cb,
1442 const struct wcd_mbhc_intr *intr_ids,
1443 struct wcd_mbhc_field *fields,
1444 bool impedance_det_en)
1445 {
1446 struct device *dev = component->dev;
1447 struct wcd_mbhc *mbhc;
1448 int ret;
1449
1450 if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) {
1451 dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__);
1452 return ERR_PTR(-EINVAL);
1453 }
1454
1455 mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL);
1456 if (!mbhc)
1457 return ERR_PTR(-ENOMEM);
1458
1459 mbhc->component = component;
1460 mbhc->dev = dev;
1461 mbhc->intr_ids = intr_ids;
1462 mbhc->mbhc_cb = mbhc_cb;
1463 mbhc->fields = fields;
1464 mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
1465
1466 if (mbhc_cb->compute_impedance)
1467 mbhc->impedance_detect = impedance_det_en;
1468
1469 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn);
1470
1471 mutex_init(&mbhc->lock);
1472
1473 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1474
1475 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL,
1476 wcd_mbhc_mech_plug_detect_irq,
1477 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1478 "mbhc sw intr", mbhc);
1479 if (ret)
1480 goto err;
1481
1482 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL,
1483 wcd_mbhc_btn_press_handler,
1484 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1485 "Button Press detect", mbhc);
1486 if (ret)
1487 goto err;
1488
1489 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL,
1490 wcd_mbhc_btn_release_handler,
1491 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1492 "Button Release detect", mbhc);
1493 if (ret)
1494 goto err;
1495
1496 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
1497 wcd_mbhc_adc_hs_ins_irq,
1498 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1499 "Elect Insert", mbhc);
1500 if (ret)
1501 goto err;
1502
1503 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1504
1505 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
1506 wcd_mbhc_adc_hs_rem_irq,
1507 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1508 "Elect Remove", mbhc);
1509 if (ret)
1510 goto err;
1511
1512 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
1513
1514 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL,
1515 wcd_mbhc_hphl_ocp_irq,
1516 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1517 "HPH_L OCP detect", mbhc);
1518 if (ret)
1519 goto err;
1520
1521 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL,
1522 wcd_mbhc_hphr_ocp_irq,
1523 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1524 "HPH_R OCP detect", mbhc);
1525 if (ret)
1526 goto err;
1527
1528 return mbhc;
1529 err:
1530 dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
1531
1532 return ERR_PTR(ret);
1533 }
1534 EXPORT_SYMBOL(wcd_mbhc_init);
1535
1536 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
1537 {
1538 mutex_lock(&mbhc->lock);
1539 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1540 mutex_unlock(&mbhc->lock);
1541 }
1542 EXPORT_SYMBOL(wcd_mbhc_deinit);
1543
1544 static int __init mbhc_init(void)
1545 {
1546 return 0;
1547 }
1548
1549 static void __exit mbhc_exit(void)
1550 {
1551 }
1552
1553 module_init(mbhc_init);
1554 module_exit(mbhc_exit);
1555
1556 MODULE_DESCRIPTION("wcd MBHC v2 module");
1557 MODULE_LICENSE("GPL");