Merge remote-tracking branches 'asoc/topic/dwc', 'asoc/topic/fallthrough', 'asoc...
authorMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:31:13 +0000 (21:31 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:31:13 +0000 (21:31 +0000)
1  2  3  4  5  6 
sound/soc/codecs/msm8916-wcd-analog.c

      #include <sound/pcm.h>
      #include <sound/pcm_params.h>
      #include <sound/tlv.h>
    + #include <sound/jack.h>
      
      #define CDC_D_REVISION1                   (0xf000)
      #define CDC_D_PERPH_SUBTYPE               (0xf005)
    + #define CDC_D_INT_EN_SET          (0x015)
    + #define CDC_D_INT_EN_CLR          (0x016)
    + #define MBHC_SWITCH_INT                   BIT(7)
    + #define MBHC_MIC_ELECTRICAL_INS_REM_DET   BIT(6)
    + #define MBHC_BUTTON_PRESS_DET             BIT(5)
    + #define MBHC_BUTTON_RELEASE_DET           BIT(4)
      #define CDC_D_CDC_RST_CTL         (0xf046)
      #define RST_CTL_DIG_SW_RST_N_MASK BIT(7)
      #define RST_CTL_DIG_SW_RST_N_RESET        0
      #define CDC_D_CDC_DIG_CLK_CTL             (0xf04A)
      #define DIG_CLK_CTL_RXD1_CLK_EN           BIT(0)
      #define DIG_CLK_CTL_RXD2_CLK_EN           BIT(1)
    - #define DIG_CLK_CTL_RXD3_CLK_EN           BIT(3)
    + #define DIG_CLK_CTL_RXD3_CLK_EN           BIT(2)
    + #define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK    BIT(3)
    + #define DIG_CLK_CTL_D_MBHC_CLK_EN BIT(3)
      #define DIG_CLK_CTL_TXD_CLK_EN            BIT(4)
      #define DIG_CLK_CTL_NCP_CLK_EN_MASK       BIT(6)
      #define DIG_CLK_CTL_NCP_CLK_EN            BIT(6)
      #define MICB_1_EN_TX3_GND_SEL_TX_GND      0
      
      #define CDC_A_MICB_1_VAL          (0xf141)
 --- -#define MICB_VOLTAGE_REGVAL(v)            ((v - MICB_MIN_VAL)/MICB_STEP_SIZE)
    + #define MICB_MIN_VAL 1600
    + #define MICB_STEP_SIZE 50
 +++++#define MICB_VOLTAGE_REGVAL(v)            (((v - MICB_MIN_VAL)/MICB_STEP_SIZE) << 3)
      #define MICB_1_VAL_MICB_OUT_VAL_MASK      GENMASK(7, 3)
      #define MICB_1_VAL_MICB_OUT_VAL_V2P70V    ((0x16)  << 3)
    + #define MICB_1_VAL_MICB_OUT_VAL_V1P80V    ((0x4)  << 3)
      #define CDC_A_MICB_1_CTL          (0xf142)
      
      #define MICB_1_CTL_CFILT_REF_SEL_MASK             BIT(1)
      #define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND  0
      
      #define CDC_A_MICB_2_EN                   (0xf144)
    + #define CDC_A_MICB_2_EN_ENABLE            BIT(7)
    + #define CDC_A_MICB_2_PULL_DOWN_EN_MASK    BIT(5)
    + #define CDC_A_MICB_2_PULL_DOWN_EN BIT(5)
      #define CDC_A_TX_1_2_ATEST_CTL_2  (0xf145)
      #define CDC_A_MASTER_BIAS_CTL             (0xf146)
    + #define CDC_A_MBHC_DET_CTL_1              (0xf147)
    + #define CDC_A_MBHC_DET_CTL_L_DET_EN                       BIT(7)
    + #define CDC_A_MBHC_DET_CTL_GND_DET_EN                     BIT(6)
    + #define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION        BIT(5)
    + #define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL  (0)
    + #define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK             BIT(5)
    + #define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT            (5)
    + #define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO             BIT(4)
    + #define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL           BIT(3)
    + #define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK             GENMASK(4, 3)
    + #define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN                   BIT(2)
    + #define CDC_A_MBHC_DET_CTL_2              (0xf150)
    + #define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0    (BIT(7) | BIT(6))
    + #define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD   BIT(5)
    + #define CDC_A_PLUG_TYPE_MASK                              GENMASK(4, 3)
    + #define CDC_A_HPHL_PLUG_TYPE_NO                           BIT(4)
    + #define CDC_A_GND_PLUG_TYPE_NO                            BIT(3)
    + #define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK       BIT(0)
    + #define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN            BIT(0)
    + #define CDC_A_MBHC_FSM_CTL                (0xf151)
    + #define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN                    BIT(7)
    + #define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK               BIT(7)
    + #define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA  (0x3 << 4)
    + #define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK             GENMASK(6, 4)
    + #define CDC_A_MBHC_DBNC_TIMER             (0xf152)
    + #define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS             BIT(3)
    + #define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS        (0x9 << 4)
    + #define CDC_A_MBHC_BTN0_ZDET_CTL_0        (0xf153)
    + #define CDC_A_MBHC_BTN1_ZDET_CTL_1        (0xf154)
    + #define CDC_A_MBHC_BTN2_ZDET_CTL_2        (0xf155)
    + #define CDC_A_MBHC_BTN3_CTL               (0xf156)
    + #define CDC_A_MBHC_BTN4_CTL               (0xf157)
    + #define CDC_A_MBHC_BTN_VREF_FINE_SHIFT    (2)
    + #define CDC_A_MBHC_BTN_VREF_FINE_MASK     GENMASK(4, 2)
    + #define CDC_A_MBHC_BTN_VREF_COARSE_MASK   GENMASK(7, 5)
    + #define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5)
    + #define CDC_A_MBHC_BTN_VREF_MASK  (CDC_A_MBHC_BTN_VREF_COARSE_MASK | \
    +                                   CDC_A_MBHC_BTN_VREF_FINE_MASK)
    + #define CDC_A_MBHC_RESULT_1               (0xf158)
    + #define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK       GENMASK(4, 0)
      #define CDC_A_TX_1_EN                     (0xf160)
      #define CDC_A_TX_2_EN                     (0xf161)
      #define CDC_A_TX_1_2_TEST_CTL_1           (0xf162)
      #define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
                                    SNDRV_PCM_FMTBIT_S24_LE)
      
    + static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
    +          SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
    + static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
    + 
      static const char * const supply_names[] = {
        "vdd-cdc-io",
        "vdd-cdc-tx-rx-cx",
      };
      
    + #define MBHC_MAX_BUTTONS  (5)
    + 
      struct pm8916_wcd_analog_priv {
        u16 pmic_rev;
        u16 codec_version;
    +   bool    mbhc_btn_enabled;
    +   /* special event to detect accessory type */
    +   bool    mbhc_btn0_pressed;
    +   bool    detect_accessory_type;
        struct clk *mclk;
    +   struct snd_soc_codec *codec;
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
    +   struct snd_soc_jack *jack;
    +   bool hphl_jack_type_normally_open;
    +   bool gnd_jack_type_normally_open;
    +   /* Voltage threshold when internal current source of 100uA is used */
    +   u32 vref_btn_cs[MBHC_MAX_BUTTONS];
    +   /* Voltage threshold when microphone bias is ON */
    +   u32 vref_btn_micb[MBHC_MAX_BUTTONS];
        unsigned int micbias1_cap_mode;
        unsigned int micbias2_cap_mode;
    +   unsigned int micbias_mv;
      };
      
      static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
