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 >= 0) && !(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 const 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] = {