Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
0003 
0004 #include <linux/module.h>
0005 #include <linux/init.h>
0006 #include <linux/slab.h>
0007 #include <linux/device.h>
0008 #include <linux/pm_runtime.h>
0009 #include <linux/printk.h>
0010 #include <linux/delay.h>
0011 #include <linux/kernel.h>
0012 #include <sound/soc.h>
0013 #include <sound/jack.h>
0014 #include "wcd-mbhc-v2.h"
0015 
0016 #define HS_DETECT_PLUG_TIME_MS      (3 * 1000)
0017 #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
0018 #define GND_MIC_SWAP_THRESHOLD      4
0019 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS  100
0020 #define HPHL_CROSS_CONN_THRESHOLD   100
0021 #define HS_VREF_MIN_VAL         1400
0022 #define FAKE_REM_RETRY_ATTEMPTS     3
0023 #define WCD_MBHC_ADC_HS_THRESHOLD_MV    1700
0024 #define WCD_MBHC_ADC_HPH_THRESHOLD_MV   75
0025 #define WCD_MBHC_ADC_MICBIAS_MV     1800
0026 #define WCD_MBHC_FAKE_INS_RETRY     4
0027 
0028 #define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \
0029                SND_JACK_MECHANICAL)
0030 
0031 #define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
0032                   SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
0033                   SND_JACK_BTN_4 | SND_JACK_BTN_5)
0034 
0035 enum wcd_mbhc_adc_mux_ctl {
0036     MUX_CTL_AUTO = 0,
0037     MUX_CTL_IN2P,
0038     MUX_CTL_IN3P,
0039     MUX_CTL_IN4P,
0040     MUX_CTL_HPH_L,
0041     MUX_CTL_HPH_R,
0042     MUX_CTL_NONE,
0043 };
0044 
0045 struct wcd_mbhc {
0046     struct device *dev;
0047     struct snd_soc_component *component;
0048     struct snd_soc_jack *jack;
0049     struct wcd_mbhc_config *cfg;
0050     const struct wcd_mbhc_cb *mbhc_cb;
0051     const struct wcd_mbhc_intr *intr_ids;
0052     struct wcd_mbhc_field *fields;
0053     /* Delayed work to report long button press */
0054     struct delayed_work mbhc_btn_dwork;
0055     /* Work to correct accessory type */
0056     struct work_struct correct_plug_swch;
0057     struct mutex lock;
0058     int buttons_pressed;
0059     u32 hph_status; /* track headhpone status */
0060     u8 current_plug;
0061     bool is_btn_press;
0062     bool in_swch_irq_handler;
0063     bool hs_detect_work_stop;
0064     bool is_hs_recording;
0065     bool extn_cable_hph_rem;
0066     bool force_linein;
0067     bool impedance_detect;
0068     unsigned long event_state;
0069     unsigned long jiffies_atreport;
0070     /* impedance of hphl and hphr */
0071     uint32_t zl, zr;
0072     /* Holds type of Headset - Mono/Stereo */
0073     enum wcd_mbhc_hph_type hph_type;
0074     /* Holds mbhc detection method - ADC/Legacy */
0075     int mbhc_detection_logic;
0076 };
0077 
0078 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc,
0079                        int field, int val)
0080 {
0081     if (!mbhc->fields[field].reg)
0082         return 0;
0083 
0084     return snd_soc_component_write_field(mbhc->component,
0085                          mbhc->fields[field].reg,
0086                          mbhc->fields[field].mask, val);
0087 }
0088 
0089 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field)
0090 {
0091     if (!mbhc->fields[field].reg)
0092         return 0;
0093 
0094     return snd_soc_component_read_field(mbhc->component,
0095                         mbhc->fields[field].reg,
0096                         mbhc->fields[field].mask);
0097 }
0098 
0099 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
0100 {
0101     u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
0102 
0103     wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val);
0104 }
0105 
0106 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
0107 {
0108     struct snd_soc_component *component = mbhc->component;
0109 
0110     mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low,
0111                    mbhc->cfg->btn_high,
0112                    mbhc->cfg->num_btn, micbias);
0113 }
0114 
0115 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc,
0116                       const enum wcd_mbhc_cs_mb_en_flag cs_mb_en)
0117 {
0118 
0119     /*
0120      * Some codecs handle micbias/pullup enablement in codec
0121      * drivers itself and micbias is not needed for regular
0122      * plug type detection. So if micbias_control callback function
0123      * is defined, just return.
0124      */
0125     if (mbhc->mbhc_cb->mbhc_micbias_control)
0126         return;
0127 
0128     switch (cs_mb_en) {
0129     case WCD_MBHC_EN_CS:
0130         wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
0131         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0132         /* Program Button threshold registers as per CS */
0133         wcd_program_btn_threshold(mbhc, false);
0134         break;
0135     case WCD_MBHC_EN_MB:
0136         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0137         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0138         /* Disable PULL_UP_EN & enable MICBIAS */
0139         wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2);
0140         /* Program Button threshold registers as per MICBIAS */
0141         wcd_program_btn_threshold(mbhc, true);
0142         break;
0143     case WCD_MBHC_EN_PULLUP:
0144         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0145         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0146         wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1);
0147         /* Program Button threshold registers as per MICBIAS */
0148         wcd_program_btn_threshold(mbhc, true);
0149         break;
0150     case WCD_MBHC_EN_NONE:
0151         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0152         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0153         wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
0154         break;
0155     default:
0156         dev_err(mbhc->dev, "%s: Invalid parameter", __func__);
0157         break;
0158     }
0159 }
0160 
0161 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event)
0162 {
0163 
0164     struct snd_soc_component *component;
0165     bool micbias2 = false;
0166 
0167     if (!mbhc)
0168         return 0;
0169 
0170     component = mbhc->component;
0171 
0172     if (mbhc->mbhc_cb->micbias_enable_status)
0173         micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2);
0174 
0175     switch (event) {
0176     /* MICBIAS usage change */
0177     case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
0178         mbhc->is_hs_recording = true;
0179         break;
0180     case WCD_EVENT_POST_MICBIAS_2_ON:
0181         /* Disable current source if micbias2 enabled */
0182         if (mbhc->mbhc_cb->mbhc_micbias_control) {
0183             if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
0184                 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0185         } else {
0186             mbhc->is_hs_recording = true;
0187             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0188         }
0189         break;
0190     case WCD_EVENT_PRE_MICBIAS_2_OFF:
0191         /*
0192          * Before MICBIAS_2 is turned off, if FSM is enabled,
0193          * make sure current source is enabled so as to detect
0194          * button press/release events
0195          */
0196         if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) {
0197             if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
0198                 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0199         }
0200         break;
0201     /* MICBIAS usage change */
0202     case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
0203         mbhc->is_hs_recording = false;
0204         break;
0205     case WCD_EVENT_POST_MICBIAS_2_OFF:
0206         if (!mbhc->mbhc_cb->mbhc_micbias_control)
0207             mbhc->is_hs_recording = false;
0208 
0209         /* Enable PULL UP if PA's are enabled */
0210         if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
0211             (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state)))
0212             /* enable pullup and cs, disable mb */
0213             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
0214         else
0215             /* enable current source and disable mb, pullup*/
0216             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
0217 
0218         break;
0219     case WCD_EVENT_POST_HPHL_PA_OFF:
0220         clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
0221 
0222         /* check if micbias is enabled */
0223         if (micbias2)
0224             /* Disable cs, pullup & enable micbias */
0225             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0226         else
0227             /* Disable micbias, pullup & enable cs */
0228             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
0229         break;
0230     case WCD_EVENT_POST_HPHR_PA_OFF:
0231         clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
0232         /* check if micbias is enabled */
0233         if (micbias2)
0234             /* Disable cs, pullup & enable micbias */
0235             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0236         else
0237             /* Disable micbias, pullup & enable cs */
0238             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
0239         break;
0240     case WCD_EVENT_PRE_HPHL_PA_ON:
0241         set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
0242         /* check if micbias is enabled */
0243         if (micbias2)
0244             /* Disable cs, pullup & enable micbias */
0245             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0246         else
0247             /* Disable micbias, enable pullup & cs */
0248             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
0249         break;
0250     case WCD_EVENT_PRE_HPHR_PA_ON:
0251         set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
0252         /* check if micbias is enabled */
0253         if (micbias2)
0254             /* Disable cs, pullup & enable micbias */
0255             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
0256         else
0257             /* Disable micbias, enable pullup & cs */
0258             wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
0259         break;
0260     default:
0261         break;
0262     }
0263     return 0;
0264 }
0265 EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify);
0266 
0267 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
0268 {
0269     return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
0270 }
0271 
0272 static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
0273 {
0274     struct snd_soc_component *component = mbhc->component;
0275 
0276     if (mbhc->mbhc_cb->mbhc_micbias_control)
0277         mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
0278 
0279     if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
0280         mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false);
0281 
0282     if (mbhc->mbhc_cb->set_micbias_value) {
0283         mbhc->mbhc_cb->set_micbias_value(component);
0284         wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
0285     }
0286 }
0287 
0288 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc,
0289                      enum snd_jack_types jack_type)
0290 {
0291     mbhc->hph_status &= ~jack_type;
0292     /*
0293      * cancel possibly scheduled btn work and
0294      * report release if we reported button press
0295      */
0296     if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) {
0297         snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
0298         mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
0299     }
0300 
0301     wcd_micbias_disable(mbhc);
0302     mbhc->hph_type = WCD_MBHC_HPH_NONE;
0303     mbhc->zl = mbhc->zr = 0;
0304     snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK);
0305     mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
0306     mbhc->force_linein = false;
0307 }
0308 
0309 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc)
0310 {
0311 
0312     if (!mbhc->impedance_detect)
0313         return;
0314 
0315     if (mbhc->cfg->linein_th != 0) {
0316         u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
0317         /* Set MUX_CTL to AUTO for Z-det */
0318 
0319         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0320         wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
0321         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0322         mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr);
0323         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
0324     }
0325 }
0326 
0327 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc,
0328                        enum snd_jack_types jack_type)
0329 {
0330     bool is_pa_on;
0331     /*
0332      * Report removal of current jack type.
0333      * Headphone to headset shouldn't report headphone
0334      * removal.
0335      */
0336     if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
0337         jack_type == SND_JACK_HEADPHONE)
0338         mbhc->hph_status &= ~SND_JACK_HEADSET;
0339 
0340     /* Report insertion */
0341     switch (jack_type) {
0342     case SND_JACK_HEADPHONE:
0343         mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
0344         break;
0345     case SND_JACK_HEADSET:
0346         mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
0347         mbhc->jiffies_atreport = jiffies;
0348         break;
0349     case SND_JACK_LINEOUT:
0350         mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
0351         break;
0352     default:
0353         break;
0354     }
0355 
0356 
0357     is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
0358 
0359     if (!is_pa_on) {
0360         wcd_mbhc_compute_impedance(mbhc);
0361         if ((mbhc->zl > mbhc->cfg->linein_th) &&
0362             (mbhc->zr > mbhc->cfg->linein_th) &&
0363             (jack_type == SND_JACK_HEADPHONE)) {
0364             jack_type = SND_JACK_LINEOUT;
0365             mbhc->force_linein = true;
0366             mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
0367             if (mbhc->hph_status) {
0368                 mbhc->hph_status &= ~(SND_JACK_HEADSET |
0369                               SND_JACK_LINEOUT);
0370                 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
0371                             WCD_MBHC_JACK_MASK);
0372             }
0373         }
0374     }
0375 
0376     /* Do not calculate impedance again for lineout
0377      * as during playback pa is on and impedance values
0378      * will not be correct resulting in lineout detected
0379      * as headphone.
0380      */
0381     if (is_pa_on && mbhc->force_linein) {
0382         jack_type = SND_JACK_LINEOUT;
0383         mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
0384         if (mbhc->hph_status) {
0385             mbhc->hph_status &= ~(SND_JACK_HEADSET |
0386                           SND_JACK_LINEOUT);
0387             snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
0388                         WCD_MBHC_JACK_MASK);
0389         }
0390     }
0391 
0392     mbhc->hph_status |= jack_type;
0393 
0394     if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control)
0395         mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false);
0396 
0397     snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL),
0398                 WCD_MBHC_JACK_MASK);
0399 }
0400 
0401 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
0402                  enum snd_jack_types jack_type)
0403 {
0404 
0405     WARN_ON(!mutex_is_locked(&mbhc->lock));
0406 
0407     if (!insertion) /* Report removal */
0408         wcd_mbhc_report_plug_removal(mbhc, jack_type);
0409     else
0410         wcd_mbhc_report_plug_insertion(mbhc, jack_type);
0411 
0412 }
0413 
0414 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
0415                       struct work_struct *work)
0416 {
0417     mbhc->hs_detect_work_stop = true;
0418     mutex_unlock(&mbhc->lock);
0419     cancel_work_sync(work);
0420     mutex_lock(&mbhc->lock);
0421 }
0422 
0423 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc)
0424 {
0425     /* cancel pending button press */
0426     wcd_cancel_btn_work(mbhc);
0427     /* cancel correct work function */
0428     wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
0429 }
0430 
0431 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
0432 {
0433     wcd_mbhc_cancel_pending_work(mbhc);
0434     /* Report extension cable */
0435     wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
0436     /*
0437      * Disable HPHL trigger and MIC Schmitt triggers.
0438      * Setup for insertion detection.
0439      */
0440     disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
0441     wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE);
0442     /* Disable HW FSM */
0443     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0444     wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3);
0445 
0446     /* Set the detection type appropriately */
0447     wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
0448     enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
0449 }
0450 
0451 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
0452                    enum wcd_mbhc_plug_type plug_type)
0453 {
0454     if (mbhc->current_plug == plug_type)
0455         return;
0456 
0457     mutex_lock(&mbhc->lock);
0458 
0459     switch (plug_type) {
0460     case MBHC_PLUG_TYPE_HEADPHONE:
0461         wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
0462         break;
0463     case MBHC_PLUG_TYPE_HEADSET:
0464         wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
0465         break;
0466     case MBHC_PLUG_TYPE_HIGH_HPH:
0467         wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
0468         break;
0469     case MBHC_PLUG_TYPE_GND_MIC_SWAP:
0470         if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
0471             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
0472         if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
0473             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
0474         break;
0475     default:
0476         WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
0477              mbhc->current_plug, plug_type);
0478         break;
0479     }
0480     mutex_unlock(&mbhc->lock);
0481 }
0482 
0483 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
0484                         struct work_struct *work)
0485 {
0486     WARN_ON(!mutex_is_locked(&mbhc->lock));
0487     mbhc->hs_detect_work_stop = false;
0488     schedule_work(work);
0489 }
0490 
0491 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
0492 {
0493     struct snd_soc_component *component = mbhc->component;
0494 
0495     WARN_ON(!mutex_is_locked(&mbhc->lock));
0496 
0497     if (mbhc->mbhc_cb->hph_pull_down_ctrl)
0498         mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
0499 
0500     wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
0501 
0502     if (mbhc->mbhc_cb->mbhc_micbias_control) {
0503         mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
0504                             MICB_ENABLE);
0505         wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
0506     }
0507 }
0508 
0509 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
0510 {
0511     struct snd_soc_component *component;
0512     enum snd_jack_types jack_type;
0513     struct wcd_mbhc *mbhc = data;
0514     bool detection_type;
0515 
0516     component = mbhc->component;
0517     mutex_lock(&mbhc->lock);
0518 
0519     mbhc->in_swch_irq_handler = true;
0520 
0521     wcd_mbhc_cancel_pending_work(mbhc);
0522 
0523     detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE);
0524 
0525     /* Set the detection type appropriately */
0526     wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type);
0527 
0528     /* Enable micbias ramp */
0529     if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
0530         mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
0531 
0532     if (detection_type) {
0533         if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
0534             goto exit;
0535         /* Make sure MASTER_BIAS_CTL is enabled */
0536         mbhc->mbhc_cb->mbhc_bias(component, true);
0537         mbhc->is_btn_press = false;
0538         wcd_mbhc_adc_detect_plug_type(mbhc);
0539     } else {
0540         /* Disable HW FSM */
0541         wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0542         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
0543         mbhc->extn_cable_hph_rem = false;
0544 
0545         if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE)
0546             goto exit;
0547 
0548         mbhc->is_btn_press = false;
0549         switch (mbhc->current_plug) {
0550         case MBHC_PLUG_TYPE_HEADPHONE:
0551             jack_type = SND_JACK_HEADPHONE;
0552             break;
0553         case MBHC_PLUG_TYPE_HEADSET:
0554             jack_type = SND_JACK_HEADSET;
0555             break;
0556         case MBHC_PLUG_TYPE_HIGH_HPH:
0557             if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC)
0558                 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0);
0559             jack_type = SND_JACK_LINEOUT;
0560             break;
0561         case MBHC_PLUG_TYPE_GND_MIC_SWAP:
0562             dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n");
0563             goto exit;
0564         default:
0565             dev_err(mbhc->dev, "Invalid current plug: %d\n",
0566                 mbhc->current_plug);
0567             goto exit;
0568         }
0569         disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
0570         disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
0571         wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
0572         wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
0573         wcd_mbhc_report_plug(mbhc, 0, jack_type);
0574     }
0575 
0576 exit:
0577     mbhc->in_swch_irq_handler = false;
0578     mutex_unlock(&mbhc->lock);
0579     return IRQ_HANDLED;
0580 }
0581 
0582 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
0583 {
0584     int mask = 0;
0585     int btn;
0586 
0587     btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT);
0588 
0589     switch (btn) {
0590     case 0:
0591         mask = SND_JACK_BTN_0;
0592         break;
0593     case 1:
0594         mask = SND_JACK_BTN_1;
0595         break;
0596     case 2:
0597         mask = SND_JACK_BTN_2;
0598         break;
0599     case 3:
0600         mask = SND_JACK_BTN_3;
0601         break;
0602     case 4:
0603         mask = SND_JACK_BTN_4;
0604         break;
0605     case 5:
0606         mask = SND_JACK_BTN_5;
0607         break;
0608     default:
0609         break;
0610     }
0611 
0612     return mask;
0613 }
0614 
0615 static void wcd_btn_long_press_fn(struct work_struct *work)
0616 {
0617     struct delayed_work *dwork = to_delayed_work(work);
0618     struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
0619 
0620     if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
0621         snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
0622                     mbhc->buttons_pressed);
0623 }
0624 
0625 static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
0626 {
0627     struct wcd_mbhc *mbhc = data;
0628     int mask;
0629     unsigned long msec_val;
0630 
0631     mutex_lock(&mbhc->lock);
0632     wcd_cancel_btn_work(mbhc);
0633     mbhc->is_btn_press = true;
0634     msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
0635 
0636     /* Too short, ignore button press */
0637     if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN)
0638         goto done;
0639 
0640     /* If switch interrupt already kicked in, ignore button press */
0641     if (mbhc->in_swch_irq_handler)
0642         goto done;
0643 
0644     /* Plug isn't headset, ignore button press */
0645     if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET)
0646         goto done;
0647 
0648     mask = wcd_mbhc_get_button_mask(mbhc);
0649     mbhc->buttons_pressed |= mask;
0650     if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0)
0651         WARN(1, "Button pressed twice without release event\n");
0652 done:
0653     mutex_unlock(&mbhc->lock);
0654     return IRQ_HANDLED;
0655 }
0656 
0657 static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data)
0658 {
0659     struct wcd_mbhc *mbhc = data;
0660     int ret;
0661 
0662     mutex_lock(&mbhc->lock);
0663     if (mbhc->is_btn_press)
0664         mbhc->is_btn_press = false;
0665     else /* fake btn press */
0666         goto exit;
0667 
0668     if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK))
0669         goto exit;
0670 
0671     ret = wcd_cancel_btn_work(mbhc);
0672     if (ret == 0) { /* Reporting long button release event */
0673         snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
0674     } else {
0675         if (!mbhc->in_swch_irq_handler) {
0676             /* Reporting btn press n Release */
0677             snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
0678                         mbhc->buttons_pressed);
0679             snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
0680         }
0681     }
0682     mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
0683 exit:
0684     mutex_unlock(&mbhc->lock);
0685 
0686     return IRQ_HANDLED;
0687 }
0688 
0689 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr)
0690 {
0691 
0692     /* TODO Find a better way to report this to Userspace */
0693     dev_err(mbhc->dev, "MBHC Over Current on %s detected\n",
0694         hphr ? "HPHR" : "HPHL");
0695 
0696     wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0);
0697     wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1);
0698 
0699     return IRQ_HANDLED;
0700 }
0701 
0702 static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
0703 {
0704     return wcd_mbhc_hph_ocp_irq(data, false);
0705 }
0706 
0707 static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
0708 {
0709     return wcd_mbhc_hph_ocp_irq(data, true);
0710 }
0711 
0712 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
0713 {
0714     struct snd_soc_component *component = mbhc->component;
0715     int ret;
0716 
0717     ret = pm_runtime_resume_and_get(component->dev);
0718     if (ret < 0 && ret != -EACCES) {
0719         dev_err_ratelimited(component->dev,
0720                     "pm_runtime_resume_and_get failed in %s, ret %d\n",
0721                     __func__, ret);
0722         return ret;
0723     }
0724 
0725     mutex_lock(&mbhc->lock);
0726 
0727     /* enable HS detection */
0728     if (mbhc->mbhc_cb->hph_pull_up_control_v2)
0729         mbhc->mbhc_cb->hph_pull_up_control_v2(component,
0730                               HS_PULLUP_I_DEFAULT);
0731     else if (mbhc->mbhc_cb->hph_pull_up_control)
0732         mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT);
0733     else
0734         wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
0735 
0736     wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh);
0737     wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh);
0738     wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
0739     if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
0740         mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true);
0741     wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
0742 
0743     wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
0744 
0745     /* Insertion debounce set to 96ms */
0746     wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
0747 
0748     /* Button Debounce set to 16ms */
0749     wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
0750 
0751     /* enable bias */
0752     mbhc->mbhc_cb->mbhc_bias(component, true);
0753     /* enable MBHC clock */
0754     if (mbhc->mbhc_cb->clk_setup)
0755         mbhc->mbhc_cb->clk_setup(component, true);
0756 
0757     /* program HS_VREF value */
0758     wcd_program_hs_vref(mbhc);
0759 
0760     wcd_program_btn_threshold(mbhc, false);
0761 
0762     mutex_unlock(&mbhc->lock);
0763 
0764     pm_runtime_mark_last_busy(component->dev);
0765     pm_runtime_put_autosuspend(component->dev);
0766 
0767     return 0;
0768 }
0769 
0770 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
0771 {
0772     int micbias = 0;
0773 
0774     if (mbhc->mbhc_cb->get_micbias_val) {
0775         mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias);
0776     } else {
0777         u8 vout_ctl = 0;
0778         /* Read MBHC Micbias (Mic Bias2) voltage */
0779         vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT);
0780         /* Formula for getting micbias from vout
0781          * micbias = 1.0V + VOUT_CTL * 50mV
0782          */
0783         micbias = 1000 + (vout_ctl * 50);
0784     }
0785     return micbias;
0786 }
0787 
0788 static int wcd_get_voltage_from_adc(u8 val, int micbias)
0789 {
0790     /* Formula for calculating voltage from ADC
0791      * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8
0792      */
0793     return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
0794 }
0795 
0796 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
0797 {
0798     u8 adc_result;
0799     int output_mv;
0800     int retry = 3;
0801     u8 adc_en;
0802 
0803     /* Pre-requisites for ADC continuous measurement */
0804     /* Read legacy electircal detection and disable */
0805     wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
0806     /* Set ADC to continuous measurement */
0807     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1);
0808     /* Read ADC Enable bit to restore after adc measurement */
0809     adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
0810     /* Disable ADC_ENABLE bit */
0811     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
0812     /* Disable MBHC FSM */
0813     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0814     /* Set the MUX selection to IN2P */
0815     wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
0816     /* Enable MBHC FSM */
0817     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0818     /* Enable ADC_ENABLE bit */
0819     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
0820 
0821     while (retry--) {
0822         /* wait for 3 msec before reading ADC result */
0823         usleep_range(3000, 3100);
0824         adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
0825     }
0826 
0827     /* Restore ADC Enable */
0828     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
0829     /* Get voltage from ADC result */
0830     output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc));
0831 
0832     return output_mv;
0833 }
0834 
0835 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
0836 {
0837     struct device *dev = mbhc->dev;
0838     u8 adc_timeout = 0;
0839     u8 adc_complete = 0;
0840     u8 adc_result;
0841     int retry = 6;
0842     int ret;
0843     int output_mv = 0;
0844     u8 adc_en;
0845 
0846     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
0847     /* Read ADC Enable bit to restore after adc measurement */
0848     adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
0849     /* Trigger ADC one time measurement */
0850     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
0851     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0852     /* Set the appropriate MUX selection */
0853     wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl);
0854     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0855     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
0856 
0857     while (retry--) {
0858         /* wait for 600usec to get adc results */
0859         usleep_range(600, 610);
0860 
0861         /* check for ADC Timeout */
0862         adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT);
0863         if (adc_timeout)
0864             continue;
0865 
0866         /* Read ADC complete bit */
0867         adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE);
0868         if (!adc_complete)
0869             continue;
0870 
0871         /* Read ADC result */
0872         adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
0873 
0874         /* Get voltage from ADC result */
0875         output_mv = wcd_get_voltage_from_adc(adc_result,
0876                         wcd_mbhc_get_micbias(mbhc));
0877         break;
0878     }
0879 
0880     /* Restore ADC Enable */
0881     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
0882 
0883     if (retry <= 0) {
0884         dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n",
0885             __func__, adc_complete, adc_timeout);
0886         ret = -EINVAL;
0887     } else {
0888         ret = output_mv;
0889     }
0890 
0891     return ret;
0892 }
0893 
0894 /* To determine if cross connection occurred */
0895 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
0896 {
0897     u8 adc_mode, elect_ctl, adc_en, fsm_en;
0898     int hphl_adc_res, hphr_adc_res;
0899     bool is_cross_conn = false;
0900 
0901     /* If PA is enabled, dont check for cross-connection */
0902     if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
0903         return -EINVAL;
0904 
0905     /* Read legacy electircal detection and disable */
0906     elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC);
0907     wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
0908 
0909     /* Read and set ADC to single measurement */
0910     adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE);
0911     /* Read ADC Enable bit to restore after adc measurement */
0912     adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
0913     /* Read FSM status */
0914     fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
0915 
0916     /* Get adc result for HPH L */
0917     hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
0918     if (hphl_adc_res < 0)
0919         return hphl_adc_res;
0920 
0921     /* Get adc result for HPH R in mV */
0922     hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
0923     if (hphr_adc_res < 0)
0924         return hphr_adc_res;
0925 
0926     if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD ||
0927         hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD)
0928         is_cross_conn = true;
0929 
0930     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
0931     /* Set the MUX selection to Auto */
0932     wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
0933     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
0934     /* Restore ADC Enable */
0935     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
0936     /* Restore ADC mode */
0937     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode);
0938     /* Restore FSM state */
0939     wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
0940     /* Restore electrical detection */
0941     wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
0942 
0943     return is_cross_conn;
0944 }
0945 
0946 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc)
0947 {
0948     int hs_threshold, micbias_mv;
0949 
0950     micbias_mv = wcd_mbhc_get_micbias(mbhc);
0951     if (mbhc->cfg->hs_thr) {
0952         if (mbhc->cfg->micb_mv == micbias_mv)
0953             hs_threshold = mbhc->cfg->hs_thr;
0954         else
0955             hs_threshold = (mbhc->cfg->hs_thr *
0956                 micbias_mv) / mbhc->cfg->micb_mv;
0957     } else {
0958         hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
0959             micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
0960     }
0961     return hs_threshold;
0962 }
0963 
0964 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc)
0965 {
0966     int hph_threshold, micbias_mv;
0967 
0968     micbias_mv = wcd_mbhc_get_micbias(mbhc);
0969     if (mbhc->cfg->hph_thr) {
0970         if (mbhc->cfg->micb_mv == micbias_mv)
0971             hph_threshold = mbhc->cfg->hph_thr;
0972         else
0973             hph_threshold = (mbhc->cfg->hph_thr *
0974                 micbias_mv) / mbhc->cfg->micb_mv;
0975     } else {
0976         hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV *
0977             micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
0978     }
0979     return hph_threshold;
0980 }
0981 
0982 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
0983                        enum wcd_mbhc_plug_type plug_type)
0984 {
0985     bool micbias2 = false;
0986 
0987     switch (plug_type) {
0988     case MBHC_PLUG_TYPE_HEADPHONE:
0989         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0990         break;
0991     case MBHC_PLUG_TYPE_HEADSET:
0992         if (mbhc->mbhc_cb->micbias_enable_status)
0993             micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component,
0994                                     MIC_BIAS_2);
0995 
0996         if (!mbhc->is_hs_recording && !micbias2)
0997             wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
0998         break;
0999     default:
1000         wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1001         break;
1002 
1003     }
1004 }
1005 
1006 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable)
1007 {
1008     switch (plug_type) {
1009     case MBHC_PLUG_TYPE_HEADSET:
1010     case MBHC_PLUG_TYPE_HEADPHONE:
1011         if (mbhc->mbhc_cb->bcs_enable)
1012             mbhc->mbhc_cb->bcs_enable(mbhc->component, enable);
1013         break;
1014     default:
1015         break;
1016     }
1017 }
1018 
1019 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
1020 
1021 {
1022     enum wcd_mbhc_plug_type plug_type;
1023     u32 hph_thr, hs_thr;
1024 
1025     hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc);
1026     hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc);
1027 
1028     if (adc_result < hph_thr)
1029         plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1030     else if (adc_result > hs_thr)
1031         plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1032     else
1033         plug_type = MBHC_PLUG_TYPE_HEADSET;
1034 
1035     return plug_type;
1036 }
1037 
1038 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1039 {
1040     int hs_threshold, micbias_mv;
1041 
1042     micbias_mv = wcd_mbhc_get_micbias(mbhc);
1043     if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) {
1044         if (mbhc->cfg->micb_mv == micbias_mv)
1045             hs_threshold = mbhc->cfg->hs_thr;
1046         else
1047             hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1048     } else {
1049         hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) /
1050                             WCD_MBHC_ADC_MICBIAS_MV);
1051     }
1052     return hs_threshold;
1053 }
1054 
1055 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1056 {
1057     bool is_spl_hs = false;
1058     int output_mv, hs_threshold, hph_threshold;
1059 
1060     if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1061         return false;
1062 
1063     /* Bump up MIC_BIAS2 to 2.7V */
1064     mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true);
1065     usleep_range(10000, 10100);
1066 
1067     output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1068     hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc);
1069     hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc);
1070 
1071     if (!(output_mv > hs_threshold || output_mv < hph_threshold))
1072         is_spl_hs = true;
1073 
1074     /* Back MIC_BIAS2 to 1.8v if the type is not special headset */
1075     if (!is_spl_hs) {
1076         mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false);
1077         /* Add 10ms delay for micbias to settle */
1078         usleep_range(10000, 10100);
1079     }
1080 
1081     return is_spl_hs;
1082 }
1083 
1084 static void wcd_correct_swch_plug(struct work_struct *work)
1085 {
1086     struct wcd_mbhc *mbhc;
1087     struct snd_soc_component *component;
1088     enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
1089     unsigned long timeout;
1090     int pt_gnd_mic_swap_cnt = 0;
1091     int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv;
1092     bool is_spl_hs = false;
1093     bool is_pa_on;
1094     int ret;
1095 
1096     mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1097     component = mbhc->component;
1098 
1099     ret = pm_runtime_resume_and_get(component->dev);
1100     if (ret < 0 && ret != -EACCES) {
1101         dev_err_ratelimited(component->dev,
1102                     "pm_runtime_resume_and_get failed in %s, ret %d\n",
1103                     __func__, ret);
1104         return;
1105     }
1106     micbias_mv = wcd_mbhc_get_micbias(mbhc);
1107     hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1108 
1109     /* Mask ADC COMPLETE interrupt */
1110     disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1111 
1112     /* Check for cross connection */
1113     do {
1114         cross_conn = wcd_check_cross_conn(mbhc);
1115         try++;
1116     } while (try < GND_MIC_SWAP_THRESHOLD);
1117 
1118     if (cross_conn > 0) {
1119         plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1120         dev_err(mbhc->dev, "cross connection found, Plug type %d\n",
1121             plug_type);
1122         goto correct_plug_type;
1123     }
1124 
1125     /* Find plug type */
1126     output_mv = wcd_measure_adc_continuous(mbhc);
1127     plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1128 
1129     /*
1130      * Report plug type if it is either headset or headphone
1131      * else start the 3 sec loop
1132      */
1133     switch (plug_type) {
1134     case MBHC_PLUG_TYPE_HEADPHONE:
1135         wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1136         break;
1137     case MBHC_PLUG_TYPE_HEADSET:
1138         wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1139         wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1140         wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1141         wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1142         break;
1143     default:
1144         break;
1145     }
1146 
1147 correct_plug_type:
1148 
1149     /* Disable BCS slow insertion detection */
1150     wcd_mbhc_bcs_enable(mbhc, plug_type, false);
1151 
1152     timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1153 
1154     while (!time_after(jiffies, timeout)) {
1155         if (mbhc->hs_detect_work_stop) {
1156             wcd_micbias_disable(mbhc);
1157             goto exit;
1158         }
1159 
1160         msleep(180);
1161         /*
1162          * Use ADC single mode to minimize the chance of missing out
1163          * btn press/release for HEADSET type during correct work.
1164          */
1165         output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1166         plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1167         is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
1168 
1169         if (output_mv > hs_threshold && !is_spl_hs) {
1170             is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc);
1171             output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1172 
1173             if (is_spl_hs) {
1174                 hs_threshold *= wcd_mbhc_get_micbias(mbhc);
1175                 hs_threshold /= micbias_mv;
1176             }
1177         }
1178 
1179         if ((output_mv <= hs_threshold) && !is_pa_on) {
1180             /* Check for cross connection*/
1181             cross_conn = wcd_check_cross_conn(mbhc);
1182             if (cross_conn > 0) { /* cross-connection */
1183                 pt_gnd_mic_swap_cnt++;
1184                 if (pt_gnd_mic_swap_cnt < GND_MIC_SWAP_THRESHOLD)
1185                     continue;
1186                 else
1187                     plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1188             } else if (!cross_conn) { /* no cross connection */
1189                 pt_gnd_mic_swap_cnt = 0;
1190                 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1191                 continue;
1192             } else if (cross_conn < 0) /* Error */
1193                 continue;
1194 
1195             if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) {
1196                 /* US_EU gpio present, flip switch */
1197                 if (mbhc->cfg->swap_gnd_mic) {
1198                     if (mbhc->cfg->swap_gnd_mic(component, true))
1199                         continue;
1200                 }
1201             }
1202         }
1203 
1204         /* cable is extension cable */
1205         if (output_mv > hs_threshold || mbhc->force_linein)
1206             plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1207     }
1208 
1209     wcd_mbhc_bcs_enable(mbhc, plug_type, true);
1210 
1211     if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
1212         if (is_spl_hs)
1213             plug_type = MBHC_PLUG_TYPE_HEADSET;
1214         else
1215             wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1216     }
1217 
1218     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1219     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1220     wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1221 
1222     /*
1223      * Set DETECTION_DONE bit for HEADSET
1224      * so that btn press/release interrupt can be generated.
1225      * For other plug type, clear the bit.
1226      */
1227     if (plug_type == MBHC_PLUG_TYPE_HEADSET)
1228         wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1229     else
1230         wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1231 
1232     if (mbhc->mbhc_cb->mbhc_micbias_control)
1233         wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
1234 
1235 exit:
1236     if (mbhc->mbhc_cb->mbhc_micbias_control/* &&  !mbhc->micbias_enable*/)
1237         mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
1238 
1239     /*
1240      * If plug type is corrected from special headset to headphone,
1241      * clear the micbias enable flag, set micbias back to 1.8V and
1242      * disable micbias.
1243      */
1244     if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
1245         wcd_micbias_disable(mbhc);
1246         /*
1247          * Enable ADC COMPLETE interrupt for HEADPHONE.
1248          * Btn release may happen after the correct work, ADC COMPLETE
1249          * interrupt needs to be captured to correct plug type.
1250          */
1251         enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
1252     }
1253 
1254     if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1255         mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
1256 
1257     pm_runtime_mark_last_busy(component->dev);
1258     pm_runtime_put_autosuspend(component->dev);
1259 }
1260 
1261 static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
1262 {
1263     struct wcd_mbhc *mbhc = data;
1264     unsigned long timeout;
1265     int adc_threshold, output_mv, retry = 0;
1266 
1267     mutex_lock(&mbhc->lock);
1268     timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
1269     adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1270 
1271     do {
1272         retry++;
1273         /*
1274          * read output_mv every 10ms to look for
1275          * any change in IN2_P
1276          */
1277         usleep_range(10000, 10100);
1278         output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1279 
1280         /* Check for fake removal */
1281         if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS)
1282             goto exit;
1283     } while (!time_after(jiffies, timeout));
1284 
1285     /*
1286      * ADC COMPLETE and ELEC_REM interrupts are both enabled for
1287      * HEADPHONE, need to reject the ADC COMPLETE interrupt which
1288      * follows ELEC_REM one when HEADPHONE is removed.
1289      */
1290     if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
1291         mbhc->extn_cable_hph_rem = true;
1292 
1293     wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1294     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1295     wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1296     wcd_mbhc_elec_hs_report_unplug(mbhc);
1297     wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1298 
1299 exit:
1300     mutex_unlock(&mbhc->lock);
1301     return IRQ_HANDLED;
1302 }
1303 
1304 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
1305 {
1306     struct wcd_mbhc *mbhc = data;
1307     u8 clamp_state;
1308     u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
1309 
1310     /*
1311      * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
1312      * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
1313      * when HEADPHONE is removed.
1314      */
1315     if (mbhc->extn_cable_hph_rem == true) {
1316         mbhc->extn_cable_hph_rem = false;
1317         return IRQ_HANDLED;
1318     }
1319 
1320     do {
1321         clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE);
1322         if (clamp_state)
1323             return IRQ_HANDLED;
1324         /*
1325          * check clamp for 120ms but at 30ms chunks to leave
1326          * room for other interrupts to be processed
1327          */
1328         usleep_range(30000, 30100);
1329     } while (--clamp_retry);
1330 
1331     /*
1332      * If current plug is headphone then there is no chance to
1333      * get ADC complete interrupt, so connected cable should be
1334      * headset not headphone.
1335      */
1336     if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1337         disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1338         wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1339         wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
1340         return IRQ_HANDLED;
1341     }
1342 
1343     return IRQ_HANDLED;
1344 }
1345 
1346 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
1347 {
1348     *zl = mbhc->zl;
1349     *zr = mbhc->zr;
1350 
1351     if (*zl && *zr)
1352         return 0;
1353     else
1354         return -EINVAL;
1355 }
1356 EXPORT_SYMBOL(wcd_mbhc_get_impedance);
1357 
1358 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1359 {
1360     mbhc->hph_type = hph_type;
1361 }
1362 EXPORT_SYMBOL(wcd_mbhc_set_hph_type);
1363 
1364 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1365 {
1366     return mbhc->hph_type;
1367 }
1368 EXPORT_SYMBOL(wcd_mbhc_get_hph_type);
1369 
1370 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg,
1371            struct snd_soc_jack *jack)
1372 {
1373     if (!mbhc || !cfg || !jack)
1374         return -EINVAL;
1375 
1376     mbhc->cfg = cfg;
1377     mbhc->jack = jack;
1378 
1379     return wcd_mbhc_initialise(mbhc);
1380 }
1381 EXPORT_SYMBOL(wcd_mbhc_start);
1382 
1383 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
1384 {
1385     mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
1386     mbhc->hph_status = 0;
1387     disable_irq_nosync(mbhc->intr_ids->hph_left_ocp);
1388     disable_irq_nosync(mbhc->intr_ids->hph_right_ocp);
1389 }
1390 EXPORT_SYMBOL(wcd_mbhc_stop);
1391 
1392 int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg)
1393 {
1394     struct device_node *np = dev->of_node;
1395     int ret, i, microvolt;
1396 
1397     if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed"))
1398         cfg->hphl_swh = false;
1399     else
1400         cfg->hphl_swh = true;
1401 
1402     if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed"))
1403         cfg->gnd_swh = false;
1404     else
1405         cfg->gnd_swh = true;
1406 
1407     ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
1408                    &microvolt);
1409     if (ret)
1410         dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
1411     else
1412         cfg->hs_thr = microvolt/1000;
1413 
1414     ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
1415                    &microvolt);
1416     if (ret)
1417         dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n");
1418     else
1419         cfg->hph_thr = microvolt/1000;
1420 
1421     ret = of_property_read_u32_array(np,
1422                      "qcom,mbhc-buttons-vthreshold-microvolt",
1423                      &cfg->btn_high[0],
1424                      WCD_MBHC_DEF_BUTTONS);
1425     if (ret)
1426         dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n");
1427 
1428     for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) {
1429         if (ret) /* default voltage */
1430             cfg->btn_high[i] = 500000;
1431         else
1432             /* Micro to Milli Volts */
1433             cfg->btn_high[i] = cfg->btn_high[i]/1000;
1434     }
1435 
1436     return 0;
1437 }
1438 EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
1439 
1440 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
1441                    const struct wcd_mbhc_cb *mbhc_cb,
1442                    const struct wcd_mbhc_intr *intr_ids,
1443                    struct wcd_mbhc_field *fields,
1444                    bool impedance_det_en)
1445 {
1446     struct device *dev = component->dev;
1447     struct wcd_mbhc *mbhc;
1448     int ret;
1449 
1450     if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) {
1451         dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__);
1452         return ERR_PTR(-EINVAL);
1453     }
1454 
1455     mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL);
1456     if (!mbhc)
1457         return ERR_PTR(-ENOMEM);
1458 
1459     mbhc->component = component;
1460     mbhc->dev = dev;
1461     mbhc->intr_ids = intr_ids;
1462     mbhc->mbhc_cb = mbhc_cb;
1463     mbhc->fields = fields;
1464     mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
1465 
1466     if (mbhc_cb->compute_impedance)
1467         mbhc->impedance_detect = impedance_det_en;
1468 
1469     INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn);
1470 
1471     mutex_init(&mbhc->lock);
1472 
1473     INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1474 
1475     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL,
1476                     wcd_mbhc_mech_plug_detect_irq,
1477                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1478                     "mbhc sw intr", mbhc);
1479     if (ret)
1480         goto err;
1481 
1482     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL,
1483                     wcd_mbhc_btn_press_handler,
1484                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1485                     "Button Press detect", mbhc);
1486     if (ret)
1487         goto err;
1488 
1489     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL,
1490                     wcd_mbhc_btn_release_handler,
1491                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1492                     "Button Release detect", mbhc);
1493     if (ret)
1494         goto err;
1495 
1496     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
1497                     wcd_mbhc_adc_hs_ins_irq,
1498                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1499                     "Elect Insert", mbhc);
1500     if (ret)
1501         goto err;
1502 
1503     disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1504 
1505     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
1506                     wcd_mbhc_adc_hs_rem_irq,
1507                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1508                     "Elect Remove", mbhc);
1509     if (ret)
1510         goto err;
1511 
1512     disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
1513 
1514     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL,
1515                     wcd_mbhc_hphl_ocp_irq,
1516                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1517                     "HPH_L OCP detect", mbhc);
1518     if (ret)
1519         goto err;
1520 
1521     ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL,
1522                     wcd_mbhc_hphr_ocp_irq,
1523                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1524                     "HPH_R OCP detect", mbhc);
1525     if (ret)
1526         goto err;
1527 
1528     return mbhc;
1529 err:
1530     dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
1531 
1532     return ERR_PTR(ret);
1533 }
1534 EXPORT_SYMBOL(wcd_mbhc_init);
1535 
1536 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
1537 {
1538     mutex_lock(&mbhc->lock);
1539     wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1540     mutex_unlock(&mbhc->lock);
1541 }
1542 EXPORT_SYMBOL(wcd_mbhc_deinit);
1543 
1544 static int __init mbhc_init(void)
1545 {
1546     return 0;
1547 }
1548 
1549 static void __exit mbhc_exit(void)
1550 {
1551 }
1552 
1553 module_init(mbhc_init);
1554 module_exit(mbhc_exit);
1555 
1556 MODULE_DESCRIPTION("wcd MBHC v2 module");
1557 MODULE_LICENSE("GPL");