@@@@@@@ -340,26 -340,25 -340,25 -340,25 -265,18 -340,25 +340,26 @@@@@@@ static const struct snd_kcontrol_new pm
      
      static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
      {
    +   struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
    + 
        snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
                            MICB_1_CTL_EXT_PRECHARG_EN_MASK |
                            MICB_1_CTL_INT_PRECHARG_BYP_MASK,
                            MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
                            | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
      
    -   snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V);
    -   /*
    -    * Special headset needs MICBIAS as 2.7V so wait for
    -    * 50 msec for the MICBIAS to reach 2.7 volts.
    -    */
    -   msleep(50);
    +   if (wcd->micbias_mv) {
 --- -          snd_soc_write(codec, CDC_A_MICB_1_VAL,
 --- -                        MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
 +++++          snd_soc_update_bits(codec, CDC_A_MICB_1_VAL,
 +++++                              MICB_1_VAL_MICB_OUT_VAL_MASK,
 +++++                              MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
    +           /*
    +            * Special headset needs MICBIAS as 2.7V so wait for
    +            * 50 msec for the MICBIAS to reach 2.7 volts.
    +            */
    +           if (wcd->micbias_mv >= 2700)
    +                   msleep(50);
    +   }
    + 
        snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
                            MICB_1_CTL_EXT_PRECHARG_EN_MASK |
                            MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
@@@@@@@ -444,97 -443,97 -443,97 -443,97 -361,6 -443,97 +444,97 @@@@@@@ static int pm8916_wcd_analog_enable_mic
                                                     wcd->micbias1_cap_mode);
      }
      
    + static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
    + {
    +   struct snd_soc_codec *codec = wcd->codec;
    +   u32 plug_type = 0;
    +   u32 int_en_mask;
    + 
    +   snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
    +                 CDC_A_MBHC_DET_CTL_L_DET_EN |
    +                 CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
    +                 CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
    +                 CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
    + 
    +   if (wcd->hphl_jack_type_normally_open)
    +           plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
    + 
    +   if (wcd->gnd_jack_type_normally_open)
    +           plug_type |= CDC_A_GND_PLUG_TYPE_NO;
    + 
    +   snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
    +                 CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
    +                 CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
    +                 plug_type |
    +                 CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
    + 
    + 
    +   snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
    +                 CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
    +                 CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
    + 
    +   /* enable MBHC clock */
    +   snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
    +                       DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
    +                       DIG_CLK_CTL_D_MBHC_CLK_EN);
    + 
    +   int_en_mask = MBHC_SWITCH_INT;
    +   if (wcd->mbhc_btn_enabled)
    +           int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
    + 
    +   snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
    +   snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
    +   wcd->mbhc_btn0_pressed = false;
    +   wcd->detect_accessory_type = true;
    + }
    + 
    + static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
    +                                 bool micbias2_enabled)
    + {
    +   struct snd_soc_codec *codec = priv->codec;
    +   u32 coarse, fine, reg_val, reg_addr;
    +   int *vrefs, i;
    + 
    +   if (!micbias2_enabled) { /* use internal 100uA Current source */
    +           /* Enable internal 2.2k Internal Rbias Resistor */
    +           snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
    +                               MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
    +                               MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
    +           /* Remove pull down on MIC BIAS2 */
    +           snd_soc_update_bits(codec, CDC_A_MICB_2_EN,
    +                              CDC_A_MICB_2_PULL_DOWN_EN_MASK,
    +                              0);
    +           /* enable 100uA internal current source */
    +           snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
    +                               CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
    +                               CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
    +   }
    +   snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
    +                   CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
    +                   CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
    + 
    +   if (micbias2_enabled)
    +           vrefs = &priv->vref_btn_micb[0];
    +   else
    +           vrefs = &priv->vref_btn_cs[0];
    + 
    +   /* program vref ranges for all the buttons */
    +   reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0;
    +   for (i = 0; i <  MBHC_MAX_BUTTONS; i++) {
    +           /* split mv in to coarse parts of 100mv & fine parts of 12mv */
    +           coarse = (vrefs[i] / 100);
    +           fine = ((vrefs[i] % 100) / 12);
    +           reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
    +                    (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
    +           snd_soc_update_bits(codec, reg_addr,
    +                          CDC_A_MBHC_BTN_VREF_MASK,
    +                          reg_val);
    +           reg_addr++;
    +   }
    + 
    +   return 0;
    + }
    + 
      static int pm8916_wcd_analog_enable_micbias_int2(struct
                                                  snd_soc_dapm_widget
                                                  *w, struct snd_kcontrol
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
      
    +   switch (event) {
    +   case SND_SOC_DAPM_POST_PMU:
    +           pm8916_mbhc_configure_bias(wcd, true);
    +           break;
    +   case SND_SOC_DAPM_POST_PMD:
    +           pm8916_mbhc_configure_bias(wcd, false);
    +           break;
    +   }
    + 
        return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
                                                     wcd->micbias2_cap_mode);
      }
