static irqreturn_t hi6402_btnup_eco_handler(int irq, void *data) { struct hi6402_mbhc_platform_data *pdata = (struct hi6402_mbhc_platform_data *)data; BUG_ON(NULL == pdata); pr_err("----cg---- %s\n", __FUNCTION__); mask_irq(pdata->irq[HI6402_IRQ_BTNUP_ECO], true); mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_ECO], false); if (!check_headset_pluged_in(pdata)) return IRQ_HANDLED; wake_lock_timeout(&pdata->wake_lock, 100); if (HISI_JACK_INVERT == pdata->hs_status) { pr_err("%s: further detect\n", __FUNCTION__); /* further detect */ queue_delayed_work(pdata->headset_plug_in_delay_wq, &pdata->headset_plug_in_delay_work, msecs_to_jiffies(50)); } else if (0 == pdata->btn_report){ return IRQ_HANDLED; } else { queue_delayed_work(pdata->headset_btn_up_delay_wq, &pdata->headset_btn_up_delay_work, msecs_to_jiffies(50)); } return IRQ_HANDLED; }
static irqreturn_t hi6402_btnup_eco_handler(int irq, void *data) { struct hi6402_mbhc_platform_data *pdata = (struct hi6402_mbhc_platform_data *)data; BUG_ON(NULL == pdata); if (!check_headset_pluged_in(pdata)) return IRQ_HANDLED; wake_lock_timeout(&pdata->wake_lock, 100); if (HISI_JACK_INVERT == pdata->hs_status) { pr_err("%s: further detect\n", __FUNCTION__); /* further detect */ hi6402_plug_in_detect(pdata); } else if (0 == pdata->btn_report){ if (HISI_JACK_HEADSET != pdata->hs_status) { /* further detect */ hi6402_plug_in_detect(pdata); } return IRQ_HANDLED; } else { mutex_lock(&pdata->status_mutex); pdata->btn_report = 0; hi6402_soc_jack_report(pdata->btn_report, HI6402_BTN_MASK); mutex_unlock(&pdata->status_mutex); pr_info("%s(%u) : btn up !\n", __FUNCTION__, __LINE__); } return IRQ_HANDLED; }
static irqreturn_t hi6402_btndown_handler(int irq, void *data) { struct hi6402_mbhc_platform_data *pdata = (struct hi6402_mbhc_platform_data *)data; BUG_ON(NULL == pdata); pr_err("----cg---- %s\n", __FUNCTION__); if (!check_headset_pluged_in(pdata)) return IRQ_HANDLED; /* mask btn down interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], true); /* unmask btn up interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNUP_COMP1], false); wake_lock_timeout(&pdata->wake_lock, 50); queue_delayed_work(pdata->headset_btn_down_delay_wq, &pdata->headset_btn_down_delay_work, msecs_to_jiffies(30)); return IRQ_HANDLED; }
void hi6402_plug_in_detect(struct hi6402_mbhc_platform_data *pdata) { if (!check_headset_pluged_in(pdata)) return; wake_lock(&pdata->wake_lock); mutex_lock(&pdata->plug_mutex); mutex_lock(&pdata->status_mutex); /* todo : btn_report 4-pole headset only now */ pdata->hs_status = HISI_JACK_HEADSET; pdata->btn_report = SND_JACK_HEADSET; mutex_unlock(&pdata->status_mutex); hi6402_jack_report(pdata); /* todo */ hi6402_reg_clr_bit(pdata->p_irq, HI6402_MBHC_VREF_REG, 7); hi6402_reg_set_bit(pdata->p_irq, HI6402_MICBIAS_ECO_REG, 0); /* unmask btn down irq */ mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], false); mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_ECO], false); mutex_unlock(&pdata->plug_mutex); wake_unlock(&pdata->wake_lock); }
static irqreturn_t hi6402_plugout_handler(int irq, void *data) { struct hi6402_mbhc_platform_data *pdata = (struct hi6402_mbhc_platform_data *)data; BUG_ON(NULL == pdata); if (check_headset_pluged_in(pdata)) { pr_info("%s : hs still plugin \n", __FUNCTION__); return IRQ_HANDLED; } mutex_lock(&pdata->plug_mutex); hi6402_irq_cancel_delay_work(pdata->p_irq); hi6402_irq_mask_btn_irqs(pdata->p_irq); //stop charge first anc_hs_stop_charge(); /* eco off */ hi6402_reg_clr_bit(pdata->p_irq, HI6402_MICBIAS_ECO_REG, HI6402_MICBIAS_ECO_ON_BIT); mutex_lock(&pdata->p_irq->hs_micbias_mutex); /* hs micbias off */ pdata->p_irq->mbhc_micbias_work = false; pdata->p_irq->dapm_micbias_work = false; mutex_unlock(&pdata->p_irq->hs_micbias_mutex); hi6402_irq_hs_micbias_enable(pdata->p_irq, false); hi6402_irq_clr_btn_irqs(pdata->p_irq); hi6402_irq_mask_btn_irqs(pdata->p_irq); /* eco off */ hi6402_reg_clr_bit(pdata->p_irq, HI6402_MICBIAS_ECO_REG, HI6402_MICBIAS_ECO_ON_BIT); pr_info("%s : eco disable \n", __FUNCTION__); /* vref off */ hi6402_reg_set_bit(pdata->p_irq, HI6402_MBHC_VREF_REG, HI6402_MBHC_VREF_BIT); /* mbhc cmp off */ hi6402_reg_set_bit(pdata->p_irq, HI6402_ANA_REG60, HI6402_MBHC_ON_BIT); mutex_lock(&pdata->status_mutex); pdata->hs_status = HISI_JACK_NONE; pdata->btn_report = 0; mutex_unlock(&pdata->status_mutex); hi6402_jack_report(pdata); hi6402_mbhc_enable_ldo8(pdata, false); mutex_unlock(&pdata->plug_mutex); return IRQ_HANDLED; }
static int hi6402_mbhc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hi6402_mbhc_platform_data *pdata = NULL; const struct of_device_id *match = NULL; int ret = 0; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (NULL == pdata) { dev_err(dev, "cannot allocate hisi 6421 spk platform data\n"); return -ENOMEM; } match = of_match_device(hi6402_mbhc_of_match, dev); if (!match) { pr_err("get device info err\n"); return -ENOENT; } else { struct device_node *node = dev->of_node; int temp; /* get board defination */ if (!of_property_read_u32(node, "hisilicon,hi6402_hs_det_inv", &temp)) pdata->hs_det_inv = temp; else pdata->hs_det_inv = 0; if (!of_property_read_u32(node, "hisilicon,hs_3_pole_min_voltage", &temp)) pdata->hs_3_pole_min_voltage = temp; else pdata->hs_3_pole_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,hs_3_pole_max_voltage", &temp)) pdata->hs_3_pole_max_voltage = temp; else pdata->hs_3_pole_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,hs_4_pole_min_voltage", &temp)) pdata->hs_4_pole_min_voltage = temp; else pdata->hs_4_pole_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,hs_4_pole_max_voltage", &temp)) pdata->hs_4_pole_max_voltage = temp; else pdata->hs_4_pole_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_play_min_voltage", &temp)) pdata->btn_play_min_voltage = temp; else pdata->btn_play_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_play_max_voltage", &temp)) pdata->btn_play_max_voltage = temp; else pdata->btn_play_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_up_min_voltage", &temp)) pdata->btn_volume_up_min_voltage = temp; else pdata->btn_volume_up_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_up_max_voltage", &temp)) pdata->btn_volume_up_max_voltage = temp; else pdata->btn_volume_up_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_down_min_voltage", &temp)) pdata->btn_volume_down_min_voltage = temp; else pdata->btn_volume_down_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_down_max_voltage", &temp)) pdata->btn_volume_down_max_voltage = temp; else pdata->btn_volume_down_max_voltage = 0; } pdata->p_irq = dev_get_drvdata(pdev->dev.parent); if (!pdata->p_irq) { dev_err(dev, "get parend device error\n"); return -ENOENT; } #ifdef CONFIG_SWITCH pdata->sdev.name = "h2w"; ret = switch_dev_register(&pdata->sdev); if (ret) { pr_err("%s : error registering switch device %d\n", __FUNCTION__, ret); return ret; } #endif /* get irqs */ pdata->irq[HI6402_IRQ_PLL_UNLOCK] = platform_get_irq_byname(pdev, "pll_unlock"); if (0 > pdata->irq[HI6402_IRQ_PLL_UNLOCK]) { pr_err("get pll unlock error"); return -ENOENT; } pdata->irq[HI6402_IRQ_SOUND_TRIGER] = platform_get_irq_byname(pdev, "sound_triger"); if (0 > pdata->irq[HI6402_IRQ_SOUND_TRIGER]) { pr_err("get sound triger error"); return -ENOENT; } pdata->irq[HI6402_IRQ_PLUGOUT] = platform_get_irq_byname(pdev, "plugout"); if (0 > pdata->irq[HI6402_IRQ_PLUGOUT]) { pr_err("get plug out irq num error"); return -ENOENT; } pdata->irq[HI6402_IRQ_PLUGIN] = platform_get_irq_byname(pdev, "plugin"); if (0 > pdata->irq[HI6402_IRQ_PLUGIN]) { pr_err("get plug in irq num error"); return -ENOENT; } pdata->irq[HI6402_IRQ_BTNDOWN_ECO] = platform_get_irq_byname(pdev, "btndown_eco"); if (0 > pdata->irq[HI6402_IRQ_BTNDOWN_ECO]) { pr_err("get btn down eco irq num error"); return -ENOENT; } pdata->irq[HI6402_IRQ_BTNUP_ECO] = platform_get_irq_byname(pdev, "btnup_eco"); if (0 > pdata->irq[HI6402_IRQ_BTNUP_ECO]) { pr_err("get btn up eco irq num error"); return -ENOENT; } pdata->irq[HI6402_IRQ_BTNDOWN_COMP1] = platform_get_irq_byname(pdev, "btndown"); if (0 > pdata->irq[HI6402_IRQ_BTNDOWN_COMP1]) { pr_err("get btn down irq num error"); return -ENOENT; } pdata->irq[HI6402_IRQ_BTNUP_COMP1] = platform_get_irq_byname(pdev, "btnup"); if (0 > pdata->irq[HI6402_IRQ_BTNUP_COMP1]) { pr_err("get btn up irq num error"); return -ENOENT; } wake_lock_init(&pdata->wake_lock, WAKE_LOCK_SUSPEND, "hisi-6402-mbhc"); wake_lock_init(&pdata->soundtrigger_wake_lock, WAKE_LOCK_SUSPEND, "hisi-6402-soundtrigger"); mutex_init(&pdata->plug_mutex); mutex_init(&pdata->status_mutex); mutex_init(&pdata->saradc_mutex); /* irq request : pll unlock */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_PLL_UNLOCK], NULL, hi6402_pll_unlock_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "pll_unlock", pdata); if (0 > ret) { pr_err("request irq for pll unlock err\n"); goto pll_unlock_err; } mutex_lock(&pdata->p_irq->irq_lock); hi6402_reg_set_bit(pdata->p_irq, HI6402_MASK_IRQ_REG_2, HI6402_MASK_PLL_UNLOCK_BIT); pdata->p_irq->mask2 |= 0x10; mutex_unlock(&pdata->p_irq->irq_lock); /* irq request : sound triger */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_SOUND_TRIGER], NULL, hi6402_sound_triger_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "sound_triger", pdata); if (0 > ret) { pr_err("request irq for sound triger err\n"); goto sound_triger_err; } /* irq request : plugout */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_PLUGOUT], NULL, hi6402_plugout_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "plugout", pdata); if (0 > ret) { pr_err("request irq for plugout err\n"); goto plugout_err; } /* irq request : plugin */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_PLUGIN], NULL, hi6402_plugin_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "plugin", pdata); if (0 > ret) { pr_err("request irq for plugin err\n"); goto plugin_err; } /* irq request : button up(eco mode) */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_BTNUP_ECO], NULL, hi6402_btnup_eco_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "btnup_eco", pdata); if (0 > ret) { pr_err("request irq for btnup eco err\n"); goto btnup_eco_err; } /* irq request : button down(eco mode) */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_BTNDOWN_ECO], NULL, hi6402_btndown_eco_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "btndown_eco", pdata); if (0 > ret) { pr_err("request irq for btndown eco err\n"); goto btndown_eco_err; } /* irq request : button down */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], NULL, hi6402_btndown_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "btndown_comp1", pdata); if (0 > ret) { pr_err("request irq for btndown comp1 err\n"); goto btndown_comp1_err; } /* irq request : button up */ ret = devm_request_threaded_irq(dev, pdata->irq[HI6402_IRQ_BTNUP_COMP1], NULL, hi6402_btnup_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, "btnup_comp1", pdata); if (0 > ret) { pr_err("request irq for btnup comp1 err\n"); goto btnup_comp1_err; } hi6402_irq_mask_btn_irqs(pdata->p_irq); hi6402_irq_clr_btn_irqs(pdata->p_irq); /* enable hsdet */ hi6402_irq_write(pdata->p_irq, HI6402_REG_HSDET_CTRL, 0x19); hi6402_irq_write(pdata->p_irq, HI6402_MBHC_VREF_REG, 0x8E); //register anc hs first anc_hs_dev_register(&anc_dev, pdata); //register soundtrigger input device. ret = soundtrigger_input_init(dev); if(ret) pr_err("input registor failed: %d\n", ret); #if 0 /* check jack at first time */ if (check_headset_pluged_in(pdata)) hi6402_plug_in_detect(pdata); #endif pdata->miscdev.minor = MISC_DYNAMIC_MINOR; pdata->miscdev.name = "hi6402_mbhc"; ret = misc_register(&pdata->miscdev); if (ret) { loge("%s : hisi 6421 spk_device register failed", __FUNCTION__); goto btnup_comp1_err; } if (!dsm_audio_client) { dsm_audio_client = dsm_register_client(&dsm_audio); } pr_info("%s : hi6402 mbhc probe ok \n", __FUNCTION__); return ret; btnup_comp1_err: free_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], pdata); btndown_comp1_err: free_irq(pdata->irq[HI6402_IRQ_BTNDOWN_ECO], pdata); btndown_eco_err: free_irq(pdata->irq[HI6402_IRQ_BTNUP_ECO], pdata); btnup_eco_err: free_irq(pdata->irq[HI6402_IRQ_PLUGIN], pdata); plugin_err: free_irq(pdata->irq[HI6402_IRQ_PLUGOUT], pdata); plugout_err: free_irq(pdata->irq[HI6402_IRQ_SOUND_TRIGER], pdata); sound_triger_err: free_irq(pdata->irq[HI6402_IRQ_PLL_UNLOCK], pdata); pll_unlock_err: wake_lock_destroy(&pdata->soundtrigger_wake_lock); wake_lock_destroy(&pdata->wake_lock); mutex_destroy(&pdata->plug_mutex); mutex_destroy(&pdata->status_mutex); return ret; }
static bool hi6402_check_headset_in(void *pdata) { return check_headset_pluged_in((struct hi6402_mbhc_platform_data *)pdata); }
void hi6402_btn_down(struct hi6402_mbhc_platform_data *pdata) { int saradc_value = 0; if (!check_headset_pluged_in(pdata)) { pr_info("%s(%u) : hs pluged out \n", __FUNCTION__, __LINE__); return; } wake_lock(&pdata->wake_lock); if (HISI_JACK_HEADSET == pdata->hs_status) { /* micbias on */ hi6402_irq_micbias_mbhc_enable(pdata->p_irq, true); /* auto read */ saradc_value = hi6402_read_saradc_value_detect(pdata); /* micbias off */ hi6402_irq_micbias_mbhc_enable(pdata->p_irq, false); msleep(30); if (!check_headset_pluged_in(pdata)) { pr_info("%s(%u) : hs pluged out \n", __FUNCTION__, __LINE__); goto end; } if ((saradc_value >= pdata->hs_4_pole_min_voltage) && (saradc_value <= pdata->hs_4_pole_max_voltage)) { pr_info("%s(%u) : process as btn up! \n", __FUNCTION__, __LINE__); mutex_lock(&pdata->status_mutex); pdata->btn_report = 0; mutex_unlock(&pdata->status_mutex); } else if ((saradc_value >= pdata->btn_play_min_voltage) && (saradc_value <= pdata->btn_play_max_voltage)) { mutex_lock(&pdata->status_mutex); pdata->btn_report = SND_JACK_BTN_0; mutex_unlock(&pdata->status_mutex); } else if (pdata->btn_volume_up_min_voltage < saradc_value && saradc_value <= pdata->btn_volume_up_max_voltage) { mutex_lock(&pdata->status_mutex); pdata->btn_report = SND_JACK_BTN_1; mutex_unlock(&pdata->status_mutex); } else if (pdata->btn_volume_down_min_voltage < saradc_value && saradc_value <= pdata->btn_volume_down_max_voltage) { mutex_lock(&pdata->status_mutex); pdata->btn_report = SND_JACK_BTN_2; mutex_unlock(&pdata->status_mutex); } else { msleep(30); hi6402_plug_in_detect(pdata); goto end; } if (!check_headset_pluged_in(pdata)) { pr_info("%s(%u) : hs pluged out \n", __FUNCTION__, __LINE__); goto end; } /*btn_report key event*/ pr_info("%s(%u): btn_report type = 0x%x, status=0x%x\n", __FUNCTION__, __LINE__, pdata->btn_report, pdata->hs_status); hi6402_soc_jack_report(pdata->btn_report, HI6402_BTN_MASK); } end: wake_unlock(&pdata->wake_lock); return; }
void hi6402_plug_in_detect(struct hi6402_mbhc_platform_data *pdata) { int saradc_value = 0; int anc_type = ANC_HS_REVERT_4POLE; if (!check_headset_pluged_in(pdata)) return; wake_lock(&pdata->wake_lock); mutex_lock(&pdata->plug_mutex); if(check_anc_hs_support()) { //mask btn irqs while control boost hi6402_irq_mask_btn_irqs(pdata->p_irq); anc_hs_start_charge(); } /* micbias on */ hi6402_irq_micbias_mbhc_enable(pdata->p_irq, true); /* mbhc on (normal not auto) */ hi6402_mbhc_on(pdata); /* read hs value */ saradc_value = hi6402_read_saradc_value_detect(pdata); mutex_lock(&pdata->status_mutex); if (pdata->hs_3_pole_max_voltage >= saradc_value) { /* 3-pole headphone */ pr_info("%s : 3 pole is pluged in\n", __FUNCTION__); pdata->hs_status = HISI_JACK_HEADPHONE; anc_type = ANC_HS_3POLE; } else if (pdata->hs_4_pole_min_voltage <= saradc_value && pdata->hs_4_pole_max_voltage >= saradc_value) { /* 4-pole headset */ pr_info("%s : 4 pole is pluged in\n", __FUNCTION__); pdata->hs_status = HISI_JACK_HEADSET; anc_type = ANC_HS_4POLE; } else { /* invert 4-pole headset */ pr_info("%s : need further detect, report as 3-pole headphone\n", __FUNCTION__); pdata->hs_status = HISI_JACK_INVERT; anc_type = ANC_HS_REVERT_4POLE; } mutex_unlock(&pdata->status_mutex); if(check_anc_hs_support()) { //mask btn irqs while control boost hi6402_irq_mask_btn_irqs(pdata->p_irq); anc_hs_charge_detect(saradc_value, anc_type); } hi6402_jack_report(pdata); hi6402_mbhc_enable_ldo8(pdata, true); /* micbias off */ hi6402_irq_micbias_mbhc_enable(pdata->p_irq, false); mutex_unlock(&pdata->plug_mutex); wake_unlock(&pdata->wake_lock); }
static int hi6402_mbhc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hi6402_mbhc_platform_data *pdata = NULL; const struct of_device_id *match = NULL; int ret = 0; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (NULL == pdata){ dev_err(dev, "cannot allocate hisi 6421 spk platform data\n"); return -ENOMEM; } match = of_match_device(hi6402_mbhc_of_match, dev); if (!match) { pr_err("get device info err\n"); return -ENOENT; } else { struct device_node *node = dev->of_node; int temp; /* get board defination */ if (!of_property_read_u32(node, "hisilicon,hi6402_hs_det_inv", &temp)) pdata->hs_det_inv = temp; else pdata->hs_det_inv = 0; if (!of_property_read_u32(node, "hisilicon,hs_3_pole_min_voltage", &temp)) pdata->hs_3_pole_min_voltage = temp; else pdata->hs_3_pole_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,hs_3_pole_max_voltage", &temp)) pdata->hs_3_pole_max_voltage = temp; else pdata->hs_3_pole_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,hs_4_pole_min_voltage", &temp)) pdata->hs_4_pole_min_voltage = temp; else pdata->hs_4_pole_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,hs_4_pole_max_voltage", &temp)) pdata->hs_4_pole_max_voltage = temp; else pdata->hs_4_pole_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_play_min_voltage", &temp)) pdata->btn_play_min_voltage = temp; else pdata->btn_play_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_play_max_voltage", &temp)) pdata->btn_play_max_voltage = temp; else pdata->btn_play_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_up_min_voltage", &temp)) pdata->btn_volume_up_min_voltage = temp; else pdata->btn_volume_up_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_up_max_voltage", &temp)) pdata->btn_volume_up_max_voltage = temp; else pdata->btn_volume_up_max_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_down_min_voltage", &temp)) pdata->btn_volume_down_min_voltage = temp; else pdata->btn_volume_down_min_voltage = 0; if (!of_property_read_u32(node, "hisilicon,btn_volume_down_max_voltage", &temp)) pdata->btn_volume_down_max_voltage = temp; else pdata->btn_volume_down_max_voltage = 0; } pdata->p_irq = dev_get_drvdata(pdev->dev.parent); if (!pdata->p_irq) { dev_err(dev, "get parend device error\n"); return -ENOENT; } #ifdef CONFIG_SWITCH pdata->sdev.name = "h2w"; ret = switch_dev_register(&pdata->sdev); if (ret) { pr_err("%s : error registering switch device %d\n", __FUNCTION__, ret); return ret; } #endif wake_lock_init(&pdata->wake_lock, WAKE_LOCK_SUSPEND, "hisi-6402-mbhc"); mutex_init(&pdata->plug_mutex); mutex_init(&pdata->status_mutex); /* get irqs */ pdata->irq[HI6402_IRQ_PLUGOUT] = platform_get_irq_byname(pdev, "plugout"); if (0 > pdata->irq[HI6402_IRQ_PLUGOUT]) return -ENOENT; pdata->irq[HI6402_IRQ_PLUGIN] = platform_get_irq_byname(pdev, "plugin"); if (0 > pdata->irq[HI6402_IRQ_PLUGIN]) return -ENOENT; pdata->irq[HI6402_IRQ_BTNDOWN_ECO] = platform_get_irq_byname(pdev, "btndown_eco"); if (0 > pdata->irq[HI6402_IRQ_BTNDOWN_ECO]) return -ENOENT; pdata->irq[HI6402_IRQ_BTNUP_ECO] = platform_get_irq_byname(pdev, "btnup_eco"); if (0 > pdata->irq[HI6402_IRQ_BTNUP_ECO]) return -ENOENT; pdata->irq[HI6402_IRQ_BTNDOWN_COMP1] = platform_get_irq_byname(pdev, "btndown"); if (0 > pdata->irq[HI6402_IRQ_BTNDOWN_COMP1]) return -ENOENT; pdata->irq[HI6402_IRQ_BTNUP_COMP1] = platform_get_irq_byname(pdev, "btnup"); if (0 > pdata->irq[HI6402_IRQ_BTNUP_COMP1]) return -ENOENT; pdata->headset_plug_in_delay_wq = create_singlethread_workqueue("headset_plug_in_delay_wq"); if (!(pdata->headset_plug_in_delay_wq)) { pr_err("%s : headset_plug_in_delay_wq create failed", __FUNCTION__); ret = -ENOMEM; goto headset_plug_in_wq_err; } INIT_DELAYED_WORK(&pdata->headset_plug_in_delay_work, hi6402_plug_in_workfunc); pdata->headset_plug_out_delay_wq = create_singlethread_workqueue("headset_plug_out_delay_wq"); if (!(pdata->headset_plug_out_delay_wq)) { pr_err("%s : headset_plug_out_delay_wq create failed", __FUNCTION__); ret = -ENOMEM; goto headset_plug_out_wq_err; } INIT_DELAYED_WORK(&pdata->headset_plug_out_delay_work, hi6402_plug_out_workfunc); pdata->headset_btn_up_delay_wq = create_singlethread_workqueue("headset_btn_up_delay_wq"); if (!(pdata->headset_btn_up_delay_wq)) { pr_err("%s : headset_btn_up_delay_wq create failed", __FUNCTION__); ret = -ENOMEM; goto headset_btn_up_wq_err; } INIT_DELAYED_WORK(&pdata->headset_btn_up_delay_work, hi6402_btnup_workfunc); pdata->headset_btn_down_delay_wq = create_singlethread_workqueue("headset_btn_down_delay_wq"); if (!(pdata->headset_btn_down_delay_wq)) { pr_err("%s : headset_btn_down_delay_wq create failed", __FUNCTION__); ret = -ENOMEM; goto headset_btn_down_wq_err; } INIT_DELAYED_WORK(&pdata->headset_btn_down_delay_work, hi6402_btndown_workfunc); /* irq request : plugout */ ret = request_irq(pdata->irq[HI6402_IRQ_PLUGOUT], hi6402_plugout_handler, IRQF_DISABLED | IRQF_NO_SUSPEND, "plugout", pdata); if (0 > ret) goto plugout_err; /* irq request : plugin */ ret = request_irq(pdata->irq[HI6402_IRQ_PLUGIN], hi6402_plugin_handler, IRQF_DISABLED | IRQF_NO_SUSPEND, "plugin", pdata); if (0 > ret) goto plugin_err; /* irq request : button up(eco mode) */ ret = request_irq(pdata->irq[HI6402_IRQ_BTNUP_ECO], hi6402_btnup_eco_handler, IRQF_DISABLED | IRQF_NO_SUSPEND, "btnup_eco", pdata); if (0 > ret) goto btnup_eco_err; /* irq request : button down(eco mode) */ ret = request_irq(pdata->irq[HI6402_IRQ_BTNDOWN_ECO], hi6402_btndown_eco_handler, IRQF_DISABLED | IRQF_NO_SUSPEND, "btndown_eco", pdata); if (0 > ret) goto btndown_eco_err; /* irq request : button down */ ret = request_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], hi6402_btndown_handler, IRQF_DISABLED | IRQF_NO_SUSPEND, "btndown_comp1", pdata); if (0 > ret) goto btndown_comp1_err; /* irq request : button up */ ret = request_irq(pdata->irq[HI6402_IRQ_BTNUP_COMP1], hi6402_btnup_handler, IRQF_DISABLED | IRQF_NO_SUSPEND, "btnup_comp1", pdata); if (0 > ret) goto btnup_comp1_err; /* mask all btn interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_ECO], true); mask_irq(pdata->irq[HI6402_IRQ_BTNUP_ECO], true); mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], true); mask_irq(pdata->irq[HI6402_IRQ_BTNUP_COMP1], true); #if 0 /* todo in cs version */ /* check jack at first time */ if (check_headset_pluged_in(pdata)) hi6402_plug_in_detect(pdata); #endif /* enable hsdet */ hi6402_irq_write(pdata->p_irq, HI6402_REG_HSDET_CTRL, 0x1); hi6402_irq_write(pdata->p_irq, HI6402_MBHC_VREF_REG, 0x8c); pdata->miscdev.minor = MISC_DYNAMIC_MINOR; pdata->miscdev.name = "hi6402_mbhc"; ret = misc_register(&pdata->miscdev); if (ret) loge("%s : hisi 6421 spk_device register failed", __FUNCTION__); return ret; btnup_comp1_err: free_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], pdata); btndown_comp1_err: free_irq(pdata->irq[HI6402_IRQ_BTNDOWN_ECO], pdata); btndown_eco_err: free_irq(pdata->irq[HI6402_IRQ_BTNUP_ECO], pdata); btnup_eco_err: free_irq(pdata->irq[HI6402_IRQ_PLUGIN], pdata); plugin_err: free_irq(pdata->irq[HI6402_IRQ_PLUGOUT], pdata); plugout_err: if(pdata->headset_btn_down_delay_wq) { cancel_delayed_work(&pdata->headset_btn_down_delay_work); flush_workqueue(pdata->headset_btn_down_delay_wq); destroy_workqueue(pdata->headset_btn_down_delay_wq); } headset_btn_down_wq_err: if(pdata->headset_btn_up_delay_wq) { cancel_delayed_work(&pdata->headset_btn_up_delay_work); flush_workqueue(pdata->headset_btn_up_delay_wq); destroy_workqueue(pdata->headset_btn_up_delay_wq); } headset_btn_up_wq_err: if(pdata->headset_plug_out_delay_wq) { cancel_delayed_work(&pdata->headset_plug_out_delay_work); flush_workqueue(pdata->headset_plug_out_delay_wq); destroy_workqueue(pdata->headset_plug_out_delay_wq); } headset_plug_out_wq_err: if(pdata->headset_plug_in_delay_wq) { cancel_delayed_work(&pdata->headset_plug_in_delay_work); flush_workqueue(pdata->headset_plug_in_delay_wq); destroy_workqueue(pdata->headset_plug_in_delay_wq); } headset_plug_in_wq_err: return ret; }
void hi6402_btndown_workfunc(struct work_struct *work) { int saradc_value = 0; struct hi6402_mbhc_platform_data *pdata = container_of(work, struct hi6402_mbhc_platform_data, headset_btn_down_delay_work.work); BUG_ON(NULL == pdata); if (!check_headset_pluged_in(pdata)) { pr_info("%s(%u) : hs pluged out \n", __FUNCTION__, __LINE__); return; } pr_info("%s(%u) : btn down !\n", __FUNCTION__, __LINE__); wake_lock(&pdata->wake_lock); if (HISI_JACK_HEADSET == pdata->hs_status) { /* power on hs-micbias */ //hi6401_hs_micbias_saradc_enable(codec, true); //saradc_value = hi6401_read_saradc_value(codec); //pr_info("%s(%u) :saradc_value: %d \n", __FUNCTION__, __LINE__, saradc_value); //hi6401_hs_micbias_saradc_enable(codec, false); if (!check_headset_pluged_in(pdata)) { pr_info("%s(%u) : hs pluged out \n", __FUNCTION__, __LINE__); /* mask all btn interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNUP_COMP1], true); mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], true); goto end; } if ((saradc_value >= pdata->hs_4_pole_min_voltage) && (saradc_value <= pdata->hs_4_pole_max_voltage)) { pr_info("%s(%u) : process as btn up! \n", __FUNCTION__, __LINE__); mutex_lock(&pdata->status_mutex); pdata->btn_report = 0; mutex_unlock(&pdata->status_mutex); } else if ((saradc_value >= pdata->btn_play_min_voltage) && (saradc_value <= pdata->btn_play_max_voltage)) { mutex_lock(&pdata->status_mutex); pdata->btn_report = SND_JACK_BTN_0; mutex_unlock(&pdata->status_mutex); } else if (pdata->btn_volume_up_min_voltage < saradc_value && saradc_value <= pdata->btn_volume_up_max_voltage) { mutex_lock(&pdata->status_mutex); pdata->btn_report = SND_JACK_BTN_1; mutex_unlock(&pdata->status_mutex); } else if (pdata->btn_volume_down_min_voltage < saradc_value && saradc_value <= pdata->btn_volume_down_max_voltage) { mutex_lock(&pdata->status_mutex); pdata->btn_report = SND_JACK_BTN_2; mutex_unlock(&pdata->status_mutex); } else { msleep(30); hi6402_plug_in_detect(pdata); goto end; } if (!check_headset_pluged_in(pdata)) { pr_info("%s(%u) : hs pluged out \n", __FUNCTION__, __LINE__); /* mask all btn interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNUP_COMP1], true); mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], true); goto end; } /*btn_report key event*/ pr_info("%s(%u): btn_report type = 0x%x, status=0x%x\n", __FUNCTION__, __LINE__, pdata->btn_report, pdata->hs_status); hi6402_soc_jack_report(pdata->btn_report, HI6402_BTN_MASK); } /* mask btn down interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNDOWN_COMP1], true); /* unmask btn up interrupt*/ mask_irq(pdata->irq[HI6402_IRQ_BTNUP_COMP1], false); end: wake_unlock(&pdata->wake_lock); return; }