Esempio n. 1
0
int hs_notify_key_event(int key_code)
{

	int uart_key;
	HS_DBG();

	if (hi->hs_35mm_type == HEADSET_UNKNOWN_MIC ||
	    hi->hs_35mm_type == HEADSET_NO_MIC ||
	    hi->h2w_35mm_type == HEADSET_NO_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (hi->hs_35mm_type == HEADSET_UNSTABLE)
		update_mic_status(0);
	else if (!hs_hpin_stable()) {
		HS_LOG("The HPIN is unstable, SKIP THE BUTTON EVENT.");
		return 1;
	} else {
		/*run one-wire button work function if the project support one-wire detection*/
		if(hi->detect_type == HEADSET_1WIRE && hi->pdata.enable_1wire){
			uart_key = button_1wire_work_func();
			if(uart_key!=99)
				key_code = uart_key;	
		}

		if(key_event_flag == (HS_BUTTON_EVENT_QUEUE-1))
			key_event_flag = -1;
		key_event_flag++;
		HS_DBG("key_event_flag = %d",key_event_flag);
		key_event[key_event_flag]->key_code = key_code;
		INIT_DELAYED_WORK(&key_event[key_event_flag]->key_work, button_35mm_work_func);
		queue_delayed_work(button_wq, &key_event[key_event_flag]->key_work,
				   HS_JIFFIES_BUTTON);
	}

	return 1;
}
static void headset_notifier_update(int id)
{
	if (!hi) {
		HS_LOG("HS_MGR driver is not ready");
		return;
	}

	switch (id) {
	case HEADSET_REG_HPIN_GPIO:
		break;
	case HEADSET_REG_REMOTE_ADC:
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		break;
	case HEADSET_REG_REMOTE_KEYCODE:
	case HEADSET_REG_RPC_KEY:
		break;
	case HEADSET_REG_MIC_STATUS:
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		break;
	case HEADSET_REG_MIC_BIAS:
	case HEADSET_REG_MIC_SELECT:
	case HEADSET_REG_KEY_INT_ENABLE:
	case HEADSET_REG_KEY_ENABLE:
		break;
	default:
		break;
	}
}
Esempio n. 3
0
int hs_notify_key_event(int key_code)
{


	HS_DBG();

	if (hi->hs_35mm_type == HEADSET_UNKNOWN_MIC ||
	    hi->hs_35mm_type == HEADSET_NO_MIC ||
	    hi->h2w_35mm_type == HEADSET_NO_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (hi->hs_35mm_type == HEADSET_UNSTABLE)
		update_mic_status(0);
	else if (!hs_hpin_stable()) {
		HS_LOG("The HPIN is unstable, SKIP THE BUTTON EVENT.");
		return 1;
	} else {
		if(key_event_flag == (HS_BUTTON_EVENT_QUEUE-1))
			key_event_flag = -1;
		key_event_flag++;
		HS_LOG("key_event_flag = %d",key_event_flag);
		key_event[key_event_flag]->key_code = key_code;
		INIT_DELAYED_WORK(&key_event[key_event_flag]->key_work, button_35mm_work_func);
		queue_delayed_work(button_wq, &key_event[key_event_flag]->key_work,
				   HS_JIFFIES_BUTTON);
	}

	return 1;
}
Esempio n. 4
0
int hs_notify_key_event(int key_code)
{
	struct button_work *work;
	int ret;

	HS_DBG();

	if (pre_key_work) {
		ret = cancel_delayed_work_sync(pre_key_work);
		if (ret)
			HS_LOG("Previous key code cancelled");
	}
	if (hi->hs_35mm_type == HEADSET_INDICATOR) {
		HS_LOG("Not support remote control");
		return 1;
	}

	if (hi->hs_35mm_type == HEADSET_UNKNOWN_MIC ||
	    hi->hs_35mm_type == HEADSET_NO_MIC ||
	    hi->h2w_35mm_type == HEADSET_NO_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (hi->hs_35mm_type == HEADSET_UNSTABLE)
		update_mic_status(0);
	else if (!hs_hpin_stable()) {
		HS_LOG("IGNORE key %d (Unstable HPIN)", key_code);
		return 1;
	} else if (hi->hs_35mm_type == HEADSET_UNPLUG && hi->is_ext_insert == 1) {
		HS_LOG("MIC status is changed from float, re-polling to decide accessory type");
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		return 1;
	} else {
		work = kzalloc(sizeof(struct button_work), GFP_KERNEL);
		if (!work) {
			HS_ERR("Failed to allocate button memory");
			return 1;
		}
		work->key_code = key_code;
		INIT_DELAYED_WORK(&work->key_work, button_35mm_work_func);
		pre_key_work = &work->key_work;
		if (hi->pdata.driver_flag & DRIVER_HS_MGR_OLD_AJ) {
			queue_delayed_work(button_wq, &work->key_work,
					   HS_JIFFIES_BUTTON_LONG);
		} else {
			queue_delayed_work(button_wq, &work->key_work,
					   HS_JIFFIES_BUTTON);
		}
	}

	return 1;
}
int hs_notify_key_irq(void)
{
	int adc = 0;
	int key_code = HS_MGR_KEY_INVALID;

	if (hi->hs_35mm_type == HEADSET_INDICATOR) {
		HS_LOG("Not support remote control");
		return 1;
	}

	if (!hs_mgr_notifier.remote_adc || !hs_mgr_notifier.remote_keycode) {
		HS_LOG("Failed to get remote key code");
		return 1;
	}

	if (hs_hpin_stable()) {
		mdelay(40);
		hs_mgr_notifier.remote_adc(&adc);
		key_code = hs_mgr_notifier.remote_keycode(adc);
		hs_notify_key_event(key_code);
	} else if (hi->hs_35mm_type == HEADSET_NO_MIC ||
		   hi->hs_35mm_type == HEADSET_UNKNOWN_MIC) {
		HS_LOG("IGNORE key IRQ (Unstable HPIN)");
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	}

	return 1;
}
int hs_notify_key_event(int key_code)
{
	struct button_work *work;

	HS_DBG();

	if (hi->hs_35mm_type == HEADSET_UNKNOWN_MIC ||
	    hi->hs_35mm_type == HEADSET_NO_MIC ||
	    hi->h2w_35mm_type == HEADSET_NO_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (!hs_hpin_stable()) {
		HS_LOG("The HPIN is unstable, SKIP THE BUTTON EVENT.");
		return 1;
	} else {
		work = kzalloc(sizeof(struct button_work), GFP_KERNEL);
		if (!work) {
			HS_ERR("Failed to allocate button memory");
			return 1;
		}
		work->key_code = key_code;
		INIT_DELAYED_WORK(&work->key_work, button_35mm_work_func);
		queue_delayed_work(button_wq, &work->key_work,
				   HS_JIFFIES_BUTTON);
	}

	return 1;
}
static void headset_notifier_update(int id)
{
	if (!hi) {
		HS_LOG("HS_MGR driver is not ready");
		return;
	}

	switch (id) {
	case HEADSET_REG_HPIN_GPIO:
		break;
	case HEADSET_REG_REMOTE_ADC:
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		break;
	case HEADSET_REG_REMOTE_KEYCODE:
	case HEADSET_REG_RPC_KEY:
		break;
	case HEADSET_REG_MIC_STATUS:
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		break;
	case HEADSET_REG_MIC_BIAS:
		if (!hi->pdata.headset_power &&
		    hi->hs_35mm_type != HEADSET_UNPLUG) {
			hs_mgr_notifier.mic_bias_enable(1);
			hi->mic_bias_state = 1;
			msleep(HS_DELAY_MIC_BIAS);
			update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		}
		break;
	case HEADSET_REG_MIC_SELECT:
	case HEADSET_REG_KEY_INT_ENABLE:
	case HEADSET_REG_KEY_ENABLE:
	case HEADSET_REG_INDICATOR_ENABLE:
		break;
	default:
		break;
	}
}
int headset_get_type_sync(int count, unsigned int interval)
{
	int current_type = hi->hs_35mm_type;
	int new_type = HEADSET_UNKNOWN_MIC;

	while (count--) {
		new_type = get_mic_status();
		if (new_type != current_type)
			break;
		if (count)
			msleep(interval);
	}

	if (new_type != current_type) {
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
		return HEADSET_UNKNOWN_MIC;
	}

	return hi->hs_35mm_type;
}
Esempio n. 9
0
int hs_notify_key_irq(void)
{
	int adc = 0;
	int key_code = HS_MGR_KEY_INVALID;

	key_bounce++;

	if (hi->one_wire_mode == 1 && hs_hpin_stable()) {
		wake_lock_timeout(&hi->hs_wake_lock, HS_WAKE_LOCK_TIMEOUT);
		key_code = hs_mgr_notifier.hs_1wire_read_key();
		if (key_code >= 0)
			hs_notify_key_event(key_code);
		return 1;
	}

	if (hi->hs_35mm_type == HEADSET_INDICATOR) {
		HS_LOG("Not support remote control");
		return 1;
	}

	if (!hs_mgr_notifier.remote_adc || !hs_mgr_notifier.remote_keycode) {
		HS_LOG("Failed to get remote key code");
		return 1;
	}

	if (hs_hpin_stable()) {
		hs_mgr_notifier.remote_adc(&adc);
		key_code = hs_mgr_notifier.remote_keycode(adc);
		hs_notify_key_event(key_code);
	} else if (hi->hs_35mm_type == HEADSET_NO_MIC ||
		   hi->hs_35mm_type == HEADSET_UNKNOWN_MIC) {
		HS_LOG("IGNORE key IRQ (Unstable HPIN)");
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	}

	return 1;
}
static void insert_detect_work_func(struct work_struct *work)
{
	int state,old_state;
	int mic = HEADSET_NO_MIC;

	wake_lock_timeout(&hi->hs_wake_lock, HS_WAKE_LOCK_TIMEOUT);

	HS_DBG();

	if (!hi->is_ext_insert) {
		HS_LOG("Headset has been removed");
		return;
	}

	hi->insert_jiffies = jiffies;
	set_35mm_hw_state(1);

	mutex_lock(&hi->mutex_lock);

	mic = get_mic_status();
	if (hi->pdata.driver_flag & DRIVER_HS_MGR_FLOAT_DET) {
		HS_LOG("Headset float detect enable");
		if (mic == HEADSET_UNPLUG) {
			mutex_unlock(&hi->mutex_lock);
			update_mic_status(HS_DEF_MIC_DETECT_COUNT);
			return;
		}
	}

	if (mic == HEADSET_NO_MIC)
		mic = tv_out_detect();

	if (mic == HEADSET_TV_OUT && hi->pdata.hptv_sel_gpio)
		gpio_set_value(hi->pdata.hptv_sel_gpio, 1);

	if (mic == HEADSET_METRICO && !hi->metrico_status)
		enable_metrico_headset(1);

	state = switch_get_state(&hi->sdev_h2w);
	old_state = state;
	state &= ~MASK_35MM_HEADSET;
	state |= BIT_35MM_HEADSET;

	switch (mic) {

	case HEADSET_NO_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_NO_MIC");
		break;
	case HEADSET_MIC:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_MIC");
		break;
	case HEADSET_METRICO:
		mic = HEADSET_UNSTABLE;
		HS_LOG_TIME("HEADSET_METRICO (UNSTABLE)");
		break;
	case HEADSET_UNKNOWN_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_UNKNOWN_MIC");
		break;
	case HEADSET_TV_OUT:
		state |= BIT_TV_OUT;
		HS_LOG_TIME("HEADSET_TV_OUT");
#if defined(CONFIG_FB_MSM_TVOUT) && defined(CONFIG_ARCH_MSM8X60)
		tvout_enable_detection(1);
#endif
		break;
	case HEADSET_BEATS:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS (UNSTABLE)");
		break;
	case HEADSET_BEATS_SOLO:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS_SOLO (UNSTABLE)");
		break;
	case HEADSET_INDICATOR:
		HS_LOG_TIME("HEADSET_INDICATOR");
		break;
	}

	if (old_state != state) {
		if (old_state & state & MASK_35MM_HEADSET) {
			if (hi->pdata.driver_flag & DRIVER_HS_MGR_OLD_AJ) {
				state |= old_state;
				HS_LOG("Old audio jack found, use workaround");
			} else {
				switch_set_state(&hi->sdev_h2w, old_state & ~MASK_35MM_HEADSET);
				HS_LOG("Report fake remove event");
			}
		}
		hi->hs_35mm_type = mic;
		HS_LOG_TIME("Send uevent for state change, %d => %d", old_state, state);
		switch_set_state(&hi->sdev_h2w, state);
	} else
		HS_LOG("No state change");

	mutex_unlock(&hi->mutex_lock);

#ifdef HTC_HEADSET_CONFIG_QUICK_BOOT
	if (gpio_event_get_quickboot_status())
		HS_LOG("quick_boot_status = 1");
#endif

	if (mic == HEADSET_UNKNOWN_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (mic == HEADSET_UNSTABLE)
		update_mic_status(0);
	else if (mic == HEADSET_INDICATOR) {
		if (headset_get_type_sync(3, HS_DELAY_SEC) == HEADSET_INDICATOR)
			HS_LOG("Delay check: HEADSET_INDICATOR");
		else
			HS_LOG("Delay check: HEADSET_UNKNOWN_MIC");
	}
}
static void insert_detect_work_func(struct work_struct *work)
{
	int state;
	int mic = HEADSET_NO_MIC;

	wake_lock_timeout(&hi->hs_wake_lock, HS_WAKE_LOCK_TIMEOUT);

	HS_DBG();

	if (!hi->is_ext_insert) {
		HS_LOG("Headset has been removed");
		return;
	}

	hi->insert_jiffies = jiffies;
	set_35mm_hw_state(1);

	mutex_lock(&hi->mutex_lock);

	mic = get_mic_status();

	if (mic == HEADSET_NO_MIC)
		mic = tv_out_detect();

	if (mic == HEADSET_TV_OUT && hi->pdata.hptv_sel_gpio)
		gpio_set_value(hi->pdata.hptv_sel_gpio, 1);

	if (mic == HEADSET_METRICO && !hi->metrico_status)
		enable_metrico_headset(1);

	state = switch_get_state(&hi->sdev);
	state &= ~MASK_35MM_HEADSET;
	state |= BIT_35MM_HEADSET;

	switch (mic) {
	case HEADSET_NO_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_NO_MIC");
		break;
	case HEADSET_MIC:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_MIC");
		break;
	case HEADSET_METRICO:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_METRICO");
		break;
	case HEADSET_UNKNOWN_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_UNKNOWN_MIC");
		break;
	case HEADSET_TV_OUT:
		state |= BIT_TV_OUT;
		HS_LOG_TIME("HEADSET_TV_OUT");
#if defined(CONFIG_FB_MSM_TVOUT) && defined(CONFIG_ARCH_MSM8X60)
		tvout_enable_detection(1);
#endif
		break;
	case HEADSET_BEATS:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS");
		break;
	case HEADSET_INDICATOR:
		HS_LOG_TIME("HEADSET_INDICATOR");
		break;
	}

	hi->hs_35mm_type = mic;
	switch_set_state(&hi->sdev, state);

	mutex_unlock(&hi->mutex_lock);

	if (mic == HEADSET_UNKNOWN_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (mic == HEADSET_INDICATOR) {
		if (headset_get_type_sync(3, HS_DELAY_SEC) == HEADSET_INDICATOR)
			HS_LOG("Delay check: HEADSET_INDICATOR");
		else
			HS_LOG("Delay check: HEADSET_UNKNOWN_MIC");
	}
}
Esempio n. 12
0
static void insert_detect_work_func(struct work_struct *work)
{
	int state;
	int mic = HEADSET_NO_MIC;

	wake_lock_timeout(&hi->hs_wake_lock, HS_WAKE_LOCK_TIMEOUT);

	HS_DBG();

	if (!hi->is_ext_insert) {
		HS_LOG("Headset has been removed");
		return;
	}

	hi->insert_jiffies = jiffies;
	set_35mm_hw_state(1);

	mutex_lock(&hi->mutex_lock);

	mic = get_mic_status();

	if(mic == HEADSET_UNPLUG){
		mdelay(1000);
		mic = get_mic_status();
	if(mic == HEADSET_UNPLUG){
		HS_LOG("Headset unplug.");
		hi->hs_35mm_type = mic;
		mutex_unlock(&hi->mutex_lock);
		if ((hi->pdata.eng_cfg == HS_EDE_U) || (hi->pdata.eng_cfg == HS_EDE_TD) || (hi->pdata.eng_cfg == HS_BLE)){
			aic3008_set_mic_bias(0);
		}
		if ((hi->pdata.eng_cfg == HS_QUO_F_U)){
			regulator = regulator_get(NULL, "v_aud_2v85");
			if (IS_ERR_OR_NULL(regulator)) {
				pr_err("htc_headset_gpio_probe:Couldn't get regulator v_aud_2v85\n");
				regulator = NULL;
				return;
			}
			regulator_disable(regulator);
		}
		return;
	}
	}

	if (mic == HEADSET_NO_MIC)
		mic = tv_out_detect();

	if (mic == HEADSET_TV_OUT && hi->pdata.hptv_sel_gpio)
		gpio_set_value(hi->pdata.hptv_sel_gpio, 1);

	if (mic == HEADSET_METRICO && !hi->metrico_status)
		enable_metrico_headset(1);

	state = switch_get_state(&hi->sdev);
	state &= ~MASK_35MM_HEADSET;
	state |= BIT_35MM_HEADSET;

/*run one-wire detect work function if one-wire detection is enable*/
	if (hi->pdata.enable_1wire)
		{
		int wire = 0;
		wire = insert_1wire_work_func();
		if (wire > 0)
			{
			HS_LOG("Enable one-wire detection");
			mic = wire;
			}
		}

	switch (mic) {
	case HEADSET_NO_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_NO_MIC");
		break;
	case HEADSET_MIC:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_MIC");
		break;
	case HEADSET_METRICO:
		mic = HEADSET_UNSTABLE;
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_METRICO (UNSTABLE)");
		break;
	case HEADSET_UNKNOWN_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_UNKNOWN_MIC");
		break;
	case HEADSET_TV_OUT:
		state |= BIT_TV_OUT;
		HS_LOG_TIME("HEADSET_TV_OUT");
#if defined(CONFIG_FB_MSM_TVOUT) && defined(CONFIG_ARCH_MSM8X60)
		tvout_enable_detection(1);
#endif
		break;
	case HEADSET_BEATS:
//		mic = HEADSET_UNSTABLE;
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS (UNSTABLE)");
		break;
	case HEADSET_BEATS_SOLO:
//		mic = HEADSET_UNSTABLE;
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS_SOLO (UNSTABLE)");
		break;
	case HEADSET_INDICATOR:
		HS_LOG_TIME("HEADSET_INDICATOR");
		break;
	}

	hi->hs_35mm_type = mic;
	switch_set_state(&hi->sdev, state);
	hpin_report++;

	mutex_unlock(&hi->mutex_lock);

	/* FIXME */
/*	if (gpio_event_get_quickboot_status())
		HS_LOG("quick_boot_status = 1"); */

	if (mic == HEADSET_UNKNOWN_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (mic == HEADSET_UNSTABLE)
		update_mic_status(0);
	else if (mic == HEADSET_INDICATOR) {
		if (headset_get_type_sync(3, HS_DELAY_SEC) == HEADSET_INDICATOR)
			HS_LOG("Delay check: HEADSET_INDICATOR");
		else
			HS_LOG("Delay check: HEADSET_UNKNOWN_MIC");
	}
}
Esempio n. 13
0
static void insert_detect_work_func(struct work_struct *work)
{
	int state,old_state;
	int mic = HEADSET_NO_MIC;
	int adc = 0;

	wake_lock_timeout(&hi->hs_wake_lock, HS_WAKE_LOCK_TIMEOUT);

	HS_DBG();

	if (!hi->is_ext_insert) {
		HS_LOG("Headset has been removed");
		return;
	}

	HS_LOG("Start 1-wire detecting sequence");
	if (hi->pdata.uart_tx_gpo)
		hi->pdata.uart_tx_gpo(0);
	if (hi->pdata.uart_lv_shift_en)
		hi->pdata.uart_lv_shift_en(0);
	msleep(20);
	if (hi->pdata.uart_lv_shift_en)
		hi->pdata.uart_lv_shift_en(1);
	if (hi->pdata.uart_tx_gpo)
		hi->pdata.uart_tx_gpo(2);

	hi->insert_jiffies = jiffies;
	set_35mm_hw_state(1);
	msleep(150);
	if (hs_mgr_notifier.remote_adc)
		hs_mgr_notifier.remote_adc(&adc);

	mutex_lock(&hi->mutex_lock);

	hi->one_wire_mode = 0;
/*Check one wire accessory for every plug event*/
	if (hi->driver_one_wire_exist && adc > 915) {
		HS_LOG("[HS_1wire]1wire driver exists, starting init");
		if (hs_mgr_notifier.key_int_enable)
			hs_mgr_notifier.key_int_enable(0);
		if (hs_mgr_notifier.hs_1wire_init() == 0) {
			hi->one_wire_mode = 1;
		/*Report as normal headset with MIC*/
			state = switch_get_state(&hi->sdev_h2w);
			state |= BIT_HEADSET;
			switch_set_state(&hi->sdev_h2w, state);
			hi->hs_35mm_type = HEADSET_BEATS;
			mutex_unlock(&hi->mutex_lock);
		if (hs_mgr_notifier.key_int_enable)
			hs_mgr_notifier.key_int_enable(1);
			return;
		}
		else {
			hi->one_wire_mode = 0;
			HS_LOG("Lagacy mode");
			if (hi->pdata.uart_tx_gpo)
				hi->pdata.uart_tx_gpo(2);
			if (hs_mgr_notifier.key_int_enable)
				hs_mgr_notifier.key_int_enable(1);
		}
	}

	mic = get_mic_status();
	if (hi->pdata.driver_flag & DRIVER_HS_MGR_FLOAT_DET) {
		HS_LOG("Headset float detect enable");
		if (mic == HEADSET_UNPLUG) {
			mutex_unlock(&hi->mutex_lock);
			update_mic_status(HS_DEF_MIC_DETECT_COUNT);
			return;
		}
	}

	if (mic == HEADSET_NO_MIC)
		mic = tv_out_detect();

	if (mic == HEADSET_TV_OUT && hi->pdata.hptv_sel_gpio)
		gpio_set_value(hi->pdata.hptv_sel_gpio, 1);

	if (mic == HEADSET_METRICO && !hi->metrico_status)
		enable_metrico_headset(1);

	state = switch_get_state(&hi->sdev_h2w);
	old_state = state;
	state &= ~MASK_35MM_HEADSET;
	state |= BIT_35MM_HEADSET;

	switch (mic) {

	case HEADSET_NO_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_NO_MIC");
		break;
	case HEADSET_MIC:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_MIC");
		break;
	case HEADSET_METRICO:
		mic = HEADSET_UNSTABLE;
		HS_LOG_TIME("HEADSET_METRICO (UNSTABLE)");
		break;
	case HEADSET_UNKNOWN_MIC:
		state |= BIT_HEADSET_NO_MIC;
		HS_LOG_TIME("HEADSET_UNKNOWN_MIC");
		break;
	case HEADSET_TV_OUT:
		state |= BIT_TV_OUT;
		HS_LOG_TIME("HEADSET_TV_OUT");
#if defined(CONFIG_FB_MSM_TVOUT) && defined(CONFIG_ARCH_MSM8X60)
		tvout_enable_detection(1);
#endif
		break;
	case HEADSET_BEATS:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS (UNSTABLE)");
		break;
	case HEADSET_BEATS_SOLO:
		state |= BIT_HEADSET;
		HS_LOG_TIME("HEADSET_BEATS_SOLO (UNSTABLE)");
		break;
	case HEADSET_INDICATOR:
		HS_LOG_TIME("HEADSET_INDICATOR");
		break;
	}

	if (old_state != state) {
		if (old_state & state & MASK_35MM_HEADSET) {
			if (hi->pdata.driver_flag & DRIVER_HS_MGR_OLD_AJ) {
				state |= old_state;
				HS_LOG("Old audio jack found, use workaround");
			} else {
				switch_set_state(&hi->sdev_h2w, old_state & ~MASK_35MM_HEADSET);
				HS_LOG("Report fake remove event");
			}
		}
		hi->hs_35mm_type = mic;
		HS_LOG_TIME("Send uevent for state change, %d => %d", old_state, state);
		switch_set_state(&hi->sdev_h2w, state);
		hpin_report++;
	} else
		HS_LOG("No state change");

	mutex_unlock(&hi->mutex_lock);

#ifdef HTC_HEADSET_CONFIG_QUICK_BOOT
	if (gpio_event_get_quickboot_status())
		HS_LOG("quick_boot_status = 1");
#endif

	if (mic == HEADSET_UNKNOWN_MIC)
		update_mic_status(HS_DEF_MIC_DETECT_COUNT);
	else if (mic == HEADSET_UNSTABLE)
		update_mic_status(0);
	else if (mic == HEADSET_INDICATOR) {
		if (headset_get_type_sync(3, HS_DELAY_SEC) == HEADSET_INDICATOR)
			HS_LOG("Delay check: HEADSET_INDICATOR");
		else
			HS_LOG("Delay check: HEADSET_UNKNOWN_MIC");
	}
}