@@@@@@@ -615,6 -614,6 -614,7 -614,6 -432,6 -614,6 +615,7 @@@@@@@ static int pm8916_wcd_analog_enable_adc
                case CDC_A_TX_2_EN:
                        snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
                                            MICB_1_CTL_CFILT_REF_SEL_MASK, 0);
++ +++                  /* fall through */
                case CDC_A_TX_3_EN:
                        snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
                                            CONN_TX2_SERIAL_TX2_MUX,
@@@@@@@ -719,14 -718,14 -719,14 -718,14 -536,6 -718,14 +720,14 @@@@@@@ static int pm8916_wcd_analog_probe(stru
                snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
                              wcd_reg_defaults_2_0[reg].def);
      
    +   priv->codec = codec;
    + 
    +   snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
    +                       RST_CTL_DIG_SW_RST_N_MASK,
    +                       RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
    + 
    +   pm8916_wcd_setup_mbhc(priv);
    + 
        return 0;
      }
      
@@@@@@@ -734,9 -733,9 -734,9 -733,9 -543,6 -733,9 +735,9 @@@@@@@ static int pm8916_wcd_analog_remove(str
      {
        struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
      
    +   snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
    +                       RST_CTL_DIG_SW_RST_N_MASK, 0);
    + 
        return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
                                      priv->supplies);
      }
