/* * Copyright (C) 2013 Spreadtrum Communications Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_OF #include #include #endif #include #include #include //==================== debug ==================== #define ENTER \ do{ if(debug_level >= 1) printk(KERN_INFO "[SPRD_HEADSET_DBG][%d] func: %s line: %04d\n", adie_type, __func__, __LINE__); }while(0) #define PRINT_DBG(format,x...) \ do{ if(debug_level >= 1) printk(KERN_INFO "[SPRD_HEADSET_DBG][%d] " format, adie_type, ## x); }while(0) #define PRINT_INFO(format,x...) \ do{ printk(KERN_INFO "[SPRD_HEADSET_INFO][%d] " format, adie_type, ## x); }while(0) #define PRINT_WARN(format,x...) \ do{ printk(KERN_INFO "[SPRD_HEADSET_WARN][%d] " format, adie_type, ## x); }while(0) #define PRINT_ERR(format,x...) \ do{ printk(KERN_ERR "[SPRD_HEADSET_ERR][%d] func: %s line: %04d info: " format, adie_type, __func__, __LINE__, ## x); }while(0) //==================== debug ==================== /********************************************** * The micro ADPGAR_BYP_SELECT is used for avoiding the Bug#298417, * please refer to Bug#298417 to confirm your configuration. **********************************************/ #define ADPGAR_BYP_SELECT #define PLUG_CONFIRM_COUNT (1) #define NO_MIC_RETRY_COUNT (0) #define ADC_READ_COUNT (5) #define ADC_READ_LOOP (2) #define ADC_GND (300) #define SCI_ADC_GET_VALUE_COUNT (50) #define EIC3_DBNC_CTRL (0x4C) #define SW_DBNC_VALUE (10) #define DBNC_CNT3_VALUE (30) #define DBNC_CNT3_SHIFT (0) #define DBNC_CNT3_MASK (0xFFF << DBNC_CNT3_SHIFT) #define EIC5_DBNC_CTRL (0x54) #define DBNC_CNT5_VALUE (25) #define DBNC_CNT5_SHIFT (0) #define DBNC_CNT5_MASK (0xFFF << DBNC_CNT5_SHIFT) #define EIC8_DBNC_CTRL (0x60) #define DBNC_CNT8_VALUE (25) #define DBNC_CNT8_SHIFT (0) #define DBNC_CNT8_MASK (0xFFF << DBNC_CNT8_SHIFT) #define CLK_AUD_HID_EN (BIT(4)) #define CLK_AUD_HBD_EN (BIT(3)) #define HEADMIC_DETECT_BASE (ANA_AUDCFGA_INT_BASE) #define HEADMIC_DETECT_REG(X) (HEADMIC_DETECT_BASE + (X)) #define HEADMIC_DETECT_GLB_REG(X) (ANA_REGS_GLB_BASE + (X)) #define HDT_EN (BIT(5)) #define AUD_EN (BIT(4)) //no use #define HEADMIC_BUTTON_BASE (ANA_HDT_INT_BASE) #define HEADMIC_BUTTON_REG(X) (HEADMIC_BUTTON_BASE + (X)) #define HID_CFG0 (0x0080) #define HID_CFG2 (0x0088) #define HID_CFG3 (0x008C) #define HID_CFG4 (0x0090) //no use #define ANA_PMU0 (0x0000) #define ANA_CDC1 (0x0020) #define ANA_HDT0 (0x0068) #define ANA_STS0 (0x0074) #define AUDIO_HEADMIC_SLEEP_EN (BIT(6)) #define AUDIO_ADPGAR_BYP_SHIFT (10) #define AUDIO_ADPGAR_BYP_MASK (0x3 << AUDIO_ADPGAR_BYP_SHIFT) #define AUDIO_ADPGAR_BYP_NORMAL (0) #define AUDIO_ADPGAR_BYP_ADC_PGAR1_2_ADCR (1) #define AUDIO_ADPGAR_BYP_HEADMIC_2_ADCR (2) #define AUDIO_ADPGAR_BYP_ALL_DISCONNECTED (3) #define AUDIO_HEAD_SDET_SHIFT (5) #define AUDIO_HEAD_SDET_MASK (0x3 << AUDIO_HEAD_SDET_SHIFT) #define AUDIO_HEAD_SDET_2P1 (3) #define AUDIO_HEAD_SDET_2P3 (2) #define AUDIO_HEAD_SDET_2P5 (1) #define AUDIO_HEAD_SDET_2P7 (0) #define AUDIO_HEAD_INS_VREF_SHIFT (8) #define AUDIO_HEAD_INS_VREF_MASK (0x3 << AUDIO_HEAD_INS_VREF_SHIFT) #define AUDIO_HEAD_INS_VREF_2P1 (3) #define AUDIO_HEAD_INS_VREF_2P3 (2) #define AUDIO_HEAD_INS_VREF_2P5 (1) #define AUDIO_HEAD_INS_VREF_2P7 (0) #define AUDIO_HEAD_SBUT_SHIFT (1) #define AUDIO_HEAD_SBUT_MASK (0xF << AUDIO_HEAD_SBUT_SHIFT) #define AUDIO_HEAD_INS_PD (BIT(10)) #define AUDIO_HEADDETECT_PD (BIT(7)) #define AUDIO_V2ADC_EN (BIT(15)) #define AUDIO_HEAD2ADC_SEL_SHIFT (11) #define AUDIO_HEAD2ADC_SEL_MASK (0xF << AUDIO_HEAD2ADC_SEL_SHIFT) #define AUDIO_HEAD2ADC_SEL_DISABLE (0) #define AUDIO_HEAD2ADC_SEL_HEADMIC_IN (1) #define AUDIO_HEAD2ADC_SEL_HEADSET_L_INT (3) #define AUDIO_HEAD2ADC_SEL_HEAD_DRO_L (4) #define AUDIO_HEAD_BUTTON (BIT(11)) #define AUDIO_HEAD_INSERT (BIT(10)) #define AUDIO_HEAD_INSERT_2 (BIT(9)) #define AUDIO_PMUR1 (BIT(0)) #define ANA_PMU1 (0x0004) #define ABS(x) (((x) < (0)) ? (-(x)) : (x)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #define headset_reg_read(addr) \ do { \ sci_adi_read(addr); \ } while(0) #define headset_reg_set_val(addr, val, mask, shift) \ do { \ uint32_t temp; \ temp = sci_adi_read(addr); \ temp = (temp & (~mask)) | ((val) << (shift)); \ sci_adi_raw_write(addr, temp); \ } while(0) #define headset_reg_clr_bit(addr, bit) \ do { \ uint32_t temp; \ temp = sci_adi_read(addr); \ temp = temp & (~bit); \ sci_adi_raw_write(addr, temp); \ } while(0) #define headset_reg_set_bit(addr, bit) \ do { \ uint32_t temp; \ temp = sci_adi_read(addr); \ temp = temp | bit; \ sci_adi_raw_write(addr, temp); \ } while(0) static inline uint32_t headset_reg_get_bit(uint32_t addr, uint32_t bit) { uint32_t temp; temp = sci_adi_read(addr); temp = temp & bit; return temp; } typedef enum sprd_headset_type { HEADSET_4POLE_NORMAL, HEADSET_NO_MIC, HEADSET_4POLE_NOT_NORMAL, HEADSET_APPLE, HEADSET_TYPE_ERR = -1, } SPRD_HEADSET_TYPE; static struct delayed_work reg_dump_work; static struct workqueue_struct *reg_dump_work_queue; #ifdef ADPGAR_BYP_SELECT static struct delayed_work adpgar_byp_select_work; static struct workqueue_struct *adpgar_byp_select_work_queue; #endif struct sprd_headset_auxadc_cal_l { u32 A; u32 B; u32 E; u32 cal_type; }; #define SPRD_HEADSET_AUXADC_CAL_NO 0 #define SPRD_HEADSET_AUXADC_CAL_DO 1 static struct sprd_headset_auxadc_cal_l adc_cal_headset = { 0, 0,0,SPRD_HEADSET_AUXADC_CAL_NO, }; static DEFINE_SPINLOCK(irq_button_lock); static DEFINE_SPINLOCK(irq_detect_lock); static DEFINE_SPINLOCK(irq_detect_mic_lock); static int detect_err_count = 0; static int debug_level = 0; static int adie_type = -1; static int gpio_detect_value_last = 0; static int gpio_button_value_last = 0; static volatile int button_state_last = 0; //0==released, 1==pressed static int current_key_code = KEY_RESERVED; static int plug_state_last = 0; //if the hardware detected the headset is plug in, set plug_state_last = 1 static struct wake_lock headset_detect_wakelock; static struct wake_lock headset_button_wakelock; static struct semaphore headset_sem; static struct platform_device *this_pdev = NULL; static struct sprd_headset headset = { .sdev = { .name = "h2w", }, }; //======================== audio codec ======================== static struct sprd_headset_power { struct regulator *head_mic; struct regulator *vcom_buf; struct regulator *vbo; } sprd_hts_power; static int sprd_headset_power_get(struct device *dev, struct regulator **regu, const char *id) { if (!*regu) { *regu = regulator_get(dev, id); if (IS_ERR(*regu)) { pr_err("ERR:Failed to request %ld: %s\n", PTR_ERR(*regu), id); *regu = 0; return PTR_ERR(*regu); } } return 0; } static int sprd_headset_power_init(struct device *dev) { int ret = 0; ret = sprd_headset_power_get(dev, &sprd_hts_power.head_mic, "HEADMICBIAS"); if (ret || (sprd_hts_power.head_mic == NULL)) { sprd_hts_power.head_mic = 0; return ret; } regulator_set_voltage(sprd_hts_power.head_mic, 950000, 950000); ret = sprd_headset_power_get(dev, &sprd_hts_power.vcom_buf, "VCOM_BUF"); if (ret) { sprd_hts_power.vcom_buf = 0; goto __err1; } ret = sprd_headset_power_get(dev, &sprd_hts_power.vbo, "VBO"); if (ret) { sprd_hts_power.vbo = 0; goto __err2; } goto __ok; __err2: regulator_put(sprd_hts_power.vcom_buf); __err1: regulator_put(sprd_hts_power.head_mic); __ok: return ret; } static void sprd_headset_power_deinit(void) { regulator_put(sprd_hts_power.head_mic); regulator_put(sprd_hts_power.vcom_buf); regulator_put(sprd_hts_power.vbo); } static int sprd_headset_audio_block_is_running(struct device *dev) { return regulator_is_enabled(sprd_hts_power.vcom_buf) || regulator_is_enabled(sprd_hts_power.vbo); } static int sprd_headset_audio_headmic_sleep_disable(struct device *dev, int on) { int ret = 0; if (!sprd_hts_power.head_mic) { return -1; } if (on) { ret = regulator_enable(sprd_hts_power.vbo); ret = regulator_set_mode(sprd_hts_power.head_mic, REGULATOR_MODE_NORMAL); } else { ret = regulator_disable(sprd_hts_power.vbo); if (sprd_headset_audio_block_is_running(dev)) { ret = regulator_set_mode(sprd_hts_power.head_mic, REGULATOR_MODE_NORMAL); } else { ret = regulator_set_mode(sprd_hts_power.head_mic, REGULATOR_MODE_STANDBY); } } return ret; } static int sprd_headset_headmic_bias_control(struct device *dev, int on) { int ret = 0; if (!sprd_hts_power.head_mic) { return -1; } if (on) { ret = regulator_enable(sprd_hts_power.head_mic); } else { ret = regulator_disable(sprd_hts_power.head_mic); } if (!ret) { /* Set HEADMIC_SLEEP when audio block closed */ if (sprd_headset_audio_block_is_running(dev)) { ret = regulator_set_mode(sprd_hts_power.head_mic, REGULATOR_MODE_NORMAL); } else { ret = regulator_set_mode(sprd_hts_power.head_mic, REGULATOR_MODE_STANDBY); } } return ret; } static BLOCKING_NOTIFIER_HEAD(hp_chain_list); int hp_register_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&hp_chain_list, nb); } EXPORT_SYMBOL(hp_register_notifier); int hp_unregister_notifier(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&hp_chain_list, nb); } EXPORT_SYMBOL(hp_unregister_notifier); #if 0 static int hp_notifier_call_chain(unsigned long val) { return (blocking_notifier_call_chain(&hp_chain_list, val, NULL) == NOTIFY_BAD) ? -EINVAL : 0; } #endif int get_hp_plug_state(void) { return !!plug_state_last; } EXPORT_SYMBOL(get_hp_plug_state); //======================== audio codec ======================== static int wrap_sci_adc_get_value(unsigned int channel, int scale) { int count = 0; int average = 0; while(count < SCI_ADC_GET_VALUE_COUNT) { average += sci_adc_get_value(channel, scale); count++; } average /= SCI_ADC_GET_VALUE_COUNT; return average; } /* on = 0: open headmic detect circuit */ static void headset_detect_circuit(unsigned on) { if (on) { headset_reg_clr_bit(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD_INS_PD); headset_reg_clr_bit(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEADDETECT_PD); } else { headset_reg_set_bit(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD_INS_PD); headset_reg_set_bit(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEADDETECT_PD); } } static void headset_detect_clk_en(void) { //address:0x4003_8800+0x00 headset_reg_set_bit(HEADMIC_DETECT_GLB_REG(0x00), (HDT_EN | AUD_EN)); //address:0x4003_8800+0x04 headset_reg_set_bit(HEADMIC_DETECT_GLB_REG(0x04), (CLK_AUD_HID_EN | CLK_AUD_HBD_EN)); } static void headset_detect_init(void) { headset_detect_clk_en(); /* set headset detect voltage */ headset_reg_set_bit(HEADMIC_DETECT_REG(ANA_PMU1), AUDIO_PMUR1); headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD_SDET_2P5, AUDIO_HEAD_SDET_MASK, AUDIO_HEAD_SDET_SHIFT); headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD_INS_VREF_2P1, AUDIO_HEAD_INS_VREF_MASK, AUDIO_HEAD_INS_VREF_SHIFT); } static void headmic_sleep_disable(struct device *dev, int on); static void headset_adc_en(int en) { if (en) { headset_reg_set_bit(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_V2ADC_EN); headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD2ADC_SEL_HEADMIC_IN, AUDIO_HEAD2ADC_SEL_MASK, AUDIO_HEAD2ADC_SEL_SHIFT); headmic_sleep_disable(&this_pdev->dev, 1); } else { if(debug_level <= 2) { headset_reg_clr_bit(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_V2ADC_EN); headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD2ADC_SEL_DISABLE, AUDIO_HEAD2ADC_SEL_MASK, AUDIO_HEAD2ADC_SEL_SHIFT); } headmic_sleep_disable(&this_pdev->dev, 0); } } /* is_set = 1, headset_mic to AUXADC */ static void set_adc_to_headmic(unsigned is_set) { headset_adc_en(1); if (is_set) { headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD2ADC_SEL_HEADMIC_IN, AUDIO_HEAD2ADC_SEL_MASK, AUDIO_HEAD2ADC_SEL_SHIFT); } else { headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), AUDIO_HEAD2ADC_SEL_HEADSET_L_INT, AUDIO_HEAD2ADC_SEL_MASK, AUDIO_HEAD2ADC_SEL_SHIFT); } } static void headset_button_irq_threshold(int enable) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; int audio_head_sbut = 0; audio_head_sbut = pdata->irq_threshold_buttont; if (enable) headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), audio_head_sbut, AUDIO_HEAD_SBUT_MASK, AUDIO_HEAD_SBUT_SHIFT); else headset_reg_set_val(HEADMIC_DETECT_REG(ANA_HDT0), 0xF, AUDIO_HEAD_SBUT_MASK, AUDIO_HEAD_SBUT_SHIFT); } static void headset_irq_button_enable(int enable, unsigned int irq) { unsigned long spin_lock_flags; static int current_irq_state = 1;//irq is enabled after request_irq() spin_lock_irqsave(&irq_button_lock, spin_lock_flags); if (1 == enable) { if (0 == current_irq_state) { enable_irq(irq); current_irq_state = 1; } } else { if (1 == current_irq_state) { disable_irq_nosync(irq); current_irq_state = 0; } } spin_unlock_irqrestore(&irq_button_lock, spin_lock_flags); return; } static void headset_irq_detect_enable(int enable, unsigned int irq) { unsigned long spin_lock_flags; static int current_irq_state = 1;//irq is enabled after request_irq() spin_lock_irqsave(&irq_detect_lock, spin_lock_flags); if (1 == enable) { if (0 == current_irq_state) { enable_irq(irq); current_irq_state = 1; } } else { if (1 == current_irq_state) { disable_irq_nosync(irq); current_irq_state = 0; } } spin_unlock_irqrestore(&irq_detect_lock, spin_lock_flags); return; } static void headset_irq_detect_mic_enable(int enable, unsigned int irq) { unsigned long spin_lock_flags; static int current_irq_state = 1; spin_lock_irqsave(&irq_detect_mic_lock, spin_lock_flags); if (1 == enable) { if (0 == current_irq_state) { enable_irq(irq); current_irq_state = 1; } } else { if (1 == current_irq_state) { disable_irq_nosync(irq); current_irq_state = 0; } } spin_unlock_irqrestore(&irq_detect_mic_lock, spin_lock_flags); return; } static void headmic_sleep_disable(struct device *dev, int on) { static int current_power_state = 0; if (1 == on) { if (0 == current_power_state) { sprd_headset_audio_headmic_sleep_disable(dev, 1); current_power_state = 1; } } else { if (1 == current_power_state) { sprd_headset_audio_headmic_sleep_disable(dev, 0); current_power_state = 0; } } return; } static void headmicbias_power_on(struct device *dev, int on) { static int current_power_state = 0; struct sprd_headset *ht = &headset; if (1 == on) { if (0 == current_power_state) { if(NULL != ht->platform_data->external_headmicbias_power_on) ht->platform_data->external_headmicbias_power_on(1); sprd_headset_headmic_bias_control(dev, 1); current_power_state = 1; } } else { if (1 == current_power_state) { if(NULL != ht->platform_data->external_headmicbias_power_on) ht->platform_data->external_headmicbias_power_on(0); sprd_headset_headmic_bias_control(dev, 0); current_power_state = 0; } } return; } static int ana_sts0_confirm(void) { if (0 == headset_reg_get_bit(HEADMIC_DETECT_REG(ANA_STS0), AUDIO_HEAD_INSERT)) #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 return 0; #else return 1; #endif else return 1; } static int adc_compare(int x1, int x2) { int delta = 0; int max = 0; if((x1<300) && (x2<300)) return 1; x1 = ((0==x1) ? 1 : (x1*100)); x2 = ((0==x2) ? 1 : (x2*100)); delta = ABS(x1-x2); max = MAX(x1, x2); if(delta < ((max*10)/100)) return 1; else return 0; } static int adc_get_average(int gpio_num, int gpio_value) { int i = 0; int j = 0; int k = 0; int adc_average = 0; int success = 1; int adc[ADC_READ_COUNT] = {0}; struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; //================= debug ===================== if(debug_level >= 3) { int count = 0; int adc_val = 0; int gpio_button = 0; int ana_pmu0 = 0; int ana_cfg1 = 0; int ana_hdt0 = 0; int ana_sts0 = 0; while(count < 20) { count++; adc_val = wrap_sci_adc_get_value(ADC_CHANNEL_HEADMIC, 0); gpio_button = gpio_get_value(pdata->gpio_button); ana_pmu0 = sci_adi_read(HEADMIC_DETECT_REG(ANA_PMU0)); ana_hdt0 = sci_adi_read(HEADMIC_DETECT_REG(ANA_HDT0)); ana_sts0 = sci_adi_read(HEADMIC_DETECT_REG(ANA_STS0)); PRINT_INFO("%2d: gpio_button=%d adc=%4d ana_pmu0=0x%08X ana_cfg1=0x%08X ana_hdt0=0x%08X ana_sts0=0x%08X\n", count, gpio_button, adc_val, ana_pmu0, ana_cfg1, ana_hdt0, ana_sts0); msleep(1); } } //================= debug ===================== msleep(1); if(0 == headset_reg_get_bit(HEADMIC_DETECT_REG(ANA_PMU0), AUDIO_HEADMIC_SLEEP_EN)) PRINT_INFO("AUDIO_HEADMIC_SLEEP_EN is disabled\n"); for(i=0; i< ADC_READ_LOOP; i++) { if(gpio_get_value(gpio_num) != gpio_value) { PRINT_INFO("gpio value changed!!! the adc read operation aborted (step1)\n"); return -1; } if(0 == ana_sts0_confirm()) { PRINT_INFO("ana_sts0_confirm failed!!! the adc read operation aborted (step2)\n"); return -1; } adc[0] = wrap_sci_adc_get_value(ADC_CHANNEL_HEADMIC, 0); for(j=0; jaction->flags; if(irq == ht->irq_button) { if(IRQF_TRIGGER_HIGH == type) { PRINT_DBG("IRQF_TRIGGER_HIGH is set for irq_button(%d). irq_flags = 0x%08X, ret = %d\n", ht->irq_button, irq_flags, ret); } else if(IRQF_TRIGGER_LOW == type) { PRINT_DBG("IRQF_TRIGGER_LOW is set for irq_button(%d). irq_flags = 0x%08X, ret = %d\n", ht->irq_button, irq_flags, ret); } } else if(irq == ht->irq_detect) { if(IRQF_TRIGGER_HIGH == type) { PRINT_DBG("IRQF_TRIGGER_HIGH is set for irq_detect(%d). irq_flags = 0x%08X, ret = %d\n", ht->irq_detect, irq_flags, ret); } else if(IRQF_TRIGGER_LOW == type) { PRINT_DBG("IRQF_TRIGGER_LOW is set for irq_detect(%d). irq_flags = 0x%08X, ret = %d\n", ht->irq_detect, irq_flags, ret); } } return 0; } static int headset_button_valid(int gpio_detect_value_current) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; int button_is_valid = 0; if(1 == pdata->irq_trigger_level_detect) { if(1 == gpio_detect_value_current) button_is_valid = 1; else button_is_valid = 0; } else { if(0 == gpio_detect_value_current) button_is_valid = 1; else button_is_valid = 0; } return button_is_valid; } static int headset_gpio_2_button_state(int gpio_button_value_current) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; int button_state_current = 0; if(1 == pdata->irq_trigger_level_button) { if(1 == gpio_button_value_current) button_state_current = 1; else button_state_current = 0; } else { if(0 == gpio_button_value_current) button_state_current = 1; else button_state_current = 0; } return button_state_current; //0==released, 1==pressed } static int headset_plug_confirm_by_adc(int last_gpio_detect_value) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; int adc_last = 0; int adc_current = 0; int count = 0; int adc_read_interval = 10; adc_last = adc_get_average(pdata->gpio_detect, last_gpio_detect_value); if(-1 == adc_last) { PRINT_INFO("headset_plug_confirm_by_adc failed!!!\n"); return -1; } while(count < PLUG_CONFIRM_COUNT) { msleep(adc_read_interval); adc_current = adc_get_average(pdata->gpio_detect, last_gpio_detect_value); if(-1 == adc_current) { PRINT_INFO("headset_plug_confirm_by_adc failed!!!\n"); return -1; } if(0 == adc_compare(adc_last, adc_current)) { PRINT_INFO("headset_plug_confirm_by_adc failed!!!\n"); return -1; } adc_last = adc_current; count++; } PRINT_INFO("headset_plug_confirm_by_adc success!!!\n"); return adc_current; } static int adc_get_ideal(u32 adc_mic); static SPRD_HEADSET_TYPE headset_type_detect(int last_gpio_detect_value) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; int adc_mic_average = 0; int adc_left_average = 0; int adc_mic_ideal = 0; int no_mic_retry_count = NO_MIC_RETRY_COUNT; ENTER; if(0 != pdata->gpio_switch) gpio_direction_output(pdata->gpio_switch, 0); else PRINT_INFO("automatic type switch is unsupported\n"); headset_button_irq_threshold(1); headset_detect_init(); headset_detect_circuit(1); no_mic_retry: //get adc value of left if(EIC_AUD_HEAD_INST2 == pdata->gpio_detect) { PRINT_INFO("HEADSET_DETECT_GPIO=%d, matched the reference phone, now getting adc value of left\n", pdata->gpio_detect); set_adc_to_headmic(0); msleep(100); adc_left_average = headset_plug_confirm_by_adc(last_gpio_detect_value); if(-1 == adc_left_average) return HEADSET_TYPE_ERR; } else { PRINT_INFO("HEADSET_DETECT_GPIO=%d, NOT matched the reference phone(GPIO_%d), set adc_left_average to 0\n", pdata->gpio_detect, EIC_AUD_HEAD_INST2); adc_left_average = 0; } //get adc value of mic set_adc_to_headmic(1); msleep(50); adc_mic_average = headset_plug_confirm_by_adc(last_gpio_detect_value); if(-1 == adc_mic_average) return HEADSET_TYPE_ERR; adc_mic_ideal = adc_get_ideal(adc_mic_average); PRINT_INFO("adc_mic_average=%d, adc_mic_ideal=%d\n", adc_mic_average, adc_mic_ideal); if(adc_mic_ideal >= 0) { adc_mic_average = adc_mic_ideal; } PRINT_INFO("adc_mic_average = %d\n", adc_mic_average); PRINT_INFO("adc_left_average = %d\n", adc_left_average); if((gpio_get_value(pdata->gpio_detect)) != last_gpio_detect_value) { PRINT_INFO("software debance (gpio check)!!!(headset_type_detect)\n"); return HEADSET_TYPE_ERR; } if(0 == ana_sts0_confirm()) { PRINT_INFO("software debance (ana_sts0_confirm)!!!(headset_type_detect)\n"); return HEADSET_TYPE_ERR; } if((adc_mic_average < pdata->adc_threshold_3pole_detect)) { if(0 != no_mic_retry_count) { PRINT_INFO("no_mic_retry\n"); no_mic_retry_count--; goto no_mic_retry; } return HEADSET_NO_MIC; } else if((adc_left_average < ADC_GND) && (adc_mic_average > ADC_GND)) return HEADSET_4POLE_NORMAL; else if((adc_left_average > ADC_GND) && (adc_mic_average > ADC_GND) && (ABS(adc_mic_average - adc_left_average) < ADC_GND)) return HEADSET_4POLE_NOT_NORMAL; else return HEADSET_TYPE_ERR; return HEADSET_TYPE_ERR; } static void button_release_verify(void) { struct sprd_headset *ht = &headset; if(1 == button_state_last) { input_event(ht->input_dev, EV_KEY, current_key_code, 0); input_sync(ht->input_dev); button_state_last = 0; PRINT_INFO("headset button released by force!!! current_key_code = %d(0x%04X)\n", current_key_code, current_key_code); if (1 == ht->platform_data->irq_trigger_level_button) headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_HIGH); else headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_LOW); } } static void headset_button_work_func(struct work_struct *work) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; int gpio_button_value_current = 0; int button_state_current = 0; int adc_mic_average = 0; int i = 0; int adc_ideal = 0; down(&headset_sem); set_adc_to_headmic(1); ENTER; gpio_button_value_current = gpio_get_value(pdata->gpio_button); if(gpio_button_value_current != gpio_button_value_last) { PRINT_INFO("software debance (step 1: gpio check)!!!(headset_button_work_func)\n"); #ifdef ADPGAR_BYP_SELECT queue_delayed_work(adpgar_byp_select_work_queue, &adpgar_byp_select_work, msecs_to_jiffies(0)); #endif goto out; } button_state_current = headset_gpio_2_button_state(gpio_button_value_current); if(1 == button_state_current) {//pressed! if(ht->platform_data->nbuttons > 0) { adc_mic_average = adc_get_average(pdata->gpio_button, gpio_button_value_last); if(-1 == adc_mic_average) { PRINT_INFO("software debance (step 3: adc check)!!!(headset_button_work_func)(pressed)\n"); #ifdef ADPGAR_BYP_SELECT queue_delayed_work(adpgar_byp_select_work_queue, &adpgar_byp_select_work, msecs_to_jiffies(0)); #endif goto out; } adc_ideal = adc_get_ideal(adc_mic_average); PRINT_INFO("adc_mic_average=%d, adc_ideal=%d\n", adc_mic_average, adc_ideal); if (adc_ideal >= 0) adc_mic_average = adc_ideal; PRINT_INFO("adc_mic_average = %d\n", adc_mic_average); for (i = 0; i < ht->platform_data->nbuttons; i++) { if (adc_mic_average >= ht->platform_data->headset_buttons[i].adc_min && adc_mic_average < ht->platform_data->headset_buttons[i].adc_max) { current_key_code = ht->platform_data->headset_buttons[i].code; break; } current_key_code = KEY_RESERVED; } } if(0 == button_state_last) { input_event(ht->input_dev, EV_KEY, current_key_code, 1); input_sync(ht->input_dev); button_state_last = 1; PRINT_INFO("headset button pressed! current_key_code = %d(0x%04X)\n", current_key_code, current_key_code); } else { PRINT_ERR("headset button pressed already! current_key_code = %d(0x%04X)\n", current_key_code, current_key_code); #ifdef ADPGAR_BYP_SELECT queue_delayed_work(adpgar_byp_select_work_queue, &adpgar_byp_select_work, msecs_to_jiffies(0)); #endif } if (1 == ht->platform_data->irq_trigger_level_button) headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_LOW); else headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_HIGH); headset_irq_button_enable(1, ht->irq_button); } else { //released! if(1 == button_state_last) { input_event(ht->input_dev, EV_KEY, current_key_code, 0); input_sync(ht->input_dev); button_state_last = 0; PRINT_INFO("headset button released! current_key_code = %d(0x%04X)\n", current_key_code, current_key_code); } else PRINT_ERR("headset button released already! current_key_code = %d(0x%04X)\n", current_key_code, current_key_code); if (1 == ht->platform_data->irq_trigger_level_button) headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_HIGH); else headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_LOW); headset_irq_button_enable(1, ht->irq_button); } out: headset_adc_en(0); headset_irq_button_enable(1, ht->irq_button); //wake_unlock(&headset_button_wakelock); up(&headset_sem); return; } static void headset_detect_work_func(struct work_struct *work) { struct sprd_headset *ht = &headset; struct sprd_headset_platform_data *pdata = ht->platform_data; SPRD_HEADSET_TYPE headset_type; int plug_state_current = 0; int gpio_detect_value_current = 0; down(&headset_sem); ENTER; if (sprd_hts_power.head_mic == NULL) { sprd_headset_power_init(&this_pdev->dev); } if (sprd_hts_power.head_mic == NULL ) { PRINT_INFO("sprd_headset_power_init fail 0 \n"); goto out; } if(0 == plug_state_last) { //schedule_timeout_uninterruptible(msecs_to_jiffies(10)); headmicbias_power_on(&this_pdev->dev, 1); } if(0 == plug_state_last) { gpio_detect_value_current = gpio_get_value(pdata->gpio_detect); PRINT_INFO("gpio_detect_value_current = %d, gpio_detect_value_last = %d, plug_state_last = %d\n", gpio_detect_value_current, gpio_detect_value_last, plug_state_last); if(gpio_detect_value_current != gpio_detect_value_last) { PRINT_INFO("software debance (step 1)!!!(headset_detect_work_func)\n"); goto out; } if(1 == pdata->irq_trigger_level_detect) { if(1 == gpio_detect_value_current) plug_state_current = 1; else plug_state_current = 0; } else { if(0 == gpio_detect_value_current) plug_state_current = 1; else plug_state_current = 0; } } else plug_state_current = 0;//no debounce for plug out!!! if(1 == plug_state_current && 0 == plug_state_last) { headset_type = headset_type_detect(gpio_detect_value_last); headset_adc_en(0); switch (headset_type) { case HEADSET_TYPE_ERR: detect_err_count ++; PRINT_INFO("headset_type = %d detect_err_count = %d(HEADSET_TYPE_ERR)\n", headset_type,detect_err_count); goto out; case HEADSET_4POLE_NOT_NORMAL: PRINT_INFO("headset_type = %d (HEADSET_4POLE_NOT_NORMAL)\n", headset_type); if(0 != pdata->gpio_switch) gpio_direction_output(pdata->gpio_switch, 1); break; case HEADSET_4POLE_NORMAL: PRINT_INFO("headset_type = %d (HEADSET_4POLE_NORMAL)\n", headset_type); if(0 != pdata->gpio_switch) gpio_direction_output(pdata->gpio_switch, 0); break; case HEADSET_NO_MIC: PRINT_INFO("headset_type = %d (HEADSET_NO_MIC)\n", headset_type); if(0 != pdata->gpio_switch) gpio_direction_output(pdata->gpio_switch, 0); break; case HEADSET_APPLE: PRINT_INFO("headset_type = %d (HEADSET_APPLE)\n", headset_type); PRINT_INFO("we have not yet implemented this in the code\n"); break; default: PRINT_INFO("headset_type = %d (HEADSET_UNKNOWN)\n", headset_type); break; } detect_err_count = 0; if(headset_type == HEADSET_NO_MIC) ht->headphone = 1; else ht->headphone = 0; if (ht->headphone) { headset_button_irq_threshold(0); headset_irq_button_enable(0, ht->irq_button); ht->type = BIT_HEADSET_NO_MIC; //hp_notifier_call_chain(ht->type); switch_set_state(&ht->sdev, ht->type); PRINT_INFO("headphone plug in (headset_detect_work_func)\n"); } else { headset_button_irq_threshold(1); if((HEADSET_4POLE_NOT_NORMAL == headset_type) && (0 == pdata->gpio_switch)) { headset_irq_button_enable(0, ht->irq_button); PRINT_INFO("HEADSET_4POLE_NOT_NORMAL is not supported by your hardware! so disable the button irq!\n"); } else { if (1 == ht->platform_data->irq_trigger_level_button) headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_HIGH); else headset_irq_set_irq_type(ht->irq_button, IRQF_TRIGGER_LOW); headset_irq_button_enable(1, ht->irq_button); } ht->type = BIT_HEADSET_MIC; //hp_notifier_call_chain(ht->type); switch_set_state(&ht->sdev, ht->type); PRINT_INFO("headset plug in (headset_detect_work_func)\n"); #ifdef ADPGAR_BYP_SELECT queue_delayed_work(adpgar_byp_select_work_queue, &adpgar_byp_select_work, msecs_to_jiffies(500)); #endif } plug_state_last = 1; #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 headset_irq_detect_enable(0, ht->irq_detect); headset_irq_detect_mic_enable(1, ht->irq_detect_mic); #else if(1 == pdata->irq_trigger_level_detect) headset_irq_set_irq_type(ht->irq_detect, IRQF_TRIGGER_LOW); else headset_irq_set_irq_type(ht->irq_detect, IRQF_TRIGGER_HIGH); headset_irq_detect_enable(1, ht->irq_detect); #endif } else if(0 == plug_state_current && 1 == plug_state_last) { headset_irq_button_enable(0, ht->irq_button); button_release_verify(); if (ht->headphone) { PRINT_INFO("headphone plug out (headset_detect_work_func)\n"); } else { PRINT_INFO("headset plug out (headset_detect_work_func)\n"); } ht->type = BIT_HEADSET_OUT; //hp_notifier_call_chain(ht->type); switch_set_state(&ht->sdev, ht->type); plug_state_last = 0; #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 headset_irq_detect_mic_enable(0, ht->irq_detect_mic); #else if(1 == pdata->irq_trigger_level_detect) headset_irq_set_irq_type(ht->irq_detect, IRQF_TRIGGER_HIGH); else headset_irq_set_irq_type(ht->irq_detect, IRQF_TRIGGER_LOW); #endif headset_irq_detect_enable(1, ht->irq_detect); } else { PRINT_INFO("irq_detect must be enabled anyway!!!\n"); goto out; } out: if(0 == plug_state_last) { #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 headset_irq_detect_mic_enable(0, ht->irq_detect_mic); if (detect_err_count < 500) { headset_irq_detect_enable(1, ht->irq_detect); } #endif headmicbias_power_on(&this_pdev->dev, 0); //headset_detect_clk_en(); //if (sprd_hts_power.head_mic) { //regulator_set_mode(sprd_hts_power.head_mic, REGULATOR_MODE_NORMAL); //} } #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 if (1 == plug_state_last) { headset_irq_detect_mic_enable(1, ht->irq_detect_mic); headset_irq_detect_enable(0, ht->irq_detect); } #else headset_irq_detect_enable(1, ht->irq_detect); #endif //wake_unlock(&headset_detect_wakelock); up(&headset_sem); return; } #ifdef ADPGAR_BYP_SELECT static void adpgar_byp_select_func(struct work_struct *work) { if ((0x2723 == (sci_get_ana_chip_id() >> 16)) && (SC2723ES == sci_get_ana_chip_ver() || SC2723TS == sci_get_ana_chip_ver())) { return; } headset_reg_set_val(HEADMIC_DETECT_REG(ANA_CDC1), AUDIO_ADPGAR_BYP_HEADMIC_2_ADCR, AUDIO_ADPGAR_BYP_MASK, AUDIO_ADPGAR_BYP_SHIFT); PRINT_INFO("ANA_CDC1 = 0x%08X\n", sci_adi_read(HEADMIC_DETECT_REG(ANA_CDC1))); msleep(100); headset_reg_set_val(HEADMIC_DETECT_REG(ANA_CDC1), AUDIO_ADPGAR_BYP_NORMAL, AUDIO_ADPGAR_BYP_MASK, AUDIO_ADPGAR_BYP_SHIFT); PRINT_INFO("ANA_CDC1 = 0x%08X\n", sci_adi_read(HEADMIC_DETECT_REG(ANA_CDC1))); PRINT_INFO("adpgar_byp_select_func\n"); } #endif static void reg_dump_func(struct work_struct *work) { int adc_mic = 0; int gpio_detect = 0; int gpio_button = 0; int gpio_detect_mic = 0; int ana_sts0 = 0; int ana_pmu0 = 0; int ana_cfg1 = 0; int ana_hdt0 = 0; int hid_cfg0 = 0; int hid_cfg2 = 0; int hid_cfg3 = 0; int hid_cfg4 = 0; int arm_module_en = 0; int arm_clk_en = 0; adc_mic = wrap_sci_adc_get_value(ADC_CHANNEL_HEADMIC, 1); gpio_detect = gpio_get_value(headset.platform_data->gpio_detect); gpio_button = gpio_get_value(headset.platform_data->gpio_button); #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 gpio_detect_mic = gpio_get_value(headset.platform_data->gpio_detect_mic); #endif sci_adi_write(ANA_REG_GLB_ARM_MODULE_EN, BIT_ANA_AUD_EN, BIT_ANA_AUD_EN);//arm base address:0x40038800 for register accessable ana_pmu0 = sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_PMU0);//arm base address:0x40038600 ana_hdt0 = sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_HDT0);//arm base address:0x40038600 ana_sts0 = sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_STS0);//arm base address:0x40038600 sci_adi_write(ANA_REG_GLB_ARM_MODULE_EN, BIT_ANA_HDT_EN, BIT_ANA_HDT_EN);//arm base address:0x40038800 for register accessable sci_adi_write(ANA_REG_GLB_ARM_CLK_EN, BIT_CLK_AUD_HID_EN, BIT_CLK_AUD_HID_EN);//arm base address:0x40038800 for register accessable hid_cfg2 = sci_adi_read(ANA_HDT_INT_BASE+HID_CFG2);//arm base address:0x40038700 hid_cfg3 = sci_adi_read(ANA_HDT_INT_BASE+HID_CFG3);//arm base address:0x40038700 hid_cfg4 = sci_adi_read(ANA_HDT_INT_BASE+HID_CFG4);//arm base address:0x40038700 hid_cfg0 = sci_adi_read(ANA_HDT_INT_BASE+HID_CFG0);//arm base address:0x40038700 arm_module_en = sci_adi_read(ANA_REG_GLB_ARM_MODULE_EN); arm_clk_en = sci_adi_read(ANA_REG_GLB_ARM_CLK_EN); PRINT_INFO("GPIO_%03d(det)=%d GPIO_%03d(but)=%d GPIO_%03d(det_mic)=%d adc_mic=%d\n", headset.platform_data->gpio_detect, gpio_detect, headset.platform_data->gpio_button, gpio_button, headset.platform_data->gpio_detect_mic, gpio_detect_mic, adc_mic); PRINT_INFO("arm_module_en|arm_clk_en|ana_pmu0 |ana_cfg1 |ana_hdt0 |ana_sts0 |hid_cfg2 |hid_cfg3 |hid_cfg4 |hid_cfg0\n"); PRINT_INFO("0x%08X |0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X\n", arm_module_en, arm_clk_en, ana_pmu0, ana_cfg1, ana_hdt0, ana_sts0, hid_cfg2, hid_cfg3, hid_cfg4, hid_cfg0); #if 0 int i = 0; int hbd[20] = {0}; for(i=0; i<20; i++) hbd[i] = sci_adi_read(ANA_HDT_INT_BASE + (i*4)); PRINT_INFO(" hbd_cfg0 | hbd_cfg1 | hbd_cfg2 | hbd_cfg3 | hbd_cfg4 | hbd_cfg5 | hbd_cfg6 | hbd_cfg7 | hbd_cfg8 | hbd_cfg9\n"); PRINT_INFO("0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X\n", hbd[0], hbd[1], hbd[2], hbd[3], hbd[4], hbd[5], hbd[6], hbd[7], hbd[8], hbd[9]); PRINT_INFO("hbd_cfg10 |hbd_cfg11 |hbd_cfg12 |hbd_cfg13 |hbd_cfg14 |hbd_cfg15 |hbd_cfg16 | hbd_sts0 | hbd_sts1 | hbd_sts2\n"); PRINT_INFO("0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X|0x%08X\n", hbd[10], hbd[11], hbd[12], hbd[13], hbd[14], hbd[15], hbd[16], hbd[17], hbd[18], hbd[19]); #endif if (debug_level >= 2) queue_delayed_work(reg_dump_work_queue, ®_dump_work, msecs_to_jiffies(500)); return; } /** * some phone boards, when no headset plugin, the button headset_button_valid() * will always return 0, so we need to disable headset_button irq in here * otherwise button irq will always happen. */ volatile int headset_button_hardware_bug_fix_stage = 1; static void headset_button_hardware_bug_fix(struct sprd_headset *ht) { if (headset_button_hardware_bug_fix_stage) { headset_irq_button_enable(0, ht->irq_button); // disable button irq before headset detected pr_err("This phone board headset button circuit has bug, please fix the hardware\n"); } } static irqreturn_t headset_button_irq_handler(int irq, void *dev) { struct sprd_headset *ht = dev; int button_state_current = 0; int gpio_button_value_current = 0; if(0 == headset_button_valid(gpio_get_value(ht->platform_data->gpio_detect))) { PRINT_INFO("headset_button_irq_handler: button is invalid!!! IRQ_%d(GPIO_%d) = %d, ANA_STS0 = 0x%08X\n", ht->irq_button, ht->platform_data->gpio_button, gpio_button_value_last, sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_STS0)); headset_button_hardware_bug_fix(ht); if(0 == plug_state_last) headset_irq_button_enable(0, ht->irq_button); return IRQ_HANDLED; } gpio_button_value_current = gpio_get_value(ht->platform_data->gpio_button); button_state_current = headset_gpio_2_button_state(gpio_button_value_current); #ifdef ADPGAR_BYP_SELECT if(0 == button_state_current) { queue_delayed_work(adpgar_byp_select_work_queue, &adpgar_byp_select_work, msecs_to_jiffies(0)); } #endif if(button_state_current == button_state_last) { PRINT_INFO("button state check failed!!! maybe the release is too quick. button_state_current=%d, button_state_last=%d\n", button_state_current, button_state_last); return IRQ_HANDLED; } headset_irq_button_enable(0, ht->irq_button); wake_lock_timeout(&headset_button_wakelock, msecs_to_jiffies(2000)); gpio_button_value_last = gpio_button_value_current; PRINT_DBG("headset_button_irq_handler: IRQ_%d(GPIO_%d) = %d, ANA_STS0 = 0x%08X\n", ht->irq_button, ht->platform_data->gpio_button, gpio_button_value_last, sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_STS0)); queue_work(ht->button_work_queue, &ht->work_button); return IRQ_HANDLED; } static irqreturn_t headset_detect_irq_handler(int irq, void *dev) { struct sprd_headset *ht = dev; PRINT_INFO("headset_detect_irq_handler in \n"); headset_irq_button_enable(0, ht->irq_button); headset_irq_detect_enable(0, ht->irq_detect); #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 headset_irq_detect_mic_enable(0, ht->irq_detect_mic); #endif wake_lock_timeout(&headset_detect_wakelock, msecs_to_jiffies(2000)); gpio_detect_value_last = gpio_get_value(ht->platform_data->gpio_detect); PRINT_DBG("headset_detect_irq_handler: IRQ_%d(GPIO_%d) = %d, ANA_STS0 = 0x%08X\n", ht->irq_detect, ht->platform_data->gpio_detect, gpio_detect_value_last, sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_STS0)); queue_delayed_work(ht->detect_work_queue, &ht->work_detect, msecs_to_jiffies(0)); PRINT_INFO("headset_detect_irq_handler out \n"); return IRQ_HANDLED; } static irqreturn_t headset_detect_mic_irq_handler(int irq, void *dev) { struct sprd_headset *ht = dev; PRINT_INFO("headset_detect_mic_irq_handler in \n"); if (plug_state_last != 1) { headset_irq_detect_mic_enable(0, ht->irq_detect_mic); PRINT_INFO("headset_detect_mic_irq_handler out0 \n"); return IRQ_HANDLED; } headset_irq_detect_mic_enable(0, ht->irq_detect_mic); headset_irq_detect_enable(0, ht->irq_detect); wake_lock_timeout(&headset_detect_wakelock, msecs_to_jiffies(2000)); queue_delayed_work(ht->detect_work_queue, &ht->work_detect, msecs_to_jiffies(0)); PRINT_INFO("headset_detect_mic_irq_handler out1 \n"); return IRQ_HANDLED; } //================= create sys fs for debug =================== //============= /sys/kernel/headset/debug_level =============== static ssize_t headset_debug_level_show(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { PRINT_INFO("debug_level = %d\n", debug_level); return sprintf(buff, "%d\n", debug_level); } static ssize_t headset_debug_level_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t len) { unsigned long level = simple_strtoul(buff, NULL, 10); debug_level = level; PRINT_INFO("debug_level = %d\n", debug_level); if(debug_level >= 2) queue_delayed_work(reg_dump_work_queue, ®_dump_work, msecs_to_jiffies(500)); return len; } static struct kobject *headset_debug_kobj = NULL; static struct kobj_attribute headset_debug_attr = __ATTR(debug_level, 0644, headset_debug_level_show, headset_debug_level_store); static int headset_debug_sysfs_init(void) { int ret = -1; headset_debug_kobj = kobject_create_and_add("headset", kernel_kobj); if (headset_debug_kobj == NULL) { ret = -ENOMEM; PRINT_ERR("register sysfs failed. ret = %d\n", ret); return ret; } ret = sysfs_create_file(headset_debug_kobj, &headset_debug_attr.attr); if (ret) { PRINT_ERR("create sysfs failed. ret = %d\n", ret); return ret; } PRINT_INFO("headset_debug_sysfs_init success\n"); return ret; } //================= create sys fs for debug =================== #ifdef CONFIG_OF static struct sprd_headset_platform_data *headset_detect_parse_dt(struct device *dev) { struct sprd_headset_platform_data *pdata; struct device_node *np = dev->of_node,*buttons_np = NULL; int ret; struct headset_buttons *buttons_data; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(dev, "could not allocate memory for platform data\n"); return NULL; } ret = of_property_read_u32(np, "gpio_switch", &pdata->gpio_switch); if(ret) { dev_err(dev, "fail to get gpio_switch\n"); goto fail; } ret = of_property_read_u32(np, "gpio_detect", &pdata->gpio_detect); if(ret) { dev_err(dev, "fail to get gpio_detect\n"); goto fail; } #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 ret = of_property_read_u32(np, "gpio_detect_mic", &pdata->gpio_detect_mic); if (ret) { dev_err(dev, "fail to get gpio_detect_mic\n"); goto fail; } #endif ret = of_property_read_u32(np, "gpio_button", &pdata->gpio_button); if(ret) { dev_err(dev, "fail to get gpio_button\n"); goto fail; } ret = of_property_read_u32(np, "irq_trigger_level_detect", &pdata->irq_trigger_level_detect); if(ret) { dev_err(dev, "fail to get irq_trigger_level_detect\n"); goto fail; } #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 ret = of_property_read_u32(np, "irq_trigger_level_detect_mic", &pdata->irq_trigger_level_detect_mic); if (ret) { dev_err(dev, "fail to get irq_trigger_level_detect_mic\n"); goto fail; } #endif ret = of_property_read_u32(np, "irq_trigger_level_button", &pdata->irq_trigger_level_button); if(ret) { dev_err(dev, "fail to get irq_trigger_level_button\n"); goto fail; } ret = of_property_read_u32(np, "adc_threshold_3pole_detect", &pdata->adc_threshold_3pole_detect); if(ret) { dev_err(dev, "fail to get adc_threshold_3pole_detect\n"); goto fail; } ret = of_property_read_u32(np, "adc_threshold_4pole_detect", &pdata->adc_threshold_4pole_detect); if(ret) { dev_err(dev, "fail to get adc_threshold_4pole_detect\n"); goto fail; } ret = of_property_read_u32(np, "irq_threshold_buttont", &pdata->irq_threshold_buttont); if(ret) { dev_err(dev, "fail to get irq_threshold_buttont\n"); goto fail; } ret = of_property_read_u32(np, "voltage_headmicbias", &pdata->voltage_headmicbias); if(ret) { dev_err(dev, "fail to get voltage_headmicbias\n"); goto fail; } ret = of_property_read_u32(np, "nbuttons", &pdata->nbuttons); if(ret) { dev_err(dev, "fail to get nbuttons\n"); goto fail; } buttons_data = kzalloc(pdata->nbuttons*sizeof(*buttons_data),GFP_KERNEL); if (!buttons_data) { dev_err(dev, "could not allocate memory for headset_buttons\n"); goto fail; } pdata->headset_buttons = buttons_data; for_each_child_of_node(np,buttons_np) { ret = of_property_read_u32(buttons_np, "adc_min", &buttons_data->adc_min); if (ret) { dev_err(dev, "fail to get adc_min\n"); goto fail_buttons_data; } ret = of_property_read_u32(buttons_np, "adc_max", &buttons_data->adc_max); if (ret) { dev_err(dev, "fail to get adc_max\n"); goto fail_buttons_data; } ret = of_property_read_u32(buttons_np, "code", &buttons_data->code); if (ret) { dev_err(dev, "fail to get code\n"); goto fail_buttons_data; } ret = of_property_read_u32(buttons_np, "type", &buttons_data->type); if (ret) { dev_err(dev, "fail to get type\n"); goto fail_buttons_data; } PRINT_INFO("device tree data: adc_min = %d adc_max = %d code = %d type = %d \n", buttons_data->adc_min, buttons_data->adc_max, buttons_data->code, buttons_data->type); buttons_data++; }; return pdata; fail_buttons_data: kfree(buttons_data); pdata->headset_buttons = NULL; fail: kfree(pdata); return NULL; } #endif static void adc_cal_from_efuse(void); static int headset_detect_probe(struct platform_device *pdev) { struct sprd_headset_platform_data *pdata = pdev->dev.platform_data; struct sprd_headset *ht = &headset; unsigned long irqflags = 0; struct input_dev *input_dev = NULL; int i = 0; int ret = -1; int ana_sts0 = 0; int adie_chip_id_low = 0; int adie_chip_id_high = 0; unsigned int adie_chip_id = 0; unsigned int ddie_chip_id = 0; #ifdef CONFIG_OF struct device_node *np = NULL; np = pdev->dev.of_node; if (pdev->dev.of_node && !pdata) { pdata = headset_detect_parse_dt(&pdev->dev); if(pdata) pdev->dev.platform_data = pdata; } if (!pdata) { PRINT_ERR("headset_detect_probe get platform_data NULL\n"); ret = -EINVAL; goto fail_to_get_platform_data; } #endif this_pdev = pdev; sci_adi_write(ANA_REG_GLB_ARM_MODULE_EN, BIT_ANA_AUD_EN, BIT_ANA_AUD_EN);//arm base address:0x40038800 for register accessable ana_sts0 = sci_adi_read(ANA_AUDCFGA_INT_BASE+ANA_STS0);//arm base address:0x40038600 ddie_chip_id = sci_get_chip_id(); PRINT_INFO("ddie_chip_id=0x%08X\n", ddie_chip_id); adie_chip_id = sci_get_ana_chip_id(); PRINT_INFO("adie_chip_id=0x%08X\n", adie_chip_id); adie_chip_id_high = (adie_chip_id >> 16) & 0xFFFF; adie_chip_id_low = adie_chip_id & 0xFFFF; switch (adie_chip_id_high) { case 0x2723: {//chip is 2723 adie_type = 2723; PRINT_INFO("adie chip is 2723, type = %d\n", adie_type); break; //break from 2723 } default: { adie_type = -1; //unknow PRINT_ERR("unknow adie chip !!!\n"); break; } } ht->platform_data = pdata; headset_detect_init(); ret = sprd_headset_power_init(&pdev->dev); if (ret) goto fail_to_sprd_headset_power_init; PRINT_INFO("====================== SPRD HEADSET DETECT v2 ======================\n"); PRINT_INFO(" write 0~3 to \"/sys/kernel/headset/debug_level\" for headset debug\n"); PRINT_INFO("====================================================================\n"); PRINT_INFO("use GPIO_%d for insert detecting\n", pdata->gpio_detect); if(0 != pdata->gpio_switch) { ret = gpio_request(pdata->gpio_switch, "headset_switch"); if (ret < 0) { PRINT_ERR("failed to request GPIO_%d(headset_switch)\n", pdata->gpio_switch); goto failed_to_request_gpio_switch; } } else PRINT_INFO("automatic type switch is unsupported\n"); ret = gpio_request(pdata->gpio_detect, "headset_detect"); if (ret < 0) { PRINT_ERR("failed to request GPIO_%d(headset_detect)\n", pdata->gpio_detect); goto failed_to_request_gpio_detect; } #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 ret = gpio_request(pdata->gpio_detect_mic, "headset_detect_mic"); if (ret < 0) { PRINT_ERR("failed to request GPIO_%d(headset_detect_mic)\n", pdata->gpio_detect_mic); goto failed_to_request_gpio_detect_mic; } #endif ret = gpio_request(pdata->gpio_button, "headset_button"); if (ret < 0) { PRINT_ERR("failed to request GPIO_%d(headset_button)\n", pdata->gpio_button); goto failed_to_request_gpio_button; } if(0 != pdata->gpio_switch) gpio_direction_output(pdata->gpio_switch, 0); gpio_direction_input(pdata->gpio_detect); #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 gpio_direction_input(pdata->gpio_detect_mic); #endif gpio_direction_input(pdata->gpio_button); ht->irq_detect = gpio_to_irq(pdata->gpio_detect); ht->irq_button = gpio_to_irq(pdata->gpio_button); #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 ht->irq_detect_mic = gpio_to_irq(pdata->gpio_detect_mic); #endif ret = switch_dev_register(&ht->sdev); if (ret < 0) { PRINT_ERR("switch_dev_register failed!\n"); goto failed_to_register_switch_dev; } input_dev = input_allocate_device(); if ( !input_dev) { PRINT_ERR("input_allocate_device for headset_button failed!\n"); ret = -ENOMEM; goto failed_to_allocate_input_device; } input_dev->name = "headset-keyboard"; input_dev->id.bustype = BUS_HOST; ht->input_dev = input_dev; for (i = 0; i < pdata->nbuttons; i++) { struct headset_buttons *buttons = &pdata->headset_buttons[i]; unsigned int type = buttons->type ?: EV_KEY; input_set_capability(input_dev, type, buttons->code); } ret = input_register_device(input_dev); if (ret) { PRINT_ERR("input_register_device for headset_button failed!\n"); goto failed_to_register_input_device; } sema_init(&headset_sem, 1); INIT_WORK(&ht->work_button, headset_button_work_func); ht->button_work_queue = create_singlethread_workqueue("headset_button"); if(ht->button_work_queue == NULL) { PRINT_ERR("create_singlethread_workqueue for headset_button failed!\n"); goto failed_to_create_singlethread_workqueue_for_headset_button; } INIT_DELAYED_WORK(&ht->work_detect, headset_detect_work_func); ht->detect_work_queue = create_singlethread_workqueue("headset_detect"); if(ht->detect_work_queue == NULL) { PRINT_ERR("create_singlethread_workqueue for headset_detect failed!\n"); goto failed_to_create_singlethread_workqueue_for_headset_detect; } INIT_DELAYED_WORK(®_dump_work, reg_dump_func); reg_dump_work_queue = create_singlethread_workqueue("headset_reg_dump"); if(reg_dump_work_queue == NULL) { PRINT_ERR("create_singlethread_workqueue for headset_reg_dump failed!\n"); goto failed_to_create_singlethread_workqueue_for_headset_reg_dump; } if (debug_level >= 2) queue_delayed_work(reg_dump_work_queue, ®_dump_work, msecs_to_jiffies(500)); #ifdef ADPGAR_BYP_SELECT //work queue for Bug#298417 INIT_DELAYED_WORK(&adpgar_byp_select_work, adpgar_byp_select_func); adpgar_byp_select_work_queue = create_singlethread_workqueue("adpgar_byp_select"); if(adpgar_byp_select_work_queue == NULL) { PRINT_ERR("create_singlethread_workqueue for adpgar_byp_select failed!\n"); goto failed_to_create_singlethread_workqueue_for_adpgar_byp_select; } PRINT_INFO("ADPGAR_BYP_SELECT is enabled!\n"); #endif wake_lock_init(&headset_detect_wakelock, WAKE_LOCK_SUSPEND, "headset_detect_wakelock"); wake_lock_init(&headset_button_wakelock, WAKE_LOCK_SUSPEND, "headset_button_wakelock"); //set EIC3 de-bounce time for button irq headset_reg_set_val((ANA_EIC_BASE+EIC3_DBNC_CTRL), DBNC_CNT3_VALUE, DBNC_CNT3_MASK, DBNC_CNT3_SHIFT); //set EIC5 de-bounce time for inser irq headset_reg_set_val((ANA_EIC_BASE+EIC8_DBNC_CTRL), DBNC_CNT8_VALUE, DBNC_CNT8_MASK, DBNC_CNT8_SHIFT); #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 /* set EIC5 de-bounce time for ins_mic irq */ headset_reg_set_val((ANA_EIC_BASE+EIC5_DBNC_CTRL), DBNC_CNT5_VALUE, DBNC_CNT5_MASK, DBNC_CNT5_SHIFT); #endif irqflags = pdata->irq_trigger_level_button ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; ret = request_irq(ht->irq_button, headset_button_irq_handler, irqflags | IRQF_NO_SUSPEND, "headset_button", ht); if (ret) { PRINT_ERR("failed to request IRQ_%d(GPIO_%d)\n", ht->irq_button, pdata->gpio_button); goto failed_to_request_irq_headset_button; } headset_irq_button_enable(0, ht->irq_button);//disable button irq before headset detected headset_button_hardware_bug_fix_stage = 0; irqflags = pdata->irq_trigger_level_detect ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; ret = request_irq(ht->irq_detect, headset_detect_irq_handler, irqflags | IRQF_NO_SUSPEND, "headset_detect", ht); if (ret < 0) { PRINT_ERR("failed to request IRQ_%d(GPIO_%d)\n", ht->irq_detect, pdata->gpio_detect); goto failed_to_request_irq_headset_detect; } #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 irqflags = pdata->irq_trigger_level_detect_mic ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; ret = request_irq(ht->irq_detect_mic, headset_detect_mic_irq_handler, irqflags | IRQF_NO_SUSPEND, "headset_detect_mic", ht); if (ret < 0) { PRINT_ERR("failed to request IRQ_%d(GPIO_%d)\n", ht->irq_detect_mic, pdata->gpio_detect_mic); goto failed_to_request_irq_mic_headset_detect; } #endif ret = headset_debug_sysfs_init(); adc_cal_from_efuse(); PRINT_INFO("headset_detect_probe success\n"); return ret; #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 failed_to_request_irq_mic_headset_detect: free_irq(ht->irq_detect_mic, ht); #endif failed_to_request_irq_headset_detect: free_irq(ht->irq_button, ht); failed_to_request_irq_headset_button: #ifdef ADPGAR_BYP_SELECT cancel_delayed_work_sync(&adpgar_byp_select_work); destroy_workqueue(adpgar_byp_select_work_queue); failed_to_create_singlethread_workqueue_for_adpgar_byp_select: #endif cancel_delayed_work_sync(®_dump_work); destroy_workqueue(reg_dump_work_queue); failed_to_create_singlethread_workqueue_for_headset_reg_dump: destroy_workqueue(ht->detect_work_queue); failed_to_create_singlethread_workqueue_for_headset_detect: destroy_workqueue(ht->button_work_queue); failed_to_create_singlethread_workqueue_for_headset_button: input_unregister_device(input_dev); failed_to_register_input_device: input_free_device(input_dev); failed_to_allocate_input_device: switch_dev_unregister(&ht->sdev); failed_to_register_switch_dev: gpio_free(pdata->gpio_button); failed_to_request_gpio_button: gpio_free(pdata->gpio_detect); #ifdef CONFIG_SND_SOC_SPRD_USE_EAR_JACK_TYPE13 failed_to_request_gpio_detect_mic: gpio_free(pdata->gpio_detect_mic); #endif failed_to_request_gpio_detect: if(0 != pdata->gpio_switch) gpio_free(pdata->gpio_switch); failed_to_request_gpio_switch: headmicbias_power_on(&pdev->dev, 0); fail_to_sprd_headset_power_init: fail_to_get_platform_data: PRINT_ERR("headset_detect_probe failed\n"); return ret; } #ifdef CONFIG_PM static int headset_suspend(struct platform_device *dev, pm_message_t state) { PRINT_INFO("suspend (det_irq = %d, but_irq = %d, plug_state_last = %d)\n", headset.irq_detect, headset.irq_button, plug_state_last); return 0; } static int headset_resume(struct platform_device *dev) { PRINT_INFO("resume (det_irq = %d, but_irq = %d, plug_state_last = %d)\n", headset.irq_detect, headset.irq_button, plug_state_last); return 0; } #else #define headset_suspend NULL #define headset_resume NULL #endif static int adc_get_ideal(u32 adc_mic) { u64 numerator = 0; u32 denominator = 0; u32 adc_ideal = 0; if (adc_cal_headset.cal_type == SPRD_HEADSET_AUXADC_CAL_DO){ PRINT_INFO("wangzuo adc_get_ideal in\n"); u32 a = adc_cal_headset.A; u32 b = adc_cal_headset.B; u32 e = adc_cal_headset.E; if (9*adc_mic + b < 10*a){ return adc_mic; } denominator = e*(b-a); numerator = 917280*(9*(u64)adc_mic+(u64)b-10*(u64)a); PRINT_INFO("denominator=%u, numerator=%llu\n", denominator, numerator); do_div(numerator,denominator); adc_ideal = (u32)numerator; PRINT_INFO("adc_mic=%d, adc_ideal=%d\n", adc_mic, adc_ideal); return adc_ideal; } else { return adc_mic; } } extern u32 __adie_efuse_read_bits(int bit_index, int length); #define DELTA1_BLOCK9 9 #define DELTA2_BLOCK10 10 #define DELTA3_BLOCK11 11 #define BITCOUNT 8 #define BLK_WIDTH 8 static void adc_cal_from_efuse(void) { u32 delta[3] = {0}; u32 block0_bit7 = 128; u8 test[3] = {0}; PRINT_INFO("to get calibration data from efuse ...\n"); if (adc_cal_headset.cal_type == SPRD_HEADSET_AUXADC_CAL_NO) { delta[0] = __adie_efuse_read_bits(DELTA1_BLOCK9*BLK_WIDTH,BITCOUNT); delta[1] = __adie_efuse_read_bits(DELTA2_BLOCK10*BLK_WIDTH,BITCOUNT); delta[2] = __adie_efuse_read_bits(DELTA3_BLOCK11*BLK_WIDTH,BITCOUNT); test[0] = delta[0]&0xff; test[1] = delta[1]&0xff; test[2] = delta[2]&0xff; PRINT_INFO("test[0] 0x%x %d, test[1] 0x%x %d, test[2] 0x%x %d \n",test[0],test[0],test[1],test[1],test[2],test[2]); block0_bit7 = __adie_efuse_read_bits(0,BITCOUNT); PRINT_INFO("block_7 0x%08x \n",block0_bit7); if(block0_bit7&(1<<7)){ PRINT_INFO("block 0 bit 7 set 1 no efuse data\n"); return; } else { adc_cal_headset.cal_type = SPRD_HEADSET_AUXADC_CAL_DO; PRINT_INFO("block 0 bit 7 set 0 have efuse data\n"); } PRINT_INFO("test[0] %d, test[1] %d, test[2] %d \n",test[0],test[1],test[2]); adc_cal_headset.A = (test[0]*4)-184; adc_cal_headset.B = (test[1]*4)+2764; adc_cal_headset.E = (test[2]*2)+2500; PRINT_INFO("adc_cal_headset.A %d, adc_cal_headset.B %d, adc_cal_headset.E %d \n",adc_cal_headset.A,adc_cal_headset.B,adc_cal_headset.E); } else { PRINT_INFO("efuse A,B,E has been calculated! \n"); } } static const struct of_device_id headset_detect_of_match[] = { {.compatible = "sprd,headset_sprd_sc2723",}, { } }; static struct platform_driver headset_detect_driver = { .driver = { .name = "headset_sprd_sc2723", .owner = THIS_MODULE, .of_match_table = headset_detect_of_match, }, .probe = headset_detect_probe, //.suspend = headset_suspend, //.resume = headset_resume, }; static int __init headset_init(void) { int ret; ret = platform_driver_register(&headset_detect_driver); return ret; } static void __exit headset_exit(void) { sprd_headset_power_deinit(); platform_driver_unregister(&headset_detect_driver); } late_initcall(headset_init); module_exit(headset_exit); MODULE_DESCRIPTION("headset & button detect driver v2"); MODULE_AUTHOR("Yaochuan Li "); MODULE_LICENSE("GPL");