aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt17
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c373
2 files changed, 388 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
index 05b67a1d4851..551ecab67efe 100644
--- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
@@ -31,9 +31,22 @@ Required properties
31 - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. 31 - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node.
32 - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. 32 - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node.
33 - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. 33 - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node.
34
35Optional Properties: 34Optional Properties:
35 - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons
36 detection on headset when the mbhc is powered up
37 by internal current source, this is a low power.
38 - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons
39 detection on headset when mbhc is powered up
40 from micbias.
36- qcom,micbias-lvl: Voltage (mV) for Mic Bias 41- qcom,micbias-lvl: Voltage (mV) for Mic Bias
42- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a
43 NO (Normally Open). If not specified, then
44 its assumed that hphl pin on jack is NC
45 (Normally Closed).
46- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is
47 NO (Normally Open). If not specified, then
48 its assumed that gnd pin on jack is NC
49 (Normally Closed).
37- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor 50- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor
38 connected. 51 connected.
39- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor 52- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor
@@ -49,6 +62,8 @@ spmi_bus {
49 reg-names = "pmic-codec-core"; 62 reg-names = "pmic-codec-core";
50 clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; 63 clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
51 clock-names = "mclk"; 64 clock-names = "mclk";
65 qcom,mbhc-vthreshold-low = <75 150 237 450 500>;
66 qcom,mbhc-vthreshold-high = <75 150 237 450 500>;
52 interrupt-parent = <&spmi_bus>; 67 interrupt-parent = <&spmi_bus>;
53 interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, 68 interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
54 <0x1 0xf0 0x1 IRQ_TYPE_NONE>, 69 <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index 8633524b1961..f834a639b350 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -12,9 +12,16 @@
12#include <sound/pcm.h> 12#include <sound/pcm.h>
13#include <sound/pcm_params.h> 13#include <sound/pcm_params.h>
14#include <sound/tlv.h> 14#include <sound/tlv.h>
15#include <sound/jack.h>
15 16
16#define CDC_D_REVISION1 (0xf000) 17#define CDC_D_REVISION1 (0xf000)
17#define CDC_D_PERPH_SUBTYPE (0xf005) 18#define CDC_D_PERPH_SUBTYPE (0xf005)
19#define CDC_D_INT_EN_SET (0x015)
20#define CDC_D_INT_EN_CLR (0x016)
21#define MBHC_SWITCH_INT BIT(7)
22#define MBHC_MIC_ELECTRICAL_INS_REM_DET BIT(6)
23#define MBHC_BUTTON_PRESS_DET BIT(5)
24#define MBHC_BUTTON_RELEASE_DET BIT(4)
18#define CDC_D_CDC_RST_CTL (0xf046) 25#define CDC_D_CDC_RST_CTL (0xf046)
19#define RST_CTL_DIG_SW_RST_N_MASK BIT(7) 26#define RST_CTL_DIG_SW_RST_N_MASK BIT(7)
20#define RST_CTL_DIG_SW_RST_N_RESET 0 27#define RST_CTL_DIG_SW_RST_N_RESET 0
@@ -37,6 +44,8 @@
37#define DIG_CLK_CTL_RXD1_CLK_EN BIT(0) 44#define DIG_CLK_CTL_RXD1_CLK_EN BIT(0)
38#define DIG_CLK_CTL_RXD2_CLK_EN BIT(1) 45#define DIG_CLK_CTL_RXD2_CLK_EN BIT(1)
39#define DIG_CLK_CTL_RXD3_CLK_EN BIT(2) 46#define DIG_CLK_CTL_RXD3_CLK_EN BIT(2)
47#define DIG_CLK_CTL_D_MBHC_CLK_EN_MASK BIT(3)
48#define DIG_CLK_CTL_D_MBHC_CLK_EN BIT(3)
40#define DIG_CLK_CTL_TXD_CLK_EN BIT(4) 49#define DIG_CLK_CTL_TXD_CLK_EN BIT(4)
41#define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6) 50#define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6)
42#define DIG_CLK_CTL_NCP_CLK_EN BIT(6) 51#define DIG_CLK_CTL_NCP_CLK_EN BIT(6)
@@ -132,8 +141,51 @@
132#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0 141#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0
133 142
134#define CDC_A_MICB_2_EN (0xf144) 143#define CDC_A_MICB_2_EN (0xf144)
144#define CDC_A_MICB_2_EN_ENABLE BIT(7)
145#define CDC_A_MICB_2_PULL_DOWN_EN_MASK BIT(5)
146#define CDC_A_MICB_2_PULL_DOWN_EN BIT(5)
135#define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145) 147#define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145)
136#define CDC_A_MASTER_BIAS_CTL (0xf146) 148#define CDC_A_MASTER_BIAS_CTL (0xf146)
149#define CDC_A_MBHC_DET_CTL_1 (0xf147)
150#define CDC_A_MBHC_DET_CTL_L_DET_EN BIT(7)
151#define CDC_A_MBHC_DET_CTL_GND_DET_EN BIT(6)
152#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION BIT(5)
153#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_REMOVAL (0)
154#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK BIT(5)
155#define CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT (5)
156#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO BIT(4)
157#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MANUAL BIT(3)
158#define CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_MASK GENMASK(4, 3)
159#define CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN BIT(2)
160#define CDC_A_MBHC_DET_CTL_2 (0xf150)
161#define CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 (BIT(7) | BIT(6))
162#define CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD BIT(5)
163#define CDC_A_PLUG_TYPE_MASK GENMASK(4, 3)
164#define CDC_A_HPHL_PLUG_TYPE_NO BIT(4)
165#define CDC_A_GND_PLUG_TYPE_NO BIT(3)
166#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN_MASK BIT(0)
167#define CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN BIT(0)
168#define CDC_A_MBHC_FSM_CTL (0xf151)
169#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN BIT(7)
170#define CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK BIT(7)
171#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA (0x3 << 4)
172#define CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK GENMASK(6, 4)
173#define CDC_A_MBHC_DBNC_TIMER (0xf152)
174#define CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS BIT(3)
175#define CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS (0x9 << 4)
176#define CDC_A_MBHC_BTN0_ZDET_CTL_0 (0xf153)
177#define CDC_A_MBHC_BTN1_ZDET_CTL_1 (0xf154)
178#define CDC_A_MBHC_BTN2_ZDET_CTL_2 (0xf155)
179#define CDC_A_MBHC_BTN3_CTL (0xf156)
180#define CDC_A_MBHC_BTN4_CTL (0xf157)
181#define CDC_A_MBHC_BTN_VREF_FINE_SHIFT (2)
182#define CDC_A_MBHC_BTN_VREF_FINE_MASK GENMASK(4, 2)
183#define CDC_A_MBHC_BTN_VREF_COARSE_MASK GENMASK(7, 5)
184#define CDC_A_MBHC_BTN_VREF_COARSE_SHIFT (5)
185#define CDC_A_MBHC_BTN_VREF_MASK (CDC_A_MBHC_BTN_VREF_COARSE_MASK | \
186 CDC_A_MBHC_BTN_VREF_FINE_MASK)
187#define CDC_A_MBHC_RESULT_1 (0xf158)
188#define CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK GENMASK(4, 0)
137#define CDC_A_TX_1_EN (0xf160) 189#define CDC_A_TX_1_EN (0xf160)
138#define CDC_A_TX_2_EN (0xf161) 190#define CDC_A_TX_2_EN (0xf161)
139#define CDC_A_TX_1_2_TEST_CTL_1 (0xf162) 191#define CDC_A_TX_1_2_TEST_CTL_1 (0xf162)
@@ -217,16 +269,34 @@
217#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 269#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
218 SNDRV_PCM_FMTBIT_S24_LE) 270 SNDRV_PCM_FMTBIT_S24_LE)
219 271
272static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
273 SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
274static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
275
220static const char * const supply_names[] = { 276static const char * const supply_names[] = {
221 "vdd-cdc-io", 277 "vdd-cdc-io",
222 "vdd-cdc-tx-rx-cx", 278 "vdd-cdc-tx-rx-cx",
223}; 279};
224 280
281#define MBHC_MAX_BUTTONS (5)
282
225struct pm8916_wcd_analog_priv { 283struct pm8916_wcd_analog_priv {
226 u16 pmic_rev; 284 u16 pmic_rev;
227 u16 codec_version; 285 u16 codec_version;
286 bool mbhc_btn_enabled;
287 /* special event to detect accessory type */
288 bool mbhc_btn0_pressed;
289 bool detect_accessory_type;
228 struct clk *mclk; 290 struct clk *mclk;
291 struct snd_soc_codec *codec;
229 struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; 292 struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
293 struct snd_soc_jack *jack;
294 bool hphl_jack_type_normally_open;
295 bool gnd_jack_type_normally_open;
296 /* Voltage threshold when internal current source of 100uA is used */
297 u32 vref_btn_cs[MBHC_MAX_BUTTONS];
298 /* Voltage threshold when microphone bias is ON */
299 u32 vref_btn_micb[MBHC_MAX_BUTTONS];
230 unsigned int micbias1_cap_mode; 300 unsigned int micbias1_cap_mode;
231 unsigned int micbias2_cap_mode; 301 unsigned int micbias2_cap_mode;
232 unsigned int micbias_mv; 302 unsigned int micbias_mv;
@@ -373,6 +443,97 @@ static int pm8916_wcd_analog_enable_micbias_int1(struct
373 wcd->micbias1_cap_mode); 443 wcd->micbias1_cap_mode);
374} 444}
375 445
446static void pm8916_wcd_setup_mbhc(struct pm8916_wcd_analog_priv *wcd)
447{
448 struct snd_soc_codec *codec = wcd->codec;
449 u32 plug_type = 0;
450 u32 int_en_mask;
451
452 snd_soc_write(codec, CDC_A_MBHC_DET_CTL_1,
453 CDC_A_MBHC_DET_CTL_L_DET_EN |
454 CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_INSERTION |
455 CDC_A_MBHC_DET_CTL_MIC_CLAMP_CTL_AUTO |
456 CDC_A_MBHC_DET_CTL_MBHC_BIAS_EN);
457
458 if (wcd->hphl_jack_type_normally_open)
459 plug_type |= CDC_A_HPHL_PLUG_TYPE_NO;
460
461 if (wcd->gnd_jack_type_normally_open)
462 plug_type |= CDC_A_GND_PLUG_TYPE_NO;
463
464 snd_soc_write(codec, CDC_A_MBHC_DET_CTL_2,
465 CDC_A_MBHC_DET_CTL_HS_L_DET_PULL_UP_CTRL_I_3P0 |
466 CDC_A_MBHC_DET_CTL_HS_L_DET_COMPA_CTRL_V0P9_VDD |
467 plug_type |
468 CDC_A_MBHC_DET_CTL_HPHL_100K_TO_GND_EN);
469
470
471 snd_soc_write(codec, CDC_A_MBHC_DBNC_TIMER,
472 CDC_A_MBHC_DBNC_TIMER_INSREM_DBNC_T_256_MS |
473 CDC_A_MBHC_DBNC_TIMER_BTN_DBNC_T_16MS);
474
475 /* enable MBHC clock */
476 snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
477 DIG_CLK_CTL_D_MBHC_CLK_EN_MASK,
478 DIG_CLK_CTL_D_MBHC_CLK_EN);
479
480 int_en_mask = MBHC_SWITCH_INT;
481 if (wcd->mbhc_btn_enabled)
482 int_en_mask |= MBHC_BUTTON_PRESS_DET | MBHC_BUTTON_RELEASE_DET;
483
484 snd_soc_update_bits(codec, CDC_D_INT_EN_CLR, int_en_mask, 0);
485 snd_soc_update_bits(codec, CDC_D_INT_EN_SET, int_en_mask, int_en_mask);
486 wcd->mbhc_btn0_pressed = false;
487 wcd->detect_accessory_type = true;
488}
489
490static int pm8916_mbhc_configure_bias(struct pm8916_wcd_analog_priv *priv,
491 bool micbias2_enabled)
492{
493 struct snd_soc_codec *codec = priv->codec;
494 u32 coarse, fine, reg_val, reg_addr;
495 int *vrefs, i;
496
497 if (!micbias2_enabled) { /* use internal 100uA Current source */
498 /* Enable internal 2.2k Internal Rbias Resistor */
499 snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
500 MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
501 MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
502 /* Remove pull down on MIC BIAS2 */
503 snd_soc_update_bits(codec, CDC_A_MICB_2_EN,
504 CDC_A_MICB_2_PULL_DOWN_EN_MASK,
505 0);
506 /* enable 100uA internal current source */
507 snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
508 CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_MASK,
509 CDC_A_MBHC_FSM_CTL_BTN_ISRC_CTRL_I_100UA);
510 }
511 snd_soc_update_bits(codec, CDC_A_MBHC_FSM_CTL,
512 CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN_MASK,
513 CDC_A_MBHC_FSM_CTL_MBHC_FSM_EN);
514
515 if (micbias2_enabled)
516 vrefs = &priv->vref_btn_micb[0];
517 else
518 vrefs = &priv->vref_btn_cs[0];
519
520 /* program vref ranges for all the buttons */
521 reg_addr = CDC_A_MBHC_BTN0_ZDET_CTL_0;
522 for (i = 0; i < MBHC_MAX_BUTTONS; i++) {
523 /* split mv in to coarse parts of 100mv & fine parts of 12mv */
524 coarse = (vrefs[i] / 100);
525 fine = ((vrefs[i] % 100) / 12);
526 reg_val = (coarse << CDC_A_MBHC_BTN_VREF_COARSE_SHIFT) |
527 (fine << CDC_A_MBHC_BTN_VREF_FINE_SHIFT);
528 snd_soc_update_bits(codec, reg_addr,
529 CDC_A_MBHC_BTN_VREF_MASK,
530 reg_val);
531 reg_addr++;
532 }
533
534 return 0;
535}
536
376static int pm8916_wcd_analog_enable_micbias_int2(struct 537static int pm8916_wcd_analog_enable_micbias_int2(struct
377 snd_soc_dapm_widget 538 snd_soc_dapm_widget
378 *w, struct snd_kcontrol 539 *w, struct snd_kcontrol
@@ -381,6 +542,15 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct
381 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 542 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
382 struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); 543 struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
383 544
545 switch (event) {
546 case SND_SOC_DAPM_POST_PMU:
547 pm8916_mbhc_configure_bias(wcd, true);
548 break;
549 case SND_SOC_DAPM_POST_PMD:
550 pm8916_mbhc_configure_bias(wcd, false);
551 break;
552 }
553
384 return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, 554 return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
385 wcd->micbias2_cap_mode); 555 wcd->micbias2_cap_mode);
386} 556}
@@ -548,9 +718,14 @@ static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
548 snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg, 718 snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
549 wcd_reg_defaults_2_0[reg].def); 719 wcd_reg_defaults_2_0[reg].def);
550 720
721 priv->codec = codec;
722
551 snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL, 723 snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
552 RST_CTL_DIG_SW_RST_N_MASK, 724 RST_CTL_DIG_SW_RST_N_MASK,
553 RST_CTL_DIG_SW_RST_N_REMOVE_RESET); 725 RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
726
727 pm8916_wcd_setup_mbhc(priv);
728
554 return 0; 729 return 0;
555} 730}
556 731
@@ -749,11 +924,130 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
749 SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0), 924 SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
750}; 925};
751 926
927static int pm8916_wcd_analog_set_jack(struct snd_soc_codec *codec,
928 struct snd_soc_jack *jack,
929 void *data)
930{
931 struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
932
933 wcd->jack = jack;
934
935 return 0;
936}
937
752static struct regmap *pm8916_get_regmap(struct device *dev) 938static struct regmap *pm8916_get_regmap(struct device *dev)
753{ 939{
754 return dev_get_regmap(dev->parent, NULL); 940 return dev_get_regmap(dev->parent, NULL);
755} 941}
756 942
943static irqreturn_t mbhc_btn_release_irq_handler(int irq, void *arg)
944{
945 struct pm8916_wcd_analog_priv *priv = arg;
946
947 if (priv->detect_accessory_type) {
948 struct snd_soc_codec *codec = priv->codec;
949 u32 val = snd_soc_read(codec, CDC_A_MBHC_RESULT_1);
950
951 /* check if its BTN0 thats released */
952 if ((val >= 0) && !(val & CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK))
953 priv->mbhc_btn0_pressed = false;
954
955 } else {
956 snd_soc_jack_report(priv->jack, 0, btn_mask);
957 }
958
959 return IRQ_HANDLED;
960}
961
962static irqreturn_t mbhc_btn_press_irq_handler(int irq, void *arg)
963{
964 struct pm8916_wcd_analog_priv *priv = arg;
965 struct snd_soc_codec *codec = priv->codec;
966 u32 btn_result;
967
968 btn_result = snd_soc_read(codec, CDC_A_MBHC_RESULT_1) &
969 CDC_A_MBHC_RESULT_1_BTN_RESULT_MASK;
970
971 switch (btn_result) {
972 case 0xf:
973 snd_soc_jack_report(priv->jack, SND_JACK_BTN_4, btn_mask);
974 break;
975 case 0x7:
976 snd_soc_jack_report(priv->jack, SND_JACK_BTN_3, btn_mask);
977 break;
978 case 0x3:
979 snd_soc_jack_report(priv->jack, SND_JACK_BTN_2, btn_mask);
980 break;
981 case 0x1:
982 snd_soc_jack_report(priv->jack, SND_JACK_BTN_1, btn_mask);
983 break;
984 case 0x0:
985 /* handle BTN_0 specially for type detection */
986 if (priv->detect_accessory_type)
987 priv->mbhc_btn0_pressed = true;
988 else
989 snd_soc_jack_report(priv->jack,
990 SND_JACK_BTN_0, btn_mask);
991 break;
992 default:
993 dev_err(codec->dev,
994 "Unexpected button press result (%x)", btn_result);
995 break;
996 }
997
998 return IRQ_HANDLED;
999}
1000
1001
1002static irqreturn_t pm8916_mbhc_switch_irq_handler(int irq, void *arg)
1003{
1004 struct pm8916_wcd_analog_priv *priv = arg;
1005 struct snd_soc_codec *codec = priv->codec;
1006 bool ins = false;
1007
1008 if (snd_soc_read(codec, CDC_A_MBHC_DET_CTL_1) &
1009 CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK)
1010 ins = true;
1011
1012 /* Set the detection type appropriately */
1013 snd_soc_update_bits(codec, CDC_A_MBHC_DET_CTL_1,
1014 CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_MASK,
1015 (!ins << CDC_A_MBHC_DET_CTL_MECH_DET_TYPE_SHIFT));
1016
1017
1018 if (ins) { /* hs insertion */
1019 bool micbias_enabled = false;
1020
1021 if (snd_soc_read(codec, CDC_A_MICB_2_EN) &
1022 CDC_A_MICB_2_EN_ENABLE)
1023 micbias_enabled = true;
1024
1025 pm8916_mbhc_configure_bias(priv, micbias_enabled);
1026
1027 /*
1028 * if only a btn0 press event is receive just before
1029 * insert event then its a 3 pole headphone else if
1030 * both press and release event received then its
1031 * a headset.
1032 */
1033 if (priv->mbhc_btn0_pressed)
1034 snd_soc_jack_report(priv->jack,
1035 SND_JACK_HEADPHONE, hs_jack_mask);
1036 else
1037 snd_soc_jack_report(priv->jack,
1038 SND_JACK_HEADSET, hs_jack_mask);
1039
1040 priv->detect_accessory_type = false;
1041
1042 } else { /* removal */
1043 snd_soc_jack_report(priv->jack, 0, hs_jack_mask);
1044 priv->detect_accessory_type = true;
1045 priv->mbhc_btn0_pressed = false;
1046 }
1047
1048 return IRQ_HANDLED;
1049}
1050
757static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { 1051static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
758 [0] = { 1052 [0] = {
759 .name = "pm8916_wcd_analog_pdm_rx", 1053 .name = "pm8916_wcd_analog_pdm_rx",
@@ -782,6 +1076,7 @@ static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
782static const struct snd_soc_codec_driver pm8916_wcd_analog = { 1076static const struct snd_soc_codec_driver pm8916_wcd_analog = {
783 .probe = pm8916_wcd_analog_probe, 1077 .probe = pm8916_wcd_analog_probe,
784 .remove = pm8916_wcd_analog_remove, 1078 .remove = pm8916_wcd_analog_remove,
1079 .set_jack = pm8916_wcd_analog_set_jack,
785 .get_regmap = pm8916_get_regmap, 1080 .get_regmap = pm8916_get_regmap,
786 .component_driver = { 1081 .component_driver = {
787 .controls = pm8916_wcd_analog_snd_controls, 1082 .controls = pm8916_wcd_analog_snd_controls,
@@ -796,6 +1091,7 @@ static const struct snd_soc_codec_driver pm8916_wcd_analog = {
796static int pm8916_wcd_analog_parse_dt(struct device *dev, 1091static int pm8916_wcd_analog_parse_dt(struct device *dev,
797 struct pm8916_wcd_analog_priv *priv) 1092 struct pm8916_wcd_analog_priv *priv)
798{ 1093{
1094 int rval;
799 1095
800 if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap")) 1096 if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
801 priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP; 1097 priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
@@ -810,6 +1106,39 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev,
810 of_property_read_u32(dev->of_node, "qcom,micbias-lvl", 1106 of_property_read_u32(dev->of_node, "qcom,micbias-lvl",
811 &priv->micbias_mv); 1107 &priv->micbias_mv);
812 1108
1109 if (of_property_read_bool(dev->of_node,
1110 "qcom,hphl-jack-type-normally-open"))
1111 priv->hphl_jack_type_normally_open = true;
1112 else
1113 priv->hphl_jack_type_normally_open = false;
1114
1115 if (of_property_read_bool(dev->of_node,
1116 "qcom,gnd-jack-type-normally-open"))
1117 priv->gnd_jack_type_normally_open = true;
1118 else
1119 priv->gnd_jack_type_normally_open = false;
1120
1121 priv->mbhc_btn_enabled = true;
1122 rval = of_property_read_u32_array(dev->of_node,
1123 "qcom,mbhc-vthreshold-low",
1124 &priv->vref_btn_cs[0],
1125 MBHC_MAX_BUTTONS);
1126 if (rval < 0) {
1127 priv->mbhc_btn_enabled = false;
1128 } else {
1129 rval = of_property_read_u32_array(dev->of_node,
1130 "qcom,mbhc-vthreshold-high",
1131 &priv->vref_btn_micb[0],
1132 MBHC_MAX_BUTTONS);
1133 if (rval < 0)
1134 priv->mbhc_btn_enabled = false;
1135 }
1136
1137 if (!priv->mbhc_btn_enabled)
1138 dev_err(dev,
1139 "DT property missing, MBHC btn detection disabled\n");
1140
1141
813 return 0; 1142 return 0;
814} 1143}
815 1144
@@ -817,7 +1146,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
817{ 1146{
818 struct pm8916_wcd_analog_priv *priv; 1147 struct pm8916_wcd_analog_priv *priv;
819 struct device *dev = &pdev->dev; 1148 struct device *dev = &pdev->dev;
820 int ret, i; 1149 int ret, i, irq;
821 1150
822 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 1151 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
823 if (!priv) 1152 if (!priv)
@@ -849,6 +1178,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
849 return ret; 1178 return ret;
850 } 1179 }
851 1180
1181 irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
1182 if (irq < 0) {
1183 dev_err(dev, "failed to get mbhc switch irq\n");
1184 return irq;
1185 }
1186
1187 ret = devm_request_irq(dev, irq, pm8916_mbhc_switch_irq_handler,
1188 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
1189 IRQF_ONESHOT,
1190 "mbhc switch irq", priv);
1191 if (ret)
1192 dev_err(dev, "cannot request mbhc switch irq\n");
1193
1194 if (priv->mbhc_btn_enabled) {
1195 irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
1196 if (irq < 0) {
1197 dev_err(dev, "failed to get button press irq\n");
1198 return irq;
1199 }
1200
1201 ret = devm_request_irq(dev, irq, mbhc_btn_press_irq_handler,
1202 IRQF_TRIGGER_RISING |
1203 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
1204 "mbhc btn press irq", priv);
1205 if (ret)
1206 dev_err(dev, "cannot request mbhc button press irq\n");
1207
1208 irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
1209 if (irq < 0) {
1210 dev_err(dev, "failed to get button release irq\n");
1211 return irq;
1212 }
1213
1214 ret = devm_request_irq(dev, irq, mbhc_btn_release_irq_handler,
1215 IRQF_TRIGGER_RISING |
1216 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
1217 "mbhc btn release irq", priv);
1218 if (ret)
1219 dev_err(dev, "cannot request mbhc button release irq\n");
1220
1221 }
1222
852 dev_set_drvdata(dev, priv); 1223 dev_set_drvdata(dev, priv);
853 1224
854 return snd_soc_register_codec(dev, &pm8916_wcd_analog, 1225 return snd_soc_register_codec(dev, &pm8916_wcd_analog,