static irqreturn_t detect_irq_handler(int irq, void *dev_id) { int value1, value2; int retry_limit = 10; int state = BIT_HEADSET | BIT_HEADSET_NO_MIC; H2W_DBG(""); set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW); do { value1 = gpio_get_value(hi->cable_in1); set_irq_type(hi->irq, value1 ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); value2 = gpio_get_value(hi->cable_in1); } while (value1 != value2 && retry_limit-- > 0); H2WI("value2 = %d (%d retries), device=%d", value2, (10-retry_limit), switch_get_state(&hi->sdev)); if ((hi->h2w_dev_type == 0) ^ value2) { if ((switch_get_state(&hi->sdev) & state) && !hi->is_ext_insert) hi->ignore_btn = 1; if (hi->is_wake_lock_ready) wake_lock_timeout(&hi->headset_wake_lock, 2.5*HZ); queue_delayed_work(detect_wq, &detect_h2w_work, H2W_DETECT_DELAY); } return IRQ_HANDLED; }
static void remove_35mm_do_work(struct work_struct *work) { wake_lock_timeout(&hi->headset_wake_lock, 2.5*HZ); H2W_DBG(""); /*To solve the insert, remove, insert headset problem*/ if (time_before_eq(jiffies, hi->insert_jiffies)) msleep(800); if (hi->is_ext_insert) { H2WI("Skip 3.5mm headset plug out!!!"); if (hi->is_hpin_stable) *(hi->is_hpin_stable) = 1; return; } pr_info("3.5mm_headset plug out\n"); if (pd->key_event_disable != NULL) pd->key_event_disable(); if (hi->mic_bias_state) { turn_mic_bias_on(0); hi->mic_bias_state = 0; } hi->ext_35mm_status = 0; if (hi->is_hpin_stable) *(hi->is_hpin_stable) = 0; /* Notify framework via switch class */ mutex_lock(&hi->mutex_lock); switch_set_state(&hi->hs_change, hi->ext_35mm_status); mutex_unlock(&hi->mutex_lock); }
static void remove_35mm_do_work(struct work_struct *work) { int state; if (hi->is_wake_lock_ready) wake_lock_timeout(&hi->headset_wake_lock, 2.5*HZ); H2W_DBG(""); /*To solve the insert, remove, insert headset problem*/ if (time_before_eq(jiffies, hi->insert_jiffies)) msleep(800); if (hi->is_ext_insert) { H2WI("Skip 3.5mm headset plug out!!!"); return; } printk(KERN_INFO "3.5mm_headset plug out\n"); mutex_lock(&hi->mutex_lock); state = switch_get_state(&hi->sdev); if (hi->mic_bias_state) { turn_mic_bias_on(0); hi->mic_bias_state = 0; } /* For HW Metrico lab test */ if (hi->metrico_status) enable_metrico_headset(0); microp_notify_unplug_mic(); if (atomic_read(&hi->btn_state)) button_released(atomic_read(&hi->btn_state)); hi->ext_35mm_status = HTC_35MM_UNPLUG; if (hi->key_int_shutdown_gpio) gpio_set_value(hi->key_int_shutdown_gpio, 0); if (hi->ext_mic_sel) gpio_direction_output(hi->ext_mic_sel, 0); if (hi->h2w_dev_type == H2W_TVOUT) { state &= ~(BIT_HEADSET | BIT_35MM_HEADSET); state |= BIT_HEADSET_NO_MIC; switch_set_state(&hi->sdev, state); } else if (hi->cable_in1 && !gpio_get_value(hi->cable_in1)) { state &= ~BIT_35MM_HEADSET; switch_set_state(&hi->sdev, state); queue_delayed_work(detect_wq, &detect_h2w_work, H2W_NO_DELAY); } else { state &= ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_35MM_HEADSET); switch_set_state(&hi->sdev, state); } mutex_unlock(&hi->mutex_lock); }
static void button_35mm_do_work(struct work_struct *work) { int key = 0; int pressed = 0; if (!hi->is_ext_insert) { /* no headset ignor key event */ H2WI("3.5mm headset is plugged out, skip report key event"); return; } switch (hi->key_code) { case 0x1: /* Play/Pause */ H2WI("3.5mm RC: Play Pressed"); key = KEY_MEDIA; pressed = 1; break; case 0x2: H2WI("3.5mm RC: BACKWARD Pressed"); key = KEY_PREVIOUSSONG; pressed = 1; break; case 0x3: H2WI("3.5mm RC: FORWARD Pressed"); key = KEY_NEXTSONG; pressed = 1; break; case 0x81: /* Play/Pause */ H2WI("3.5mm RC: Play Released"); key = KEY_MEDIA; pressed = 0; break; case 0x82: H2WI("3.5mm RC: BACKWARD Released"); key = KEY_PREVIOUSSONG; pressed = 0; break; case 0x83: H2WI("3.5mm RC: FORWARD Released"); key = KEY_NEXTSONG; pressed = 0; break; default: H2WI("3.5mm RC: Unknown Button (0x%x) Pressed", hi->key_code); return; } input_report_key(hi->input, key, pressed); input_sync(hi->input); wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ); }
int htc_35mm_remote_notify_insert_ext_headset(int insert) { if (hi) { mutex_lock(&hi->mutex_lock); hi->is_ext_insert = insert; mutex_unlock(&hi->mutex_lock); H2WI(" %d", hi->is_ext_insert); if (!hi->is_ext_insert) queue_work(detect_wq, &remove_35mm_work); else queue_work(detect_wq, &insert_35mm_work); } return 1; }
int htc_35mm_jack_plug_event(int insert, int *hpin_stable) { if (!hi) { pr_err("Plug event before driver init\n"); return -1; } mutex_lock(&hi->mutex_lock); hi->is_ext_insert = insert; hi->is_hpin_stable = hpin_stable; mutex_unlock(&hi->mutex_lock); H2WI(" %d", hi->is_ext_insert); if (!hi->is_ext_insert) queue_work(detect_wq, &remove_35mm_work); else queue_work(detect_wq, &insert_35mm_work); return 1; }
static void button_35mm_do_work(struct work_struct *w) { int key; if (!hi->is_ext_insert && !hi->h2w_35mm_status) { H2WI("3.5mm headset is plugged out, skip report key event"); return; } if (hi->key_level_flag) { switch (hi->key_level_flag) { case 1: H2WI("3.5mm RC: Play Pressed"); key = KEY_MEDIA; break; case 2: H2WI("3.5mm RC: BACKWARD Pressed"); key = KEY_PREVIOUSSONG; break; case 3: H2WI("3.5mm RC: FORWARD Pressed"); key = KEY_NEXTSONG; break; default: H2WI("3.5mm RC: WRONG Button Pressed"); return; } headset_button_event(1, key); } else { /* key release */ if (atomic_read(&hi->btn_state)) headset_button_event(0, atomic_read(&hi->btn_state)); else H2WI("3.5mm RC: WRONG Button Release"); } if (hi->is_wake_lock_ready) wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ); }