diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt | 17 | ||||
-rw-r--r-- | sound/soc/codecs/msm8916-wcd-analog.c | 373 |
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 | |||
35 | Optional Properties: | 34 | Optional 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 | ||
272 | static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
273 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4; | ||
274 | static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET; | ||
275 | |||
220 | static const char * const supply_names[] = { | 276 | static 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 | |||
225 | struct pm8916_wcd_analog_priv { | 283 | struct 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 | ||
446 | static 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 | |||
490 | static 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 | |||
376 | static int pm8916_wcd_analog_enable_micbias_int2(struct | 537 | static 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 | ||
927 | static 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 | |||
752 | static struct regmap *pm8916_get_regmap(struct device *dev) | 938 | static 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 | ||
943 | static 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 | |||
962 | static 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 | |||
1002 | static 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 | |||
757 | static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { | 1051 | static 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[] = { | |||
782 | static const struct snd_soc_codec_driver pm8916_wcd_analog = { | 1076 | static 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 = { | |||
796 | static int pm8916_wcd_analog_parse_dt(struct device *dev, | 1091 | static 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, |