Linux Audio

Check our new training course

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