@@@@@@@ -925,128 -924,128 -925,128 -924,128 -731,32 -924,128 +926,128 @@@@@@@ static const struct snd_soc_dapm_widge
        SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
      };
      
    + static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
    +                                 struct snd_soc_jack *jack,
    +                                 void *data)
    + {
    +   struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
    + 
    +   wcd->jack = jack;
    + 
    +   return 0;
    + }
    + 
      static struct regmap *pm8916_get_regmap(struct device *dev)
      {
        return dev_get_regmap(dev->parent, NULL);
      }
      
    - static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream,
    -                                 struct snd_soc_dai *dai)
    + static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
      {
    -   snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
    -                       RST_CTL_DIG_SW_RST_N_MASK,
    -                       RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
    +   struct pm8916_wcd_analog_priv *priv = arg;
      
    -   return 0;
    +   if (priv->detect_accessory_type) {
    +           struct snd_soc_codec *codec = priv->codec;
    +           u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1);
    + 
    +           /* check if its BTN0 thats released */
    +           if ((val != -1) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
    +                   priv->mbhc_btn0_pressed = false;
    + 
    +   } else {
    +           snd_soc_jack_report(priv->jack, 0, btn_mask);
    +   }
    + 
    +   return IRQ_HANDLED;
      }
      
    - static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream,
    -                                    struct snd_soc_dai *dai)
    + static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
      {
    -   snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
    -                       RST_CTL_DIG_SW_RST_N_MASK, 0);
    +   struct pm8916_wcd_analog_priv *priv = arg;
    +   struct snd_soc_codec *codec = priv->codec;
    +   u32 btn_result;
    + 
    +   btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) &
    +                             CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
    + 
    +   switch (btn_result) {
    +   case 0xf:
    +           snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask);
    +           break;
    +   case 0x7:
    +           snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask);
    +           break;
    +   case 0x3:
    +           snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask);
    +           break;
    +   case 0x1:
    +           snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask);
    +           break;
    +   case 0x0:
    +           /* handle BTN_0 specially for type detection */
    +           if (priv->detect_accessory_type)
    +                   priv->mbhc_btn0_pressed = true;
    +           else
    +                   snd_soc_jack_report(priv->jack,
    +                                       SND_JACK_BTN_0, btn_mask);
    +           break;
    +   default:
    +           dev_err(codec->dev,
    +                   "Unexpected button press result (%x)", btn_result);
    +           break;
    +   }
    + 
    +   return IRQ_HANDLED;
      }
      
    - static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = {
    -   .startup = pm8916_wcd_analog_startup,
    -   .shutdown = pm8916_wcd_analog_shutdown,
    - };
    + static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
    + {
    +   struct pm8916_wcd_analog_priv *priv = arg;
    +   struct snd_soc_codec *codec = priv->codec;
    +   bool ins = false;
    + 
    +   if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) &
    +                           CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
    +           ins = true;
    + 
    +   /* Set the detection type appropriately */
    +   snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1,
    +                       CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
    +                       (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
    + 
    + 
    +   if (ins) { /* hs insertion */
    +           bool micbias_enabled = false;
    + 
    +           if (snd_soc_read(codec, CDC_A_MICB_2_EN) &
    +                           CDC_A_MICB_2_EN_ENABLE)
    +                   micbias_enabled = true;
    + 
    +           pm8916_mbhc_configure_bias(priv, micbias_enabled);
    + 
    +           /*
    +            * if only a btn0 press event is receive just before
    +            * insert event then its a 3 pole headphone else if
    +            * both press and release event received then its
    +            * a headset.
    +            */
    +           if (priv->mbhc_btn0_pressed)
    +                   snd_soc_jack_report(priv->jack,
    +                                       SND_JACK_HEADPHONE, hs_jack_mask);
    +           else
    +                   snd_soc_jack_report(priv->jack,
    +                                       SND_JACK_HEADSET, hs_jack_mask);
    + 
    +           priv->detect_accessory_type = false;
    + 
    +   } else { /* removal */
    +           snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
    +           priv->detect_accessory_type = true;
    +           priv->mbhc_btn0_pressed = false;
    +   }
    + 
    +   return IRQ_HANDLED;
    + }
      
      static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
        [0] = {
                            .channels_min = 1,
                            .channels_max = 3,
                            },
    -          .ops = &pm8916_wcd_analog_dai_ops,
               },
        [1] = {
               .name = "pm8916_wcd_analog_pdm_tx",
                           .channels_min = 1,
                           .channels_max = 4,
                           },
    -          .ops = &pm8916_wcd_analog_dai_ops,
               },
      };
      
    - static struct snd_soc_codec_driver pm8916_wcd_analog = {
    + static const struct snd_soc_codec_driver pm8916_wcd_analog = {
        .probe = pm8916_wcd_analog_probe,
        .remove = pm8916_wcd_analog_remove,
    +   .set_jack = pm8916_wcd_analog_set_jack,
        .get_regmap = pm8916_get_regmap,
        .component_driver = {
                .controls = pm8916_wcd_analog_snd_controls,
      static int pm8916_wcd_analog_parse_dt(struct device *dev,
                                       struct pm8916_wcd_analog_priv *priv)
      {
    +   int rval;
      
        if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
                priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
        else
                priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
      
    +   of_property_read_u32(dev->of_node, "qcom,micbias-lvl",
    +                        &priv->micbias_mv);
    + 
    +   if (of_property_read_bool(dev->of_node,
    +                             "qcom,hphl-jack-type-normally-open"))
    +           priv->hphl_jack_type_normally_open = true;
    +   else
    +           priv->hphl_jack_type_normally_open = false;
    + 
    +   if (of_property_read_bool(dev->of_node,
    +                             "qcom,gnd-jack-type-normally-open"))
    +           priv->gnd_jack_type_normally_open = true;
    +   else
    +           priv->gnd_jack_type_normally_open = false;
    + 
    +   priv->mbhc_btn_enabled = true;
    +   rval = of_property_read_u32_array(dev->of_node,
    +                                     "qcom,mbhc-vthreshold-low",
    +                                     &priv->vref_btn_cs[0],
    +                                     MBHC_MAX_BUTTONS);
    +   if (rval < 0) {
    +           priv->mbhc_btn_enabled = false;
    +   } else {
    +           rval = of_property_read_u32_array(dev->of_node,
    +                                             "qcom,mbhc-vthreshold-high",
    +                                             &priv->vref_btn_micb[0],
    +                                             MBHC_MAX_BUTTONS);
    +           if (rval < 0)
    +                   priv->mbhc_btn_enabled = false;
    +   }
    + 
    +   if (!priv->mbhc_btn_enabled)
    +           dev_err(dev,
    +                   "DT property missing, MBHC btn detection disabled\n");
    + 
    + 
        return 0;
      }
      
@@@@@@@ -1146,7 -1145,7 -1146,7 -1145,7 -820,7 -1145,7 +1147,7 @@@@@@@ static int pm8916_wcd_analog_spmi_probe
      {
        struct pm8916_wcd_analog_priv *priv;
        struct device *dev = &pdev->dev;
    -   int ret, i;
    +   int ret, i, irq;
      
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return ret;
        }
      
    +   irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
    +   if (irq < 0) {
    +           dev_err(dev, "failed to get mbhc switch irq\n");
    +           return irq;
    +   }
    + 
    +   ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler,
    +                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
    +                          IRQF_ONESHOT,
    +                          "mbhc switch irq", priv);
    +   if (ret)
    +           dev_err(dev, "cannot request mbhc switch irq\n");
    + 
    +   if (priv->mbhc_btn_enabled) {
    +           irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
    +           if (irq < 0) {
    +                   dev_err(dev, "failed to get button press irq\n");
    +                   return irq;
    +           }
    + 
    +           ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler,
    +                                  IRQF_TRIGGER_RISING |
    +                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +                                  "mbhc btn press irq", priv);
    +           if (ret)
    +                   dev_err(dev, "cannot request mbhc button press irq\n");
    + 
    +           irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
    +           if (irq < 0) {
    +                   dev_err(dev, "failed to get button release irq\n");
    +                   return irq;
    +           }
    + 
    +           ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler,
    +                                  IRQF_TRIGGER_RISING |
    +                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
    +                                  "mbhc btn release irq", priv);
    +           if (ret)
    +                   dev_err(dev, "cannot request mbhc button release irq\n");
    + 
    +   }
    + 
        dev_set_drvdata(dev, priv);
      
        return snd_soc_register_codec(dev, &pm8916_wcd_analog,