1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. |
3 | |
4 | #include <linux/module.h> |
5 | #include <linux/slab.h> |
6 | #include <linux/platform_device.h> |
7 | #include <linux/device.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/gpio/consumer.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/pm_runtime.h> |
12 | #include <linux/component.h> |
13 | #include <sound/tlv.h> |
14 | #include <linux/of_gpio.h> |
15 | #include <linux/of.h> |
16 | #include <sound/jack.h> |
17 | #include <sound/pcm.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <linux/regmap.h> |
20 | #include <sound/soc.h> |
21 | #include <sound/soc-dapm.h> |
22 | #include <linux/regulator/consumer.h> |
23 | |
24 | #include "wcd-clsh-v2.h" |
25 | #include "wcd-mbhc-v2.h" |
26 | #include "wcd938x.h" |
27 | |
28 | #define WCD938X_MAX_MICBIAS (4) |
29 | #define WCD938X_MAX_SUPPLY (4) |
30 | #define WCD938X_MBHC_MAX_BUTTONS (8) |
31 | #define TX_ADC_MAX (4) |
32 | #define WCD938X_TX_MAX_SWR_PORTS (5) |
33 | |
34 | #define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ |
35 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ |
36 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) |
37 | /* Fractional Rates */ |
38 | #define WCD938X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ |
39 | SNDRV_PCM_RATE_176400) |
40 | #define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ |
41 | SNDRV_PCM_FMTBIT_S24_LE) |
42 | /* Convert from vout ctl to micbias voltage in mV */ |
43 | #define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) |
44 | #define SWR_CLK_RATE_0P6MHZ (600000) |
45 | #define SWR_CLK_RATE_1P2MHZ (1200000) |
46 | #define SWR_CLK_RATE_2P4MHZ (2400000) |
47 | #define SWR_CLK_RATE_4P8MHZ (4800000) |
48 | #define SWR_CLK_RATE_9P6MHZ (9600000) |
49 | #define SWR_CLK_RATE_11P2896MHZ (1128960) |
50 | |
51 | #define WCD938X_DRV_NAME "wcd938x_codec" |
52 | #define WCD938X_VERSION_1_0 (1) |
53 | #define EAR_RX_PATH_AUX (1) |
54 | |
55 | #define ADC_MODE_VAL_HIFI 0x01 |
56 | #define ADC_MODE_VAL_LO_HIF 0x02 |
57 | #define ADC_MODE_VAL_NORMAL 0x03 |
58 | #define ADC_MODE_VAL_LP 0x05 |
59 | #define ADC_MODE_VAL_ULP1 0x09 |
60 | #define ADC_MODE_VAL_ULP2 0x0B |
61 | |
62 | /* Z value defined in milliohm */ |
63 | #define WCD938X_ZDET_VAL_32 (32000) |
64 | #define WCD938X_ZDET_VAL_400 (400000) |
65 | #define WCD938X_ZDET_VAL_1200 (1200000) |
66 | #define WCD938X_ZDET_VAL_100K (100000000) |
67 | /* Z floating defined in ohms */ |
68 | #define WCD938X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) |
69 | #define WCD938X_ZDET_NUM_MEASUREMENTS (900) |
70 | #define WCD938X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) |
71 | #define WCD938X_MBHC_GET_X1(x) (x & 0x3FFF) |
72 | /* Z value compared in milliOhm */ |
73 | #define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) |
74 | #define WCD938X_MBHC_ZDET_CONST (86 * 16384) |
75 | #define WCD938X_MBHC_MOISTURE_RREF R_24_KOHM |
76 | #define WCD_MBHC_HS_V_MAX 1600 |
77 | |
78 | #define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ |
79 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
80 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
81 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
82 | .tlv.p = (tlv_array), \ |
83 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
84 | .put = wcd938x_ear_pa_put_gain, \ |
85 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } |
86 | |
87 | enum { |
88 | WCD9380 = 0, |
89 | WCD9385 = 5, |
90 | }; |
91 | |
92 | enum { |
93 | TX_HDR12 = 0, |
94 | TX_HDR34, |
95 | TX_HDR_MAX, |
96 | }; |
97 | |
98 | enum { |
99 | WCD_RX1, |
100 | WCD_RX2, |
101 | WCD_RX3 |
102 | }; |
103 | |
104 | enum { |
105 | /* INTR_CTRL_INT_MASK_0 */ |
106 | WCD938X_IRQ_MBHC_BUTTON_PRESS_DET = 0, |
107 | WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, |
108 | WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, |
109 | WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, |
110 | WCD938X_IRQ_MBHC_SW_DET, |
111 | WCD938X_IRQ_HPHR_OCP_INT, |
112 | WCD938X_IRQ_HPHR_CNP_INT, |
113 | WCD938X_IRQ_HPHL_OCP_INT, |
114 | |
115 | /* INTR_CTRL_INT_MASK_1 */ |
116 | WCD938X_IRQ_HPHL_CNP_INT, |
117 | WCD938X_IRQ_EAR_CNP_INT, |
118 | WCD938X_IRQ_EAR_SCD_INT, |
119 | WCD938X_IRQ_AUX_CNP_INT, |
120 | WCD938X_IRQ_AUX_SCD_INT, |
121 | WCD938X_IRQ_HPHL_PDM_WD_INT, |
122 | WCD938X_IRQ_HPHR_PDM_WD_INT, |
123 | WCD938X_IRQ_AUX_PDM_WD_INT, |
124 | |
125 | /* INTR_CTRL_INT_MASK_2 */ |
126 | WCD938X_IRQ_LDORT_SCD_INT, |
127 | WCD938X_IRQ_MBHC_MOISTURE_INT, |
128 | WCD938X_IRQ_HPHL_SURGE_DET_INT, |
129 | WCD938X_IRQ_HPHR_SURGE_DET_INT, |
130 | WCD938X_NUM_IRQS, |
131 | }; |
132 | |
133 | enum { |
134 | WCD_ADC1 = 0, |
135 | WCD_ADC2, |
136 | WCD_ADC3, |
137 | WCD_ADC4, |
138 | ALLOW_BUCK_DISABLE, |
139 | HPH_COMP_DELAY, |
140 | HPH_PA_DELAY, |
141 | AMIC2_BCS_ENABLE, |
142 | WCD_SUPPLIES_LPM_MODE, |
143 | }; |
144 | |
145 | enum { |
146 | ADC_MODE_INVALID = 0, |
147 | ADC_MODE_HIFI, |
148 | ADC_MODE_LO_HIF, |
149 | ADC_MODE_NORMAL, |
150 | ADC_MODE_LP, |
151 | ADC_MODE_ULP1, |
152 | ADC_MODE_ULP2, |
153 | }; |
154 | |
155 | enum { |
156 | AIF1_PB = 0, |
157 | AIF1_CAP, |
158 | NUM_CODEC_DAIS, |
159 | }; |
160 | |
161 | static u8 tx_mode_bit[] = { |
162 | [ADC_MODE_INVALID] = 0x00, |
163 | [ADC_MODE_HIFI] = 0x01, |
164 | [ADC_MODE_LO_HIF] = 0x02, |
165 | [ADC_MODE_NORMAL] = 0x04, |
166 | [ADC_MODE_LP] = 0x08, |
167 | [ADC_MODE_ULP1] = 0x10, |
168 | [ADC_MODE_ULP2] = 0x20, |
169 | }; |
170 | |
171 | struct wcd938x_priv { |
172 | struct sdw_slave *tx_sdw_dev; |
173 | struct wcd938x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; |
174 | struct device *txdev; |
175 | struct device *rxdev; |
176 | struct device_node *rxnode, *txnode; |
177 | struct regmap *regmap; |
178 | struct mutex micb_lock; |
179 | /* mbhc module */ |
180 | struct wcd_mbhc *wcd_mbhc; |
181 | struct wcd_mbhc_config mbhc_cfg; |
182 | struct wcd_mbhc_intr intr_ids; |
183 | struct wcd_clsh_ctrl *clsh_info; |
184 | struct irq_domain *virq; |
185 | struct regmap_irq_chip *wcd_regmap_irq_chip; |
186 | struct regmap_irq_chip_data *irq_chip; |
187 | struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY]; |
188 | struct snd_soc_jack *jack; |
189 | unsigned long status_mask; |
190 | s32 micb_ref[WCD938X_MAX_MICBIAS]; |
191 | s32 pullup_ref[WCD938X_MAX_MICBIAS]; |
192 | u32 hph_mode; |
193 | u32 tx_mode[TX_ADC_MAX]; |
194 | int flyback_cur_det_disable; |
195 | int ear_rx_path; |
196 | int variant; |
197 | int reset_gpio; |
198 | struct gpio_desc *us_euro_gpio; |
199 | u32 micb1_mv; |
200 | u32 micb2_mv; |
201 | u32 micb3_mv; |
202 | u32 micb4_mv; |
203 | int hphr_pdm_wd_int; |
204 | int hphl_pdm_wd_int; |
205 | int aux_pdm_wd_int; |
206 | bool comp1_enable; |
207 | bool comp2_enable; |
208 | bool ldoh; |
209 | bool bcs_dis; |
210 | }; |
211 | |
212 | static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); |
213 | static const DECLARE_TLV_DB_SCALE(line_gain, -3000, 150, 0); |
214 | static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); |
215 | |
216 | struct wcd938x_mbhc_zdet_param { |
217 | u16 ldo_ctl; |
218 | u16 noff; |
219 | u16 nshift; |
220 | u16 btn5; |
221 | u16 btn6; |
222 | u16 btn7; |
223 | }; |
224 | |
225 | static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { |
226 | WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD938X_ANA_MBHC_MECH, 0x80), |
227 | WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD938X_ANA_MBHC_MECH, 0x40), |
228 | WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD938X_ANA_MBHC_MECH, 0x20), |
229 | WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0x30), |
230 | WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD938X_ANA_MBHC_ELECT, 0x08), |
231 | WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F), |
232 | WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD938X_ANA_MBHC_MECH, 0x04), |
233 | WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD938X_ANA_MBHC_MECH, 0x10), |
234 | WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD938X_ANA_MBHC_MECH, 0x08), |
235 | WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD938X_ANA_MBHC_MECH, 0x01), |
236 | WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD938X_ANA_MBHC_ELECT, 0x06), |
237 | WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD938X_ANA_MBHC_ELECT, 0x80), |
238 | WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F), |
239 | WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD938X_MBHC_NEW_CTL_1, 0x03), |
240 | WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD938X_MBHC_NEW_CTL_2, 0x03), |
241 | WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x08), |
242 | WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD938X_ANA_MBHC_RESULT_3, 0x10), |
243 | WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x20), |
244 | WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x80), |
245 | WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x40), |
246 | WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD938X_HPH_OCP_CTL, 0x10), |
247 | WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0x07), |
248 | WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD938X_ANA_MBHC_ELECT, 0x70), |
249 | WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD938X_ANA_MBHC_RESULT_3, 0xFF), |
250 | WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD938X_ANA_MICB2, 0xC0), |
251 | WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD938X_HPH_CNP_WG_TIME, 0xFF), |
252 | WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD938X_ANA_HPH, 0x40), |
253 | WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD938X_ANA_HPH, 0x80), |
254 | WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD938X_ANA_HPH, 0xC0), |
255 | WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD938X_ANA_MBHC_RESULT_3, 0x10), |
256 | WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD938X_MBHC_CTL_BCS, 0x02), |
257 | WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD938X_MBHC_NEW_FSM_STATUS, 0x01), |
258 | WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD938X_MBHC_NEW_CTL_2, 0x70), |
259 | WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD938X_MBHC_NEW_FSM_STATUS, 0x20), |
260 | WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD938X_HPH_PA_CTL2, 0x40), |
261 | WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD938X_HPH_PA_CTL2, 0x10), |
262 | WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD938X_HPH_L_TEST, 0x01), |
263 | WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD938X_HPH_R_TEST, 0x01), |
264 | WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD938X_DIGITAL_INTR_STATUS_0, 0x80), |
265 | WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD938X_DIGITAL_INTR_STATUS_0, 0x20), |
266 | WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD938X_MBHC_NEW_CTL_1, 0x08), |
267 | WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD938X_MBHC_NEW_FSM_STATUS, 0x40), |
268 | WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD938X_MBHC_NEW_FSM_STATUS, 0x80), |
269 | WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD938X_MBHC_NEW_ADC_RESULT, 0xFF), |
270 | WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD938X_ANA_MICB2, 0x3F), |
271 | WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD938X_MBHC_NEW_CTL_1, 0x10), |
272 | WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD938X_MBHC_NEW_CTL_1, 0x04), |
273 | WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD938X_ANA_MBHC_ZDET, 0x02), |
274 | }; |
275 | |
276 | static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = { |
277 | REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), |
278 | REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), |
279 | REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), |
280 | REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), |
281 | REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_SW_DET, 0, 0x10), |
282 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_OCP_INT, 0, 0x20), |
283 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_CNP_INT, 0, 0x40), |
284 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_OCP_INT, 0, 0x80), |
285 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_CNP_INT, 1, 0x01), |
286 | REGMAP_IRQ_REG(WCD938X_IRQ_EAR_CNP_INT, 1, 0x02), |
287 | REGMAP_IRQ_REG(WCD938X_IRQ_EAR_SCD_INT, 1, 0x04), |
288 | REGMAP_IRQ_REG(WCD938X_IRQ_AUX_CNP_INT, 1, 0x08), |
289 | REGMAP_IRQ_REG(WCD938X_IRQ_AUX_SCD_INT, 1, 0x10), |
290 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), |
291 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), |
292 | REGMAP_IRQ_REG(WCD938X_IRQ_AUX_PDM_WD_INT, 1, 0x80), |
293 | REGMAP_IRQ_REG(WCD938X_IRQ_LDORT_SCD_INT, 2, 0x01), |
294 | REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), |
295 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), |
296 | REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), |
297 | }; |
298 | |
299 | static struct regmap_irq_chip wcd938x_regmap_irq_chip = { |
300 | .name = "wcd938x" , |
301 | .irqs = wcd938x_irqs, |
302 | .num_irqs = ARRAY_SIZE(wcd938x_irqs), |
303 | .num_regs = 3, |
304 | .status_base = WCD938X_DIGITAL_INTR_STATUS_0, |
305 | .mask_base = WCD938X_DIGITAL_INTR_MASK_0, |
306 | .ack_base = WCD938X_DIGITAL_INTR_CLEAR_0, |
307 | .use_ack = 1, |
308 | .runtime_pm = true, |
309 | .irq_drv_data = NULL, |
310 | }; |
311 | |
312 | static int wcd938x_get_clk_rate(int mode) |
313 | { |
314 | int rate; |
315 | |
316 | switch (mode) { |
317 | case ADC_MODE_ULP2: |
318 | rate = SWR_CLK_RATE_0P6MHZ; |
319 | break; |
320 | case ADC_MODE_ULP1: |
321 | rate = SWR_CLK_RATE_1P2MHZ; |
322 | break; |
323 | case ADC_MODE_LP: |
324 | rate = SWR_CLK_RATE_4P8MHZ; |
325 | break; |
326 | case ADC_MODE_NORMAL: |
327 | case ADC_MODE_LO_HIF: |
328 | case ADC_MODE_HIFI: |
329 | case ADC_MODE_INVALID: |
330 | default: |
331 | rate = SWR_CLK_RATE_9P6MHZ; |
332 | break; |
333 | } |
334 | |
335 | return rate; |
336 | } |
337 | |
338 | static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank) |
339 | { |
340 | u8 mask = (bank ? 0xF0 : 0x0F); |
341 | u8 val = 0; |
342 | |
343 | switch (rate) { |
344 | case SWR_CLK_RATE_0P6MHZ: |
345 | val = (bank ? 0x60 : 0x06); |
346 | break; |
347 | case SWR_CLK_RATE_1P2MHZ: |
348 | val = (bank ? 0x50 : 0x05); |
349 | break; |
350 | case SWR_CLK_RATE_2P4MHZ: |
351 | val = (bank ? 0x30 : 0x03); |
352 | break; |
353 | case SWR_CLK_RATE_4P8MHZ: |
354 | val = (bank ? 0x10 : 0x01); |
355 | break; |
356 | case SWR_CLK_RATE_9P6MHZ: |
357 | default: |
358 | val = 0x00; |
359 | break; |
360 | } |
361 | snd_soc_component_update_bits(component, WCD938X_DIGITAL_SWR_TX_CLK_RATE, |
362 | mask, val); |
363 | |
364 | return 0; |
365 | } |
366 | |
367 | static int wcd938x_io_init(struct wcd938x_priv *wcd938x) |
368 | { |
369 | struct regmap *rm = wcd938x->regmap; |
370 | |
371 | regmap_update_bits(map: rm, WCD938X_SLEEP_CTL, mask: 0x0E, val: 0x0E); |
372 | regmap_update_bits(map: rm, WCD938X_SLEEP_CTL, mask: 0x80, val: 0x80); |
373 | /* 1 msec delay as per HW requirement */ |
374 | usleep_range(min: 1000, max: 1010); |
375 | regmap_update_bits(map: rm, WCD938X_SLEEP_CTL, mask: 0x40, val: 0x40); |
376 | /* 1 msec delay as per HW requirement */ |
377 | usleep_range(min: 1000, max: 1010); |
378 | regmap_update_bits(map: rm, WCD938X_LDORXTX_CONFIG, mask: 0x10, val: 0x00); |
379 | regmap_update_bits(map: rm, WCD938X_BIAS_VBG_FINE_ADJ, |
380 | mask: 0xF0, val: 0x80); |
381 | regmap_update_bits(map: rm, WCD938X_ANA_BIAS, mask: 0x80, val: 0x80); |
382 | regmap_update_bits(map: rm, WCD938X_ANA_BIAS, mask: 0x40, val: 0x40); |
383 | /* 10 msec delay as per HW requirement */ |
384 | usleep_range(min: 10000, max: 10010); |
385 | |
386 | regmap_update_bits(map: rm, WCD938X_ANA_BIAS, mask: 0x40, val: 0x00); |
387 | regmap_update_bits(map: rm, WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, |
388 | mask: 0xF0, val: 0x00); |
389 | regmap_update_bits(map: rm, WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, |
390 | mask: 0x1F, val: 0x15); |
391 | regmap_update_bits(map: rm, WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, |
392 | mask: 0x1F, val: 0x15); |
393 | regmap_update_bits(map: rm, WCD938X_HPH_REFBUFF_UHQA_CTL, |
394 | mask: 0xC0, val: 0x80); |
395 | regmap_update_bits(map: rm, WCD938X_DIGITAL_CDC_DMIC_CTL, |
396 | mask: 0x02, val: 0x02); |
397 | |
398 | regmap_update_bits(map: rm, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, |
399 | mask: 0xFF, val: 0x14); |
400 | regmap_update_bits(map: rm, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, |
401 | mask: 0x1F, val: 0x08); |
402 | |
403 | regmap_update_bits(map: rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_0, mask: 0xFF, val: 0x55); |
404 | regmap_update_bits(map: rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_1, mask: 0xFF, val: 0x44); |
405 | regmap_update_bits(map: rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_2, mask: 0xFF, val: 0x11); |
406 | regmap_update_bits(map: rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_3, mask: 0xFF, val: 0x00); |
407 | regmap_update_bits(map: rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_4, mask: 0xFF, val: 0x00); |
408 | |
409 | /* Set Noise Filter Resistor value */ |
410 | regmap_update_bits(map: rm, WCD938X_MICB1_TEST_CTL_1, mask: 0xE0, val: 0xE0); |
411 | regmap_update_bits(map: rm, WCD938X_MICB2_TEST_CTL_1, mask: 0xE0, val: 0xE0); |
412 | regmap_update_bits(map: rm, WCD938X_MICB3_TEST_CTL_1, mask: 0xE0, val: 0xE0); |
413 | regmap_update_bits(map: rm, WCD938X_MICB4_TEST_CTL_1, mask: 0xE0, val: 0xE0); |
414 | |
415 | regmap_update_bits(map: rm, WCD938X_TX_3_4_TEST_BLK_EN2, mask: 0x01, val: 0x00); |
416 | regmap_update_bits(map: rm, WCD938X_HPH_SURGE_HPHLR_SURGE_EN, mask: 0xC0, val: 0xC0); |
417 | |
418 | return 0; |
419 | |
420 | } |
421 | |
422 | static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info, |
423 | struct sdw_port_config *port_config, |
424 | u8 enable) |
425 | { |
426 | u8 ch_mask, port_num; |
427 | |
428 | port_num = ch_info->port_num; |
429 | ch_mask = ch_info->ch_mask; |
430 | |
431 | port_config->num = port_num; |
432 | |
433 | if (enable) |
434 | port_config->ch_mask |= ch_mask; |
435 | else |
436 | port_config->ch_mask &= ~ch_mask; |
437 | |
438 | return 0; |
439 | } |
440 | |
441 | static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable) |
442 | { |
443 | return wcd938x_sdw_connect_port(ch_info: &wcd->ch_info[ch_id], |
444 | port_config: &wcd->port_config[port_num - 1], |
445 | enable); |
446 | } |
447 | |
448 | static int wcd938x_codec_enable_rxclk(struct snd_soc_dapm_widget *w, |
449 | struct snd_kcontrol *kcontrol, |
450 | int event) |
451 | { |
452 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
453 | |
454 | switch (event) { |
455 | case SND_SOC_DAPM_PRE_PMU: |
456 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
457 | WCD938X_ANA_RX_CLK_EN_MASK, val: 1); |
458 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
459 | WCD938X_RX_BIAS_EN_MASK, val: 1); |
460 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX0_CTL, |
461 | WCD938X_DEM_DITHER_ENABLE_MASK, val: 0); |
462 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX1_CTL, |
463 | WCD938X_DEM_DITHER_ENABLE_MASK, val: 0); |
464 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX2_CTL, |
465 | WCD938X_DEM_DITHER_ENABLE_MASK, val: 0); |
466 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
467 | WCD938X_ANA_RX_DIV2_CLK_EN_MASK, val: 1); |
468 | snd_soc_component_write_field(component, WCD938X_AUX_AUXPA, |
469 | WCD938X_AUXPA_CLK_EN_MASK, val: 1); |
470 | break; |
471 | case SND_SOC_DAPM_POST_PMD: |
472 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
473 | WCD938X_VNEG_EN_MASK, val: 0); |
474 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
475 | WCD938X_VPOS_EN_MASK, val: 0); |
476 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
477 | WCD938X_RX_BIAS_EN_MASK, val: 0); |
478 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
479 | WCD938X_ANA_RX_DIV2_CLK_EN_MASK, val: 0); |
480 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
481 | WCD938X_ANA_RX_CLK_EN_MASK, val: 0); |
482 | break; |
483 | } |
484 | return 0; |
485 | } |
486 | |
487 | static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, |
488 | struct snd_kcontrol *kcontrol, |
489 | int event) |
490 | { |
491 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
492 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
493 | |
494 | switch (event) { |
495 | case SND_SOC_DAPM_PRE_PMU: |
496 | snd_soc_component_write_field(component, |
497 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
498 | WCD938X_RXD0_CLK_EN_MASK, val: 0x01); |
499 | snd_soc_component_write_field(component, |
500 | WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, |
501 | WCD938X_HPHL_RX_EN_MASK, val: 1); |
502 | snd_soc_component_write_field(component, |
503 | WCD938X_HPH_RDAC_CLK_CTL1, |
504 | WCD938X_CHOP_CLK_EN_MASK, val: 0); |
505 | break; |
506 | case SND_SOC_DAPM_POST_PMU: |
507 | snd_soc_component_write_field(component, |
508 | WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, |
509 | WCD938X_HPH_RES_DIV_MASK, val: 0x02); |
510 | if (wcd938x->comp1_enable) { |
511 | snd_soc_component_write_field(component, |
512 | WCD938X_DIGITAL_CDC_COMP_CTL_0, |
513 | WCD938X_HPHL_COMP_EN_MASK, val: 1); |
514 | /* 5msec compander delay as per HW requirement */ |
515 | if (!wcd938x->comp2_enable || (snd_soc_component_read(component, |
516 | WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01)) |
517 | usleep_range(min: 5000, max: 5010); |
518 | snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, |
519 | WCD938X_AUTOCHOP_TIMER_EN, val: 0); |
520 | } else { |
521 | snd_soc_component_write_field(component, |
522 | WCD938X_DIGITAL_CDC_COMP_CTL_0, |
523 | WCD938X_HPHL_COMP_EN_MASK, val: 0); |
524 | snd_soc_component_write_field(component, |
525 | WCD938X_HPH_L_EN, |
526 | WCD938X_GAIN_SRC_SEL_MASK, |
527 | WCD938X_GAIN_SRC_SEL_REGISTER); |
528 | |
529 | } |
530 | break; |
531 | case SND_SOC_DAPM_POST_PMD: |
532 | snd_soc_component_write_field(component, |
533 | WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, |
534 | WCD938X_HPH_RES_DIV_MASK, val: 0x1); |
535 | break; |
536 | } |
537 | |
538 | return 0; |
539 | } |
540 | |
541 | static int wcd938x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, |
542 | struct snd_kcontrol *kcontrol, |
543 | int event) |
544 | { |
545 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
546 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
547 | |
548 | switch (event) { |
549 | case SND_SOC_DAPM_PRE_PMU: |
550 | snd_soc_component_write_field(component, |
551 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
552 | WCD938X_RXD1_CLK_EN_MASK, val: 1); |
553 | snd_soc_component_write_field(component, |
554 | WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, |
555 | WCD938X_HPHR_RX_EN_MASK, val: 1); |
556 | snd_soc_component_write_field(component, |
557 | WCD938X_HPH_RDAC_CLK_CTL1, |
558 | WCD938X_CHOP_CLK_EN_MASK, val: 0); |
559 | break; |
560 | case SND_SOC_DAPM_POST_PMU: |
561 | snd_soc_component_write_field(component, |
562 | WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, |
563 | WCD938X_HPH_RES_DIV_MASK, val: 0x02); |
564 | if (wcd938x->comp2_enable) { |
565 | snd_soc_component_write_field(component, |
566 | WCD938X_DIGITAL_CDC_COMP_CTL_0, |
567 | WCD938X_HPHR_COMP_EN_MASK, val: 1); |
568 | /* 5msec compander delay as per HW requirement */ |
569 | if (!wcd938x->comp1_enable || |
570 | (snd_soc_component_read(component, |
571 | WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x02)) |
572 | usleep_range(min: 5000, max: 5010); |
573 | snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, |
574 | WCD938X_AUTOCHOP_TIMER_EN, val: 0); |
575 | } else { |
576 | snd_soc_component_write_field(component, |
577 | WCD938X_DIGITAL_CDC_COMP_CTL_0, |
578 | WCD938X_HPHR_COMP_EN_MASK, val: 0); |
579 | snd_soc_component_write_field(component, |
580 | WCD938X_HPH_R_EN, |
581 | WCD938X_GAIN_SRC_SEL_MASK, |
582 | WCD938X_GAIN_SRC_SEL_REGISTER); |
583 | } |
584 | break; |
585 | case SND_SOC_DAPM_POST_PMD: |
586 | snd_soc_component_write_field(component, |
587 | WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, |
588 | WCD938X_HPH_RES_DIV_MASK, val: 0x01); |
589 | break; |
590 | } |
591 | |
592 | return 0; |
593 | } |
594 | |
595 | static int wcd938x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, |
596 | struct snd_kcontrol *kcontrol, |
597 | int event) |
598 | { |
599 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
600 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
601 | |
602 | switch (event) { |
603 | case SND_SOC_DAPM_PRE_PMU: |
604 | wcd938x->ear_rx_path = |
605 | snd_soc_component_read( |
606 | component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL); |
607 | if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { |
608 | snd_soc_component_write_field(component, |
609 | WCD938X_EAR_EAR_DAC_CON, |
610 | WCD938X_DAC_SAMPLE_EDGE_SEL_MASK, val: 0); |
611 | snd_soc_component_write_field(component, |
612 | WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, |
613 | WCD938X_AUX_EN_MASK, val: 1); |
614 | snd_soc_component_write_field(component, |
615 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
616 | WCD938X_RXD2_CLK_EN_MASK, val: 1); |
617 | snd_soc_component_write_field(component, |
618 | WCD938X_ANA_EAR_COMPANDER_CTL, |
619 | WCD938X_GAIN_OVRD_REG_MASK, val: 1); |
620 | } else { |
621 | snd_soc_component_write_field(component, |
622 | WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, |
623 | WCD938X_HPHL_RX_EN_MASK, val: 1); |
624 | snd_soc_component_write_field(component, |
625 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
626 | WCD938X_RXD0_CLK_EN_MASK, val: 1); |
627 | if (wcd938x->comp1_enable) |
628 | snd_soc_component_write_field(component, |
629 | WCD938X_DIGITAL_CDC_COMP_CTL_0, |
630 | WCD938X_HPHL_COMP_EN_MASK, val: 1); |
631 | } |
632 | /* 5 msec delay as per HW requirement */ |
633 | usleep_range(min: 5000, max: 5010); |
634 | if (wcd938x->flyback_cur_det_disable == 0) |
635 | snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, |
636 | WCD938X_EN_CUR_DET_MASK, val: 0); |
637 | wcd938x->flyback_cur_det_disable++; |
638 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, |
639 | clsh_event: WCD_CLSH_EVENT_PRE_DAC, |
640 | WCD_CLSH_STATE_EAR, |
641 | mode: wcd938x->hph_mode); |
642 | break; |
643 | case SND_SOC_DAPM_POST_PMD: |
644 | if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { |
645 | snd_soc_component_write_field(component, |
646 | WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, |
647 | WCD938X_AUX_EN_MASK, val: 0); |
648 | snd_soc_component_write_field(component, |
649 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
650 | WCD938X_RXD2_CLK_EN_MASK, val: 0); |
651 | } else { |
652 | snd_soc_component_write_field(component, |
653 | WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, |
654 | WCD938X_HPHL_RX_EN_MASK, val: 0); |
655 | snd_soc_component_write_field(component, |
656 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
657 | WCD938X_RXD0_CLK_EN_MASK, val: 0); |
658 | if (wcd938x->comp1_enable) |
659 | snd_soc_component_write_field(component, |
660 | WCD938X_DIGITAL_CDC_COMP_CTL_0, |
661 | WCD938X_HPHL_COMP_EN_MASK, val: 0); |
662 | } |
663 | snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, |
664 | WCD938X_GAIN_OVRD_REG_MASK, val: 0); |
665 | snd_soc_component_write_field(component, |
666 | WCD938X_EAR_EAR_DAC_CON, |
667 | WCD938X_DAC_SAMPLE_EDGE_SEL_MASK, val: 1); |
668 | break; |
669 | } |
670 | return 0; |
671 | |
672 | } |
673 | |
674 | static int wcd938x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, |
675 | struct snd_kcontrol *kcontrol, |
676 | int event) |
677 | { |
678 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
679 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
680 | |
681 | switch (event) { |
682 | case SND_SOC_DAPM_PRE_PMU: |
683 | snd_soc_component_write_field(component, |
684 | WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
685 | WCD938X_ANA_RX_DIV4_CLK_EN_MASK, val: 1); |
686 | snd_soc_component_write_field(component, |
687 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
688 | WCD938X_RXD2_CLK_EN_MASK, val: 1); |
689 | snd_soc_component_write_field(component, |
690 | WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, |
691 | WCD938X_AUX_EN_MASK, val: 1); |
692 | if (wcd938x->flyback_cur_det_disable == 0) |
693 | snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, |
694 | WCD938X_EN_CUR_DET_MASK, val: 0); |
695 | wcd938x->flyback_cur_det_disable++; |
696 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, |
697 | clsh_event: WCD_CLSH_EVENT_PRE_DAC, |
698 | WCD_CLSH_STATE_AUX, |
699 | mode: wcd938x->hph_mode); |
700 | break; |
701 | case SND_SOC_DAPM_POST_PMD: |
702 | snd_soc_component_write_field(component, |
703 | WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
704 | WCD938X_ANA_RX_DIV4_CLK_EN_MASK, val: 0); |
705 | break; |
706 | } |
707 | return 0; |
708 | |
709 | } |
710 | |
711 | static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, |
712 | struct snd_kcontrol *kcontrol, int event) |
713 | { |
714 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
715 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
716 | int hph_mode = wcd938x->hph_mode; |
717 | |
718 | switch (event) { |
719 | case SND_SOC_DAPM_PRE_PMU: |
720 | if (wcd938x->ldoh) |
721 | snd_soc_component_write_field(component, WCD938X_LDOH_MODE, |
722 | WCD938X_LDOH_EN_MASK, val: 1); |
723 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, clsh_event: WCD_CLSH_EVENT_PRE_DAC, |
724 | WCD_CLSH_STATE_HPHR, mode: hph_mode); |
725 | wcd_clsh_set_hph_mode(ctrl: wcd938x->clsh_info, mode: CLS_H_HIFI); |
726 | |
727 | if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || |
728 | hph_mode == CLS_H_ULP) { |
729 | snd_soc_component_write_field(component, |
730 | WCD938X_HPH_REFBUFF_LP_CTL, |
731 | WCD938X_PREREF_FLIT_BYPASS_MASK, val: 1); |
732 | } |
733 | snd_soc_component_write_field(component, WCD938X_ANA_HPH, |
734 | WCD938X_HPHR_REF_EN_MASK, val: 1); |
735 | wcd_clsh_set_hph_mode(ctrl: wcd938x->clsh_info, mode: hph_mode); |
736 | /* 100 usec delay as per HW requirement */ |
737 | usleep_range(min: 100, max: 110); |
738 | set_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
739 | snd_soc_component_write_field(component, |
740 | WCD938X_DIGITAL_PDM_WD_CTL1, |
741 | WCD938X_PDM_WD_EN_MASK, val: 0x3); |
742 | break; |
743 | case SND_SOC_DAPM_POST_PMU: |
744 | /* |
745 | * 7ms sleep is required if compander is enabled as per |
746 | * HW requirement. If compander is disabled, then |
747 | * 20ms delay is required. |
748 | */ |
749 | if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { |
750 | if (!wcd938x->comp2_enable) |
751 | usleep_range(min: 20000, max: 20100); |
752 | else |
753 | usleep_range(min: 7000, max: 7100); |
754 | |
755 | if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || |
756 | hph_mode == CLS_H_ULP) |
757 | snd_soc_component_write_field(component, |
758 | WCD938X_HPH_REFBUFF_LP_CTL, |
759 | WCD938X_PREREF_FLIT_BYPASS_MASK, val: 0); |
760 | clear_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
761 | } |
762 | snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, |
763 | WCD938X_AUTOCHOP_TIMER_EN, val: 1); |
764 | if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || |
765 | hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) |
766 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
767 | WCD938X_REGULATOR_MODE_MASK, |
768 | WCD938X_REGULATOR_MODE_CLASS_AB); |
769 | enable_irq(irq: wcd938x->hphr_pdm_wd_int); |
770 | break; |
771 | case SND_SOC_DAPM_PRE_PMD: |
772 | disable_irq_nosync(irq: wcd938x->hphr_pdm_wd_int); |
773 | /* |
774 | * 7ms sleep is required if compander is enabled as per |
775 | * HW requirement. If compander is disabled, then |
776 | * 20ms delay is required. |
777 | */ |
778 | if (!wcd938x->comp2_enable) |
779 | usleep_range(min: 20000, max: 20100); |
780 | else |
781 | usleep_range(min: 7000, max: 7100); |
782 | snd_soc_component_write_field(component, WCD938X_ANA_HPH, |
783 | WCD938X_HPHR_EN_MASK, val: 0); |
784 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
785 | event: WCD_EVENT_PRE_HPHR_PA_OFF); |
786 | set_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
787 | break; |
788 | case SND_SOC_DAPM_POST_PMD: |
789 | /* |
790 | * 7ms sleep is required if compander is enabled as per |
791 | * HW requirement. If compander is disabled, then |
792 | * 20ms delay is required. |
793 | */ |
794 | if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { |
795 | if (!wcd938x->comp2_enable) |
796 | usleep_range(min: 20000, max: 20100); |
797 | else |
798 | usleep_range(min: 7000, max: 7100); |
799 | clear_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
800 | } |
801 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
802 | event: WCD_EVENT_POST_HPHR_PA_OFF); |
803 | snd_soc_component_write_field(component, WCD938X_ANA_HPH, |
804 | WCD938X_HPHR_REF_EN_MASK, val: 0); |
805 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL1, |
806 | WCD938X_PDM_WD_EN_MASK, val: 0); |
807 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, clsh_event: WCD_CLSH_EVENT_POST_PA, |
808 | WCD_CLSH_STATE_HPHR, mode: hph_mode); |
809 | if (wcd938x->ldoh) |
810 | snd_soc_component_write_field(component, WCD938X_LDOH_MODE, |
811 | WCD938X_LDOH_EN_MASK, val: 0); |
812 | break; |
813 | } |
814 | |
815 | return 0; |
816 | } |
817 | |
818 | static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, |
819 | struct snd_kcontrol *kcontrol, int event) |
820 | { |
821 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
822 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
823 | int hph_mode = wcd938x->hph_mode; |
824 | |
825 | switch (event) { |
826 | case SND_SOC_DAPM_PRE_PMU: |
827 | if (wcd938x->ldoh) |
828 | snd_soc_component_write_field(component, WCD938X_LDOH_MODE, |
829 | WCD938X_LDOH_EN_MASK, val: 1); |
830 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, clsh_event: WCD_CLSH_EVENT_PRE_DAC, |
831 | WCD_CLSH_STATE_HPHL, mode: hph_mode); |
832 | wcd_clsh_set_hph_mode(ctrl: wcd938x->clsh_info, mode: CLS_H_HIFI); |
833 | if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || |
834 | hph_mode == CLS_H_ULP) { |
835 | snd_soc_component_write_field(component, |
836 | WCD938X_HPH_REFBUFF_LP_CTL, |
837 | WCD938X_PREREF_FLIT_BYPASS_MASK, val: 1); |
838 | } |
839 | snd_soc_component_write_field(component, WCD938X_ANA_HPH, |
840 | WCD938X_HPHL_REF_EN_MASK, val: 1); |
841 | wcd_clsh_set_hph_mode(ctrl: wcd938x->clsh_info, mode: hph_mode); |
842 | /* 100 usec delay as per HW requirement */ |
843 | usleep_range(min: 100, max: 110); |
844 | set_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
845 | snd_soc_component_write_field(component, |
846 | WCD938X_DIGITAL_PDM_WD_CTL0, |
847 | WCD938X_PDM_WD_EN_MASK, val: 0x3); |
848 | break; |
849 | case SND_SOC_DAPM_POST_PMU: |
850 | /* |
851 | * 7ms sleep is required if compander is enabled as per |
852 | * HW requirement. If compander is disabled, then |
853 | * 20ms delay is required. |
854 | */ |
855 | if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { |
856 | if (!wcd938x->comp1_enable) |
857 | usleep_range(min: 20000, max: 20100); |
858 | else |
859 | usleep_range(min: 7000, max: 7100); |
860 | if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || |
861 | hph_mode == CLS_H_ULP) |
862 | snd_soc_component_write_field(component, |
863 | WCD938X_HPH_REFBUFF_LP_CTL, |
864 | WCD938X_PREREF_FLIT_BYPASS_MASK, val: 0); |
865 | clear_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
866 | } |
867 | |
868 | snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, |
869 | WCD938X_AUTOCHOP_TIMER_EN, val: 1); |
870 | if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || |
871 | hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) |
872 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
873 | WCD938X_REGULATOR_MODE_MASK, |
874 | WCD938X_REGULATOR_MODE_CLASS_AB); |
875 | enable_irq(irq: wcd938x->hphl_pdm_wd_int); |
876 | break; |
877 | case SND_SOC_DAPM_PRE_PMD: |
878 | disable_irq_nosync(irq: wcd938x->hphl_pdm_wd_int); |
879 | /* |
880 | * 7ms sleep is required if compander is enabled as per |
881 | * HW requirement. If compander is disabled, then |
882 | * 20ms delay is required. |
883 | */ |
884 | if (!wcd938x->comp1_enable) |
885 | usleep_range(min: 20000, max: 20100); |
886 | else |
887 | usleep_range(min: 7000, max: 7100); |
888 | snd_soc_component_write_field(component, WCD938X_ANA_HPH, |
889 | WCD938X_HPHL_EN_MASK, val: 0); |
890 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, event: WCD_EVENT_PRE_HPHL_PA_OFF); |
891 | set_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
892 | break; |
893 | case SND_SOC_DAPM_POST_PMD: |
894 | /* |
895 | * 7ms sleep is required if compander is enabled as per |
896 | * HW requirement. If compander is disabled, then |
897 | * 20ms delay is required. |
898 | */ |
899 | if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { |
900 | if (!wcd938x->comp1_enable) |
901 | usleep_range(min: 21000, max: 21100); |
902 | else |
903 | usleep_range(min: 7000, max: 7100); |
904 | clear_bit(nr: HPH_PA_DELAY, addr: &wcd938x->status_mask); |
905 | } |
906 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
907 | event: WCD_EVENT_POST_HPHL_PA_OFF); |
908 | snd_soc_component_write_field(component, WCD938X_ANA_HPH, |
909 | WCD938X_HPHL_REF_EN_MASK, val: 0); |
910 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0, |
911 | WCD938X_PDM_WD_EN_MASK, val: 0); |
912 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, clsh_event: WCD_CLSH_EVENT_POST_PA, |
913 | WCD_CLSH_STATE_HPHL, mode: hph_mode); |
914 | if (wcd938x->ldoh) |
915 | snd_soc_component_write_field(component, WCD938X_LDOH_MODE, |
916 | WCD938X_LDOH_EN_MASK, val: 0); |
917 | break; |
918 | } |
919 | |
920 | return 0; |
921 | } |
922 | |
923 | static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, |
924 | struct snd_kcontrol *kcontrol, int event) |
925 | { |
926 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
927 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
928 | int hph_mode = wcd938x->hph_mode; |
929 | |
930 | switch (event) { |
931 | case SND_SOC_DAPM_PRE_PMU: |
932 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, |
933 | WCD938X_AUX_PDM_WD_EN_MASK, val: 1); |
934 | break; |
935 | case SND_SOC_DAPM_POST_PMU: |
936 | /* 1 msec delay as per HW requirement */ |
937 | usleep_range(min: 1000, max: 1010); |
938 | if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || |
939 | hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) |
940 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
941 | WCD938X_REGULATOR_MODE_MASK, |
942 | WCD938X_REGULATOR_MODE_CLASS_AB); |
943 | enable_irq(irq: wcd938x->aux_pdm_wd_int); |
944 | break; |
945 | case SND_SOC_DAPM_PRE_PMD: |
946 | disable_irq_nosync(irq: wcd938x->aux_pdm_wd_int); |
947 | break; |
948 | case SND_SOC_DAPM_POST_PMD: |
949 | /* 1 msec delay as per HW requirement */ |
950 | usleep_range(min: 1000, max: 1010); |
951 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, |
952 | WCD938X_AUX_PDM_WD_EN_MASK, val: 0); |
953 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, |
954 | clsh_event: WCD_CLSH_EVENT_POST_PA, |
955 | WCD_CLSH_STATE_AUX, |
956 | mode: hph_mode); |
957 | |
958 | wcd938x->flyback_cur_det_disable--; |
959 | if (wcd938x->flyback_cur_det_disable == 0) |
960 | snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, |
961 | WCD938X_EN_CUR_DET_MASK, val: 1); |
962 | break; |
963 | } |
964 | return 0; |
965 | } |
966 | |
967 | static int wcd938x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, |
968 | struct snd_kcontrol *kcontrol, int event) |
969 | { |
970 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
971 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
972 | int hph_mode = wcd938x->hph_mode; |
973 | |
974 | switch (event) { |
975 | case SND_SOC_DAPM_PRE_PMU: |
976 | /* |
977 | * Enable watchdog interrupt for HPHL or AUX |
978 | * depending on mux value |
979 | */ |
980 | wcd938x->ear_rx_path = snd_soc_component_read(component, |
981 | WCD938X_DIGITAL_CDC_EAR_PATH_CTL); |
982 | if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) |
983 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, |
984 | WCD938X_AUX_PDM_WD_EN_MASK, val: 1); |
985 | else |
986 | snd_soc_component_write_field(component, |
987 | WCD938X_DIGITAL_PDM_WD_CTL0, |
988 | WCD938X_PDM_WD_EN_MASK, val: 0x3); |
989 | if (!wcd938x->comp1_enable) |
990 | snd_soc_component_write_field(component, |
991 | WCD938X_ANA_EAR_COMPANDER_CTL, |
992 | WCD938X_GAIN_OVRD_REG_MASK, val: 1); |
993 | |
994 | break; |
995 | case SND_SOC_DAPM_POST_PMU: |
996 | /* 6 msec delay as per HW requirement */ |
997 | usleep_range(min: 6000, max: 6010); |
998 | if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || |
999 | hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) |
1000 | snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, |
1001 | WCD938X_REGULATOR_MODE_MASK, |
1002 | WCD938X_REGULATOR_MODE_CLASS_AB); |
1003 | if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) |
1004 | enable_irq(irq: wcd938x->aux_pdm_wd_int); |
1005 | else |
1006 | enable_irq(irq: wcd938x->hphl_pdm_wd_int); |
1007 | break; |
1008 | case SND_SOC_DAPM_PRE_PMD: |
1009 | if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) |
1010 | disable_irq_nosync(irq: wcd938x->aux_pdm_wd_int); |
1011 | else |
1012 | disable_irq_nosync(irq: wcd938x->hphl_pdm_wd_int); |
1013 | break; |
1014 | case SND_SOC_DAPM_POST_PMD: |
1015 | if (!wcd938x->comp1_enable) |
1016 | snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, |
1017 | WCD938X_GAIN_OVRD_REG_MASK, val: 0); |
1018 | /* 7 msec delay as per HW requirement */ |
1019 | usleep_range(min: 7000, max: 7010); |
1020 | if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) |
1021 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, |
1022 | WCD938X_AUX_PDM_WD_EN_MASK, val: 0); |
1023 | else |
1024 | snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0, |
1025 | WCD938X_PDM_WD_EN_MASK, val: 0); |
1026 | |
1027 | wcd_clsh_ctrl_set_state(ctrl: wcd938x->clsh_info, clsh_event: WCD_CLSH_EVENT_POST_PA, |
1028 | WCD_CLSH_STATE_EAR, mode: hph_mode); |
1029 | |
1030 | wcd938x->flyback_cur_det_disable--; |
1031 | if (wcd938x->flyback_cur_det_disable == 0) |
1032 | snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, |
1033 | WCD938X_EN_CUR_DET_MASK, val: 1); |
1034 | break; |
1035 | } |
1036 | |
1037 | return 0; |
1038 | } |
1039 | |
1040 | static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w, |
1041 | struct snd_kcontrol *kcontrol, |
1042 | int event) |
1043 | { |
1044 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
1045 | u16 dmic_clk_reg, dmic_clk_en_reg; |
1046 | u8 dmic_sel_mask, dmic_clk_mask; |
1047 | |
1048 | switch (w->shift) { |
1049 | case 0: |
1050 | case 1: |
1051 | dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; |
1052 | dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL; |
1053 | dmic_clk_mask = WCD938X_DMIC1_RATE_MASK; |
1054 | dmic_sel_mask = WCD938X_AMIC1_IN_SEL_MASK; |
1055 | break; |
1056 | case 2: |
1057 | case 3: |
1058 | dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; |
1059 | dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL; |
1060 | dmic_clk_mask = WCD938X_DMIC2_RATE_MASK; |
1061 | dmic_sel_mask = WCD938X_AMIC3_IN_SEL_MASK; |
1062 | break; |
1063 | case 4: |
1064 | case 5: |
1065 | dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; |
1066 | dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL; |
1067 | dmic_clk_mask = WCD938X_DMIC3_RATE_MASK; |
1068 | dmic_sel_mask = WCD938X_AMIC4_IN_SEL_MASK; |
1069 | break; |
1070 | case 6: |
1071 | case 7: |
1072 | dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; |
1073 | dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL; |
1074 | dmic_clk_mask = WCD938X_DMIC4_RATE_MASK; |
1075 | dmic_sel_mask = WCD938X_AMIC5_IN_SEL_MASK; |
1076 | break; |
1077 | default: |
1078 | dev_err(component->dev, "%s: Invalid DMIC Selection\n" , |
1079 | __func__); |
1080 | return -EINVAL; |
1081 | } |
1082 | |
1083 | switch (event) { |
1084 | case SND_SOC_DAPM_PRE_PMU: |
1085 | snd_soc_component_write_field(component, |
1086 | WCD938X_DIGITAL_CDC_AMIC_CTL, |
1087 | mask: dmic_sel_mask, |
1088 | WCD938X_AMIC1_IN_SEL_DMIC); |
1089 | /* 250us sleep as per HW requirement */ |
1090 | usleep_range(min: 250, max: 260); |
1091 | /* Setting DMIC clock rate to 2.4MHz */ |
1092 | snd_soc_component_write_field(component, reg: dmic_clk_reg, |
1093 | mask: dmic_clk_mask, |
1094 | WCD938X_DMIC4_RATE_2P4MHZ); |
1095 | snd_soc_component_write_field(component, reg: dmic_clk_en_reg, |
1096 | WCD938X_DMIC_CLK_EN_MASK, val: 1); |
1097 | /* enable clock scaling */ |
1098 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_DMIC_CTL, |
1099 | WCD938X_DMIC_CLK_SCALING_EN_MASK, val: 0x3); |
1100 | break; |
1101 | case SND_SOC_DAPM_POST_PMD: |
1102 | snd_soc_component_write_field(component, |
1103 | WCD938X_DIGITAL_CDC_AMIC_CTL, |
1104 | mask: dmic_sel_mask, WCD938X_AMIC1_IN_SEL_AMIC); |
1105 | snd_soc_component_write_field(component, reg: dmic_clk_en_reg, |
1106 | WCD938X_DMIC_CLK_EN_MASK, val: 0); |
1107 | break; |
1108 | } |
1109 | return 0; |
1110 | } |
1111 | |
1112 | static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, |
1113 | struct snd_kcontrol *kcontrol, int event) |
1114 | { |
1115 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
1116 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1117 | int bank; |
1118 | int rate; |
1119 | |
1120 | bank = (wcd938x_swr_get_current_bank(sdev: wcd938x->sdw_priv[AIF1_CAP]->sdev)) ? 0 : 1; |
1121 | bank = bank ? 0 : 1; |
1122 | |
1123 | switch (event) { |
1124 | case SND_SOC_DAPM_PRE_PMU: |
1125 | if (strnstr(w->name, "ADC" , sizeof("ADC" ))) { |
1126 | int i = 0, mode = 0; |
1127 | |
1128 | if (test_bit(WCD_ADC1, &wcd938x->status_mask)) |
1129 | mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; |
1130 | if (test_bit(WCD_ADC2, &wcd938x->status_mask)) |
1131 | mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; |
1132 | if (test_bit(WCD_ADC3, &wcd938x->status_mask)) |
1133 | mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; |
1134 | if (test_bit(WCD_ADC4, &wcd938x->status_mask)) |
1135 | mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; |
1136 | |
1137 | if (mode != 0) { |
1138 | for (i = 0; i < ADC_MODE_ULP2; i++) { |
1139 | if (mode & (1 << i)) { |
1140 | i++; |
1141 | break; |
1142 | } |
1143 | } |
1144 | } |
1145 | rate = wcd938x_get_clk_rate(mode: i); |
1146 | wcd938x_set_swr_clk_rate(component, rate, bank); |
1147 | /* Copy clk settings to active bank */ |
1148 | wcd938x_set_swr_clk_rate(component, rate, bank: !bank); |
1149 | } |
1150 | break; |
1151 | case SND_SOC_DAPM_POST_PMD: |
1152 | if (strnstr(w->name, "ADC" , sizeof("ADC" ))) { |
1153 | rate = wcd938x_get_clk_rate(mode: ADC_MODE_INVALID); |
1154 | wcd938x_set_swr_clk_rate(component, rate, bank: !bank); |
1155 | wcd938x_set_swr_clk_rate(component, rate, bank); |
1156 | } |
1157 | break; |
1158 | } |
1159 | |
1160 | return 0; |
1161 | } |
1162 | |
1163 | static int wcd938x_get_adc_mode(int val) |
1164 | { |
1165 | int ret = 0; |
1166 | |
1167 | switch (val) { |
1168 | case ADC_MODE_INVALID: |
1169 | ret = ADC_MODE_VAL_NORMAL; |
1170 | break; |
1171 | case ADC_MODE_HIFI: |
1172 | ret = ADC_MODE_VAL_HIFI; |
1173 | break; |
1174 | case ADC_MODE_LO_HIF: |
1175 | ret = ADC_MODE_VAL_LO_HIF; |
1176 | break; |
1177 | case ADC_MODE_NORMAL: |
1178 | ret = ADC_MODE_VAL_NORMAL; |
1179 | break; |
1180 | case ADC_MODE_LP: |
1181 | ret = ADC_MODE_VAL_LP; |
1182 | break; |
1183 | case ADC_MODE_ULP1: |
1184 | ret = ADC_MODE_VAL_ULP1; |
1185 | break; |
1186 | case ADC_MODE_ULP2: |
1187 | ret = ADC_MODE_VAL_ULP2; |
1188 | break; |
1189 | default: |
1190 | ret = -EINVAL; |
1191 | break; |
1192 | } |
1193 | return ret; |
1194 | } |
1195 | |
1196 | static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, |
1197 | struct snd_kcontrol *kcontrol, int event) |
1198 | { |
1199 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
1200 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1201 | |
1202 | switch (event) { |
1203 | case SND_SOC_DAPM_PRE_PMU: |
1204 | snd_soc_component_write_field(component, |
1205 | WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
1206 | WCD938X_ANA_TX_CLK_EN_MASK, val: 1); |
1207 | snd_soc_component_write_field(component, |
1208 | WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
1209 | WCD938X_ANA_TX_DIV2_CLK_EN_MASK, val: 1); |
1210 | set_bit(nr: w->shift, addr: &wcd938x->status_mask); |
1211 | break; |
1212 | case SND_SOC_DAPM_POST_PMD: |
1213 | snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
1214 | WCD938X_ANA_TX_CLK_EN_MASK, val: 0); |
1215 | clear_bit(nr: w->shift, addr: &wcd938x->status_mask); |
1216 | break; |
1217 | } |
1218 | |
1219 | return 0; |
1220 | } |
1221 | |
1222 | static void wcd938x_tx_channel_config(struct snd_soc_component *component, |
1223 | int channel, int mode) |
1224 | { |
1225 | int reg, mask; |
1226 | |
1227 | switch (channel) { |
1228 | case 0: |
1229 | reg = WCD938X_ANA_TX_CH2; |
1230 | mask = WCD938X_HPF1_INIT_MASK; |
1231 | break; |
1232 | case 1: |
1233 | reg = WCD938X_ANA_TX_CH2; |
1234 | mask = WCD938X_HPF2_INIT_MASK; |
1235 | break; |
1236 | case 2: |
1237 | reg = WCD938X_ANA_TX_CH4; |
1238 | mask = WCD938X_HPF3_INIT_MASK; |
1239 | break; |
1240 | case 3: |
1241 | reg = WCD938X_ANA_TX_CH4; |
1242 | mask = WCD938X_HPF4_INIT_MASK; |
1243 | break; |
1244 | default: |
1245 | return; |
1246 | } |
1247 | |
1248 | snd_soc_component_write_field(component, reg, mask, val: mode); |
1249 | } |
1250 | |
1251 | static int wcd938x_adc_enable_req(struct snd_soc_dapm_widget *w, |
1252 | struct snd_kcontrol *kcontrol, int event) |
1253 | { |
1254 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
1255 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1256 | int mode; |
1257 | |
1258 | switch (event) { |
1259 | case SND_SOC_DAPM_PRE_PMU: |
1260 | snd_soc_component_write_field(component, |
1261 | WCD938X_DIGITAL_CDC_REQ_CTL, |
1262 | WCD938X_FS_RATE_4P8_MASK, val: 1); |
1263 | snd_soc_component_write_field(component, |
1264 | WCD938X_DIGITAL_CDC_REQ_CTL, |
1265 | WCD938X_NO_NOTCH_MASK, val: 0); |
1266 | wcd938x_tx_channel_config(component, channel: w->shift, mode: 1); |
1267 | mode = wcd938x_get_adc_mode(val: wcd938x->tx_mode[w->shift]); |
1268 | if (mode < 0) { |
1269 | dev_info(component->dev, "Invalid ADC mode\n" ); |
1270 | return -EINVAL; |
1271 | } |
1272 | switch (w->shift) { |
1273 | case 0: |
1274 | snd_soc_component_write_field(component, |
1275 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, |
1276 | WCD938X_TXD0_MODE_MASK, val: mode); |
1277 | snd_soc_component_write_field(component, |
1278 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1279 | WCD938X_TXD0_CLK_EN_MASK, val: 1); |
1280 | break; |
1281 | case 1: |
1282 | snd_soc_component_write_field(component, |
1283 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, |
1284 | WCD938X_TXD1_MODE_MASK, val: mode); |
1285 | snd_soc_component_write_field(component, |
1286 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1287 | WCD938X_TXD1_CLK_EN_MASK, val: 1); |
1288 | break; |
1289 | case 2: |
1290 | snd_soc_component_write_field(component, |
1291 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, |
1292 | WCD938X_TXD2_MODE_MASK, val: mode); |
1293 | snd_soc_component_write_field(component, |
1294 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1295 | WCD938X_TXD2_CLK_EN_MASK, val: 1); |
1296 | break; |
1297 | case 3: |
1298 | snd_soc_component_write_field(component, |
1299 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, |
1300 | WCD938X_TXD3_MODE_MASK, val: mode); |
1301 | snd_soc_component_write_field(component, |
1302 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1303 | WCD938X_TXD3_CLK_EN_MASK, val: 1); |
1304 | break; |
1305 | default: |
1306 | break; |
1307 | } |
1308 | |
1309 | wcd938x_tx_channel_config(component, channel: w->shift, mode: 0); |
1310 | break; |
1311 | case SND_SOC_DAPM_POST_PMD: |
1312 | switch (w->shift) { |
1313 | case 0: |
1314 | snd_soc_component_write_field(component, |
1315 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, |
1316 | WCD938X_TXD0_MODE_MASK, val: 0); |
1317 | snd_soc_component_write_field(component, |
1318 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1319 | WCD938X_TXD0_CLK_EN_MASK, val: 0); |
1320 | break; |
1321 | case 1: |
1322 | snd_soc_component_write_field(component, |
1323 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, |
1324 | WCD938X_TXD1_MODE_MASK, val: 0); |
1325 | snd_soc_component_write_field(component, |
1326 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1327 | WCD938X_TXD1_CLK_EN_MASK, val: 0); |
1328 | break; |
1329 | case 2: |
1330 | snd_soc_component_write_field(component, |
1331 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, |
1332 | WCD938X_TXD2_MODE_MASK, val: 0); |
1333 | snd_soc_component_write_field(component, |
1334 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1335 | WCD938X_TXD2_CLK_EN_MASK, val: 0); |
1336 | break; |
1337 | case 3: |
1338 | snd_soc_component_write_field(component, |
1339 | WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, |
1340 | WCD938X_TXD3_MODE_MASK, val: 0); |
1341 | snd_soc_component_write_field(component, |
1342 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1343 | WCD938X_TXD3_CLK_EN_MASK, val: 0); |
1344 | break; |
1345 | default: |
1346 | break; |
1347 | } |
1348 | snd_soc_component_write_field(component, |
1349 | WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
1350 | WCD938X_ANA_TX_DIV2_CLK_EN_MASK, val: 0); |
1351 | break; |
1352 | } |
1353 | |
1354 | return 0; |
1355 | } |
1356 | |
1357 | static int wcd938x_micbias_control(struct snd_soc_component *component, |
1358 | int micb_num, int req, bool is_dapm) |
1359 | { |
1360 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1361 | int micb_index = micb_num - 1; |
1362 | u16 micb_reg; |
1363 | |
1364 | switch (micb_num) { |
1365 | case MIC_BIAS_1: |
1366 | micb_reg = WCD938X_ANA_MICB1; |
1367 | break; |
1368 | case MIC_BIAS_2: |
1369 | micb_reg = WCD938X_ANA_MICB2; |
1370 | break; |
1371 | case MIC_BIAS_3: |
1372 | micb_reg = WCD938X_ANA_MICB3; |
1373 | break; |
1374 | case MIC_BIAS_4: |
1375 | micb_reg = WCD938X_ANA_MICB4; |
1376 | break; |
1377 | default: |
1378 | dev_err(component->dev, "%s: Invalid micbias number: %d\n" , |
1379 | __func__, micb_num); |
1380 | return -EINVAL; |
1381 | } |
1382 | |
1383 | switch (req) { |
1384 | case MICB_PULLUP_ENABLE: |
1385 | wcd938x->pullup_ref[micb_index]++; |
1386 | if ((wcd938x->pullup_ref[micb_index] == 1) && |
1387 | (wcd938x->micb_ref[micb_index] == 0)) |
1388 | snd_soc_component_write_field(component, reg: micb_reg, |
1389 | WCD938X_MICB_EN_MASK, |
1390 | WCD938X_MICB_PULL_UP); |
1391 | break; |
1392 | case MICB_PULLUP_DISABLE: |
1393 | if (wcd938x->pullup_ref[micb_index] > 0) |
1394 | wcd938x->pullup_ref[micb_index]--; |
1395 | |
1396 | if ((wcd938x->pullup_ref[micb_index] == 0) && |
1397 | (wcd938x->micb_ref[micb_index] == 0)) |
1398 | snd_soc_component_write_field(component, reg: micb_reg, |
1399 | WCD938X_MICB_EN_MASK, val: 0); |
1400 | break; |
1401 | case MICB_ENABLE: |
1402 | wcd938x->micb_ref[micb_index]++; |
1403 | if (wcd938x->micb_ref[micb_index] == 1) { |
1404 | snd_soc_component_write_field(component, |
1405 | WCD938X_DIGITAL_CDC_DIG_CLK_CTL, |
1406 | WCD938X_TX_CLK_EN_MASK, val: 0xF); |
1407 | snd_soc_component_write_field(component, |
1408 | WCD938X_DIGITAL_CDC_ANA_CLK_CTL, |
1409 | WCD938X_ANA_TX_DIV2_CLK_EN_MASK, val: 1); |
1410 | snd_soc_component_write_field(component, |
1411 | WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, |
1412 | WCD938X_TX_SC_CLK_EN_MASK, val: 1); |
1413 | |
1414 | snd_soc_component_write_field(component, reg: micb_reg, |
1415 | WCD938X_MICB_EN_MASK, |
1416 | WCD938X_MICB_ENABLE); |
1417 | if (micb_num == MIC_BIAS_2) |
1418 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
1419 | event: WCD_EVENT_POST_MICBIAS_2_ON); |
1420 | } |
1421 | if (micb_num == MIC_BIAS_2 && is_dapm) |
1422 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
1423 | event: WCD_EVENT_POST_DAPM_MICBIAS_2_ON); |
1424 | |
1425 | |
1426 | break; |
1427 | case MICB_DISABLE: |
1428 | if (wcd938x->micb_ref[micb_index] > 0) |
1429 | wcd938x->micb_ref[micb_index]--; |
1430 | |
1431 | if ((wcd938x->micb_ref[micb_index] == 0) && |
1432 | (wcd938x->pullup_ref[micb_index] > 0)) |
1433 | snd_soc_component_write_field(component, reg: micb_reg, |
1434 | WCD938X_MICB_EN_MASK, |
1435 | WCD938X_MICB_PULL_UP); |
1436 | else if ((wcd938x->micb_ref[micb_index] == 0) && |
1437 | (wcd938x->pullup_ref[micb_index] == 0)) { |
1438 | if (micb_num == MIC_BIAS_2) |
1439 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
1440 | event: WCD_EVENT_PRE_MICBIAS_2_OFF); |
1441 | |
1442 | snd_soc_component_write_field(component, reg: micb_reg, |
1443 | WCD938X_MICB_EN_MASK, val: 0); |
1444 | if (micb_num == MIC_BIAS_2) |
1445 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
1446 | event: WCD_EVENT_POST_MICBIAS_2_OFF); |
1447 | } |
1448 | if (is_dapm && micb_num == MIC_BIAS_2) |
1449 | wcd_mbhc_event_notify(mbhc: wcd938x->wcd_mbhc, |
1450 | event: WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); |
1451 | break; |
1452 | } |
1453 | |
1454 | return 0; |
1455 | } |
1456 | |
1457 | static int wcd938x_codec_enable_micbias(struct snd_soc_dapm_widget *w, |
1458 | struct snd_kcontrol *kcontrol, |
1459 | int event) |
1460 | { |
1461 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
1462 | int micb_num = w->shift; |
1463 | |
1464 | switch (event) { |
1465 | case SND_SOC_DAPM_PRE_PMU: |
1466 | wcd938x_micbias_control(component, micb_num, req: MICB_ENABLE, is_dapm: true); |
1467 | break; |
1468 | case SND_SOC_DAPM_POST_PMU: |
1469 | /* 1 msec delay as per HW requirement */ |
1470 | usleep_range(min: 1000, max: 1100); |
1471 | break; |
1472 | case SND_SOC_DAPM_POST_PMD: |
1473 | wcd938x_micbias_control(component, micb_num, req: MICB_DISABLE, is_dapm: true); |
1474 | break; |
1475 | } |
1476 | |
1477 | return 0; |
1478 | } |
1479 | |
1480 | static int wcd938x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, |
1481 | struct snd_kcontrol *kcontrol, |
1482 | int event) |
1483 | { |
1484 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
1485 | int micb_num = w->shift; |
1486 | |
1487 | switch (event) { |
1488 | case SND_SOC_DAPM_PRE_PMU: |
1489 | wcd938x_micbias_control(component, micb_num, |
1490 | req: MICB_PULLUP_ENABLE, is_dapm: true); |
1491 | break; |
1492 | case SND_SOC_DAPM_POST_PMU: |
1493 | /* 1 msec delay as per HW requirement */ |
1494 | usleep_range(min: 1000, max: 1100); |
1495 | break; |
1496 | case SND_SOC_DAPM_POST_PMD: |
1497 | wcd938x_micbias_control(component, micb_num, |
1498 | req: MICB_PULLUP_DISABLE, is_dapm: true); |
1499 | break; |
1500 | } |
1501 | |
1502 | return 0; |
1503 | } |
1504 | |
1505 | static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, |
1506 | struct snd_ctl_elem_value *ucontrol) |
1507 | { |
1508 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1509 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1510 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1511 | int path = e->shift_l; |
1512 | |
1513 | ucontrol->value.enumerated.item[0] = wcd938x->tx_mode[path]; |
1514 | |
1515 | return 0; |
1516 | } |
1517 | |
1518 | static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol, |
1519 | struct snd_ctl_elem_value *ucontrol) |
1520 | { |
1521 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1522 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1523 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1524 | int path = e->shift_l; |
1525 | |
1526 | if (wcd938x->tx_mode[path] == ucontrol->value.enumerated.item[0]) |
1527 | return 0; |
1528 | |
1529 | wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0]; |
1530 | |
1531 | return 1; |
1532 | } |
1533 | |
1534 | static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, |
1535 | struct snd_ctl_elem_value *ucontrol) |
1536 | { |
1537 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1538 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1539 | |
1540 | ucontrol->value.enumerated.item[0] = wcd938x->hph_mode; |
1541 | |
1542 | return 0; |
1543 | } |
1544 | |
1545 | static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, |
1546 | struct snd_ctl_elem_value *ucontrol) |
1547 | { |
1548 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1549 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1550 | |
1551 | if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0]) |
1552 | return 0; |
1553 | |
1554 | wcd938x->hph_mode = ucontrol->value.enumerated.item[0]; |
1555 | |
1556 | return 1; |
1557 | } |
1558 | |
1559 | static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol, |
1560 | struct snd_ctl_elem_value *ucontrol) |
1561 | { |
1562 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1563 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1564 | |
1565 | if (wcd938x->comp1_enable) { |
1566 | dev_err(component->dev, "Can not set EAR PA Gain, compander1 is enabled\n" ); |
1567 | return -EINVAL; |
1568 | } |
1569 | |
1570 | snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, |
1571 | WCD938X_EAR_GAIN_MASK, |
1572 | val: ucontrol->value.integer.value[0]); |
1573 | |
1574 | return 1; |
1575 | } |
1576 | |
1577 | static int wcd938x_get_compander(struct snd_kcontrol *kcontrol, |
1578 | struct snd_ctl_elem_value *ucontrol) |
1579 | { |
1580 | |
1581 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1582 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1583 | struct soc_mixer_control *mc; |
1584 | bool hphr; |
1585 | |
1586 | mc = (struct soc_mixer_control *)(kcontrol->private_value); |
1587 | hphr = mc->shift; |
1588 | |
1589 | if (hphr) |
1590 | ucontrol->value.integer.value[0] = wcd938x->comp2_enable; |
1591 | else |
1592 | ucontrol->value.integer.value[0] = wcd938x->comp1_enable; |
1593 | |
1594 | return 0; |
1595 | } |
1596 | |
1597 | static int wcd938x_set_compander(struct snd_kcontrol *kcontrol, |
1598 | struct snd_ctl_elem_value *ucontrol) |
1599 | { |
1600 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1601 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1602 | struct wcd938x_sdw_priv *wcd; |
1603 | int value = ucontrol->value.integer.value[0]; |
1604 | int portidx; |
1605 | struct soc_mixer_control *mc; |
1606 | bool hphr; |
1607 | |
1608 | mc = (struct soc_mixer_control *)(kcontrol->private_value); |
1609 | hphr = mc->shift; |
1610 | |
1611 | wcd = wcd938x->sdw_priv[AIF1_PB]; |
1612 | |
1613 | if (hphr) |
1614 | wcd938x->comp2_enable = value; |
1615 | else |
1616 | wcd938x->comp1_enable = value; |
1617 | |
1618 | portidx = wcd->ch_info[mc->reg].port_num; |
1619 | |
1620 | if (value) |
1621 | wcd938x_connect_port(wcd, port_num: portidx, ch_id: mc->reg, enable: true); |
1622 | else |
1623 | wcd938x_connect_port(wcd, port_num: portidx, ch_id: mc->reg, enable: false); |
1624 | |
1625 | return 1; |
1626 | } |
1627 | |
1628 | static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol, |
1629 | struct snd_ctl_elem_value *ucontrol) |
1630 | { |
1631 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1632 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1633 | |
1634 | ucontrol->value.integer.value[0] = wcd938x->ldoh; |
1635 | |
1636 | return 0; |
1637 | } |
1638 | |
1639 | static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, |
1640 | struct snd_ctl_elem_value *ucontrol) |
1641 | { |
1642 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1643 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1644 | |
1645 | if (wcd938x->ldoh == ucontrol->value.integer.value[0]) |
1646 | return 0; |
1647 | |
1648 | wcd938x->ldoh = ucontrol->value.integer.value[0]; |
1649 | |
1650 | return 1; |
1651 | } |
1652 | |
1653 | static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol, |
1654 | struct snd_ctl_elem_value *ucontrol) |
1655 | { |
1656 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1657 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1658 | |
1659 | ucontrol->value.integer.value[0] = wcd938x->bcs_dis; |
1660 | |
1661 | return 0; |
1662 | } |
1663 | |
1664 | static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, |
1665 | struct snd_ctl_elem_value *ucontrol) |
1666 | { |
1667 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
1668 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
1669 | |
1670 | if (wcd938x->bcs_dis == ucontrol->value.integer.value[0]) |
1671 | return 0; |
1672 | |
1673 | wcd938x->bcs_dis = ucontrol->value.integer.value[0]; |
1674 | |
1675 | return 1; |
1676 | } |
1677 | |
1678 | static const char * const tx_mode_mux_text_wcd9380[] = { |
1679 | "ADC_INVALID" , "ADC_HIFI" , "ADC_LO_HIF" , "ADC_NORMAL" , "ADC_LP" , |
1680 | }; |
1681 | |
1682 | static const char * const tx_mode_mux_text[] = { |
1683 | "ADC_INVALID" , "ADC_HIFI" , "ADC_LO_HIF" , "ADC_NORMAL" , "ADC_LP" , |
1684 | "ADC_ULP1" , "ADC_ULP2" , |
1685 | }; |
1686 | |
1687 | static const char * const rx_hph_mode_mux_text_wcd9380[] = { |
1688 | "CLS_H_INVALID" , "CLS_H_INVALID_1" , "CLS_H_LP" , "CLS_AB" , |
1689 | "CLS_H_LOHIFI" , "CLS_H_ULP" , "CLS_H_INVALID_2" , "CLS_AB_LP" , |
1690 | "CLS_AB_LOHIFI" , |
1691 | }; |
1692 | |
1693 | static const char * const rx_hph_mode_mux_text[] = { |
1694 | "CLS_H_INVALID" , "CLS_H_HIFI" , "CLS_H_LP" , "CLS_AB" , "CLS_H_LOHIFI" , |
1695 | "CLS_H_ULP" , "CLS_AB_HIFI" , "CLS_AB_LP" , "CLS_AB_LOHIFI" , |
1696 | }; |
1697 | |
1698 | static const char * const adc2_mux_text[] = { |
1699 | "INP2" , "INP3" |
1700 | }; |
1701 | |
1702 | static const char * const adc3_mux_text[] = { |
1703 | "INP4" , "INP6" |
1704 | }; |
1705 | |
1706 | static const char * const adc4_mux_text[] = { |
1707 | "INP5" , "INP7" |
1708 | }; |
1709 | |
1710 | static const char * const rdac3_mux_text[] = { |
1711 | "RX1" , "RX3" |
1712 | }; |
1713 | |
1714 | static const char * const hdr12_mux_text[] = { |
1715 | "NO_HDR12" , "HDR12" |
1716 | }; |
1717 | |
1718 | static const char * const hdr34_mux_text[] = { |
1719 | "NO_HDR34" , "HDR34" |
1720 | }; |
1721 | |
1722 | static const struct soc_enum tx0_mode_enum_wcd9380 = |
1723 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9380), |
1724 | tx_mode_mux_text_wcd9380); |
1725 | |
1726 | static const struct soc_enum tx1_mode_enum_wcd9380 = |
1727 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9380), |
1728 | tx_mode_mux_text_wcd9380); |
1729 | |
1730 | static const struct soc_enum tx2_mode_enum_wcd9380 = |
1731 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9380), |
1732 | tx_mode_mux_text_wcd9380); |
1733 | |
1734 | static const struct soc_enum tx3_mode_enum_wcd9380 = |
1735 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9380), |
1736 | tx_mode_mux_text_wcd9380); |
1737 | |
1738 | static const struct soc_enum tx0_mode_enum_wcd9385 = |
1739 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), |
1740 | tx_mode_mux_text); |
1741 | |
1742 | static const struct soc_enum tx1_mode_enum_wcd9385 = |
1743 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), |
1744 | tx_mode_mux_text); |
1745 | |
1746 | static const struct soc_enum tx2_mode_enum_wcd9385 = |
1747 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), |
1748 | tx_mode_mux_text); |
1749 | |
1750 | static const struct soc_enum tx3_mode_enum_wcd9385 = |
1751 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text), |
1752 | tx_mode_mux_text); |
1753 | |
1754 | static const struct soc_enum rx_hph_mode_mux_enum_wcd9380 = |
1755 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9380), |
1756 | rx_hph_mode_mux_text_wcd9380); |
1757 | |
1758 | static const struct soc_enum rx_hph_mode_mux_enum = |
1759 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), |
1760 | rx_hph_mode_mux_text); |
1761 | |
1762 | static const struct soc_enum adc2_enum = |
1763 | SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 7, |
1764 | ARRAY_SIZE(adc2_mux_text), adc2_mux_text); |
1765 | |
1766 | static const struct soc_enum adc3_enum = |
1767 | SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 6, |
1768 | ARRAY_SIZE(adc3_mux_text), adc3_mux_text); |
1769 | |
1770 | static const struct soc_enum adc4_enum = |
1771 | SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 5, |
1772 | ARRAY_SIZE(adc4_mux_text), adc4_mux_text); |
1773 | |
1774 | static const struct soc_enum hdr12_enum = |
1775 | SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 4, |
1776 | ARRAY_SIZE(hdr12_mux_text), hdr12_mux_text); |
1777 | |
1778 | static const struct soc_enum hdr34_enum = |
1779 | SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 3, |
1780 | ARRAY_SIZE(hdr34_mux_text), hdr34_mux_text); |
1781 | |
1782 | static const struct soc_enum rdac3_enum = |
1783 | SOC_ENUM_SINGLE(WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0, |
1784 | ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); |
1785 | |
1786 | static const struct snd_kcontrol_new adc1_switch[] = { |
1787 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1788 | }; |
1789 | |
1790 | static const struct snd_kcontrol_new adc2_switch[] = { |
1791 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1792 | }; |
1793 | |
1794 | static const struct snd_kcontrol_new adc3_switch[] = { |
1795 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1796 | }; |
1797 | |
1798 | static const struct snd_kcontrol_new adc4_switch[] = { |
1799 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1800 | }; |
1801 | |
1802 | static const struct snd_kcontrol_new dmic1_switch[] = { |
1803 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1804 | }; |
1805 | |
1806 | static const struct snd_kcontrol_new dmic2_switch[] = { |
1807 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1808 | }; |
1809 | |
1810 | static const struct snd_kcontrol_new dmic3_switch[] = { |
1811 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1812 | }; |
1813 | |
1814 | static const struct snd_kcontrol_new dmic4_switch[] = { |
1815 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1816 | }; |
1817 | |
1818 | static const struct snd_kcontrol_new dmic5_switch[] = { |
1819 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1820 | }; |
1821 | |
1822 | static const struct snd_kcontrol_new dmic6_switch[] = { |
1823 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1824 | }; |
1825 | |
1826 | static const struct snd_kcontrol_new dmic7_switch[] = { |
1827 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1828 | }; |
1829 | |
1830 | static const struct snd_kcontrol_new dmic8_switch[] = { |
1831 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1832 | }; |
1833 | |
1834 | static const struct snd_kcontrol_new ear_rdac_switch[] = { |
1835 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1836 | }; |
1837 | |
1838 | static const struct snd_kcontrol_new aux_rdac_switch[] = { |
1839 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1840 | }; |
1841 | |
1842 | static const struct snd_kcontrol_new hphl_rdac_switch[] = { |
1843 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1844 | }; |
1845 | |
1846 | static const struct snd_kcontrol_new hphr_rdac_switch[] = { |
1847 | SOC_DAPM_SINGLE("Switch" , SND_SOC_NOPM, 0, 1, 0) |
1848 | }; |
1849 | |
1850 | static const struct snd_kcontrol_new tx_adc2_mux = |
1851 | SOC_DAPM_ENUM("ADC2 MUX Mux" , adc2_enum); |
1852 | |
1853 | static const struct snd_kcontrol_new tx_adc3_mux = |
1854 | SOC_DAPM_ENUM("ADC3 MUX Mux" , adc3_enum); |
1855 | |
1856 | static const struct snd_kcontrol_new tx_adc4_mux = |
1857 | SOC_DAPM_ENUM("ADC4 MUX Mux" , adc4_enum); |
1858 | |
1859 | static const struct snd_kcontrol_new tx_hdr12_mux = |
1860 | SOC_DAPM_ENUM("HDR12 MUX Mux" , hdr12_enum); |
1861 | |
1862 | static const struct snd_kcontrol_new tx_hdr34_mux = |
1863 | SOC_DAPM_ENUM("HDR34 MUX Mux" , hdr34_enum); |
1864 | |
1865 | static const struct snd_kcontrol_new rx_rdac3_mux = |
1866 | SOC_DAPM_ENUM("RDAC3_MUX Mux" , rdac3_enum); |
1867 | |
1868 | static const struct snd_kcontrol_new wcd9380_snd_controls[] = { |
1869 | SOC_ENUM_EXT("RX HPH Mode" , rx_hph_mode_mux_enum_wcd9380, |
1870 | wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), |
1871 | SOC_ENUM_EXT("TX0 MODE" , tx0_mode_enum_wcd9380, |
1872 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1873 | SOC_ENUM_EXT("TX1 MODE" , tx1_mode_enum_wcd9380, |
1874 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1875 | SOC_ENUM_EXT("TX2 MODE" , tx2_mode_enum_wcd9380, |
1876 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1877 | SOC_ENUM_EXT("TX3 MODE" , tx3_mode_enum_wcd9380, |
1878 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1879 | }; |
1880 | |
1881 | static const struct snd_kcontrol_new wcd9385_snd_controls[] = { |
1882 | SOC_ENUM_EXT("RX HPH Mode" , rx_hph_mode_mux_enum, |
1883 | wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), |
1884 | SOC_ENUM_EXT("TX0 MODE" , tx0_mode_enum_wcd9385, |
1885 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1886 | SOC_ENUM_EXT("TX1 MODE" , tx1_mode_enum_wcd9385, |
1887 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1888 | SOC_ENUM_EXT("TX2 MODE" , tx2_mode_enum_wcd9385, |
1889 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1890 | SOC_ENUM_EXT("TX3 MODE" , tx3_mode_enum_wcd9385, |
1891 | wcd938x_tx_mode_get, wcd938x_tx_mode_put), |
1892 | }; |
1893 | |
1894 | static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol, |
1895 | struct snd_ctl_elem_value *ucontrol) |
1896 | { |
1897 | struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); |
1898 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: comp); |
1899 | struct wcd938x_sdw_priv *wcd; |
1900 | struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; |
1901 | int dai_id = mixer->shift; |
1902 | int portidx, ch_idx = mixer->reg; |
1903 | |
1904 | |
1905 | wcd = wcd938x->sdw_priv[dai_id]; |
1906 | portidx = wcd->ch_info[ch_idx].port_num; |
1907 | |
1908 | ucontrol->value.integer.value[0] = wcd->port_enable[portidx]; |
1909 | |
1910 | return 0; |
1911 | } |
1912 | |
1913 | static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol, |
1914 | struct snd_ctl_elem_value *ucontrol) |
1915 | { |
1916 | struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); |
1917 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: comp); |
1918 | struct wcd938x_sdw_priv *wcd; |
1919 | struct soc_mixer_control *mixer = |
1920 | (struct soc_mixer_control *)kcontrol->private_value; |
1921 | int ch_idx = mixer->reg; |
1922 | int portidx; |
1923 | int dai_id = mixer->shift; |
1924 | bool enable; |
1925 | |
1926 | wcd = wcd938x->sdw_priv[dai_id]; |
1927 | |
1928 | portidx = wcd->ch_info[ch_idx].port_num; |
1929 | if (ucontrol->value.integer.value[0]) |
1930 | enable = true; |
1931 | else |
1932 | enable = false; |
1933 | |
1934 | wcd->port_enable[portidx] = enable; |
1935 | |
1936 | wcd938x_connect_port(wcd, port_num: portidx, ch_id: ch_idx, enable); |
1937 | |
1938 | return 1; |
1939 | |
1940 | } |
1941 | |
1942 | /* MBHC related */ |
1943 | static void wcd938x_mbhc_clk_setup(struct snd_soc_component *component, |
1944 | bool enable) |
1945 | { |
1946 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_1, |
1947 | WCD938X_MBHC_CTL_RCO_EN_MASK, val: enable); |
1948 | } |
1949 | |
1950 | static void wcd938x_mbhc_mbhc_bias_control(struct snd_soc_component *component, |
1951 | bool enable) |
1952 | { |
1953 | snd_soc_component_write_field(component, WCD938X_ANA_MBHC_ELECT, |
1954 | WCD938X_ANA_MBHC_BIAS_EN, val: enable); |
1955 | } |
1956 | |
1957 | static void wcd938x_mbhc_program_btn_thr(struct snd_soc_component *component, |
1958 | int *btn_low, int *btn_high, |
1959 | int num_btn, bool is_micbias) |
1960 | { |
1961 | int i, vth; |
1962 | |
1963 | if (num_btn > WCD_MBHC_DEF_BUTTONS) { |
1964 | dev_err(component->dev, "%s: invalid number of buttons: %d\n" , |
1965 | __func__, num_btn); |
1966 | return; |
1967 | } |
1968 | |
1969 | for (i = 0; i < num_btn; i++) { |
1970 | vth = ((btn_high[i] * 2) / 25) & 0x3F; |
1971 | snd_soc_component_write_field(component, WCD938X_ANA_MBHC_BTN0 + i, |
1972 | WCD938X_MBHC_BTN_VTH_MASK, val: vth); |
1973 | dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n" , |
1974 | __func__, i, btn_high[i], vth); |
1975 | } |
1976 | } |
1977 | |
1978 | static bool wcd938x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) |
1979 | { |
1980 | u8 val; |
1981 | |
1982 | if (micb_num == MIC_BIAS_2) { |
1983 | val = snd_soc_component_read_field(component, |
1984 | WCD938X_ANA_MICB2, |
1985 | WCD938X_ANA_MICB2_ENABLE_MASK); |
1986 | if (val == WCD938X_MICB_ENABLE) |
1987 | return true; |
1988 | } |
1989 | return false; |
1990 | } |
1991 | |
1992 | static void wcd938x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component, |
1993 | int pull_up_cur) |
1994 | { |
1995 | /* Default pull up current to 2uA */ |
1996 | if (pull_up_cur > HS_PULLUP_I_OFF || pull_up_cur < HS_PULLUP_I_3P0_UA) |
1997 | pull_up_cur = HS_PULLUP_I_2P0_UA; |
1998 | |
1999 | snd_soc_component_write_field(component, |
2000 | WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, |
2001 | WCD938X_HSDET_PULLUP_C_MASK, val: pull_up_cur); |
2002 | } |
2003 | |
2004 | static int wcd938x_mbhc_request_micbias(struct snd_soc_component *component, |
2005 | int micb_num, int req) |
2006 | { |
2007 | return wcd938x_micbias_control(component, micb_num, req, is_dapm: false); |
2008 | } |
2009 | |
2010 | static void wcd938x_mbhc_micb_ramp_control(struct snd_soc_component *component, |
2011 | bool enable) |
2012 | { |
2013 | if (enable) { |
2014 | snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP, |
2015 | WCD938X_RAMP_SHIFT_CTRL_MASK, val: 0x0C); |
2016 | snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP, |
2017 | WCD938X_RAMP_EN_MASK, val: 1); |
2018 | } else { |
2019 | snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP, |
2020 | WCD938X_RAMP_EN_MASK, val: 0); |
2021 | snd_soc_component_write_field(component, WCD938X_ANA_MICB2_RAMP, |
2022 | WCD938X_RAMP_SHIFT_CTRL_MASK, val: 0); |
2023 | } |
2024 | } |
2025 | |
2026 | static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv) |
2027 | { |
2028 | /* min micbias voltage is 1V and maximum is 2.85V */ |
2029 | if (micb_mv < 1000 || micb_mv > 2850) |
2030 | return -EINVAL; |
2031 | |
2032 | return (micb_mv - 1000) / 50; |
2033 | } |
2034 | |
2035 | static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, |
2036 | int req_volt, int micb_num) |
2037 | { |
2038 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2039 | int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; |
2040 | |
2041 | switch (micb_num) { |
2042 | case MIC_BIAS_1: |
2043 | micb_reg = WCD938X_ANA_MICB1; |
2044 | break; |
2045 | case MIC_BIAS_2: |
2046 | micb_reg = WCD938X_ANA_MICB2; |
2047 | break; |
2048 | case MIC_BIAS_3: |
2049 | micb_reg = WCD938X_ANA_MICB3; |
2050 | break; |
2051 | case MIC_BIAS_4: |
2052 | micb_reg = WCD938X_ANA_MICB4; |
2053 | break; |
2054 | default: |
2055 | return -EINVAL; |
2056 | } |
2057 | mutex_lock(&wcd938x->micb_lock); |
2058 | /* |
2059 | * If requested micbias voltage is same as current micbias |
2060 | * voltage, then just return. Otherwise, adjust voltage as |
2061 | * per requested value. If micbias is already enabled, then |
2062 | * to avoid slow micbias ramp-up or down enable pull-up |
2063 | * momentarily, change the micbias value and then re-enable |
2064 | * micbias. |
2065 | */ |
2066 | micb_en = snd_soc_component_read_field(component, reg: micb_reg, |
2067 | WCD938X_MICB_EN_MASK); |
2068 | cur_vout_ctl = snd_soc_component_read_field(component, reg: micb_reg, |
2069 | WCD938X_MICB_VOUT_MASK); |
2070 | |
2071 | req_vout_ctl = wcd938x_get_micb_vout_ctl_val(micb_mv: req_volt); |
2072 | if (req_vout_ctl < 0) { |
2073 | ret = -EINVAL; |
2074 | goto exit; |
2075 | } |
2076 | |
2077 | if (cur_vout_ctl == req_vout_ctl) { |
2078 | ret = 0; |
2079 | goto exit; |
2080 | } |
2081 | |
2082 | if (micb_en == WCD938X_MICB_ENABLE) |
2083 | snd_soc_component_write_field(component, reg: micb_reg, |
2084 | WCD938X_MICB_EN_MASK, |
2085 | WCD938X_MICB_PULL_UP); |
2086 | |
2087 | snd_soc_component_write_field(component, reg: micb_reg, |
2088 | WCD938X_MICB_VOUT_MASK, |
2089 | val: req_vout_ctl); |
2090 | |
2091 | if (micb_en == WCD938X_MICB_ENABLE) { |
2092 | snd_soc_component_write_field(component, reg: micb_reg, |
2093 | WCD938X_MICB_EN_MASK, |
2094 | WCD938X_MICB_ENABLE); |
2095 | /* |
2096 | * Add 2ms delay as per HW requirement after enabling |
2097 | * micbias |
2098 | */ |
2099 | usleep_range(min: 2000, max: 2100); |
2100 | } |
2101 | exit: |
2102 | mutex_unlock(lock: &wcd938x->micb_lock); |
2103 | return ret; |
2104 | } |
2105 | |
2106 | static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, |
2107 | int micb_num, bool req_en) |
2108 | { |
2109 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2110 | int micb_mv; |
2111 | |
2112 | if (micb_num != MIC_BIAS_2) |
2113 | return -EINVAL; |
2114 | /* |
2115 | * If device tree micbias level is already above the minimum |
2116 | * voltage needed to detect threshold microphone, then do |
2117 | * not change the micbias, just return. |
2118 | */ |
2119 | if (wcd938x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) |
2120 | return 0; |
2121 | |
2122 | micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd938x->micb2_mv; |
2123 | |
2124 | return wcd938x_mbhc_micb_adjust_voltage(component, req_volt: micb_mv, micb_num: MIC_BIAS_2); |
2125 | } |
2126 | |
2127 | static void wcd938x_mbhc_get_result_params(struct snd_soc_component *component, |
2128 | s16 *d1_a, u16 noff, |
2129 | int32_t *zdet) |
2130 | { |
2131 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2132 | int i; |
2133 | int val, val1; |
2134 | s16 c1; |
2135 | s32 x1, d1; |
2136 | int32_t denom; |
2137 | static const int minCode_param[] = { |
2138 | 3277, 1639, 820, 410, 205, 103, 52, 26 |
2139 | }; |
2140 | |
2141 | regmap_update_bits(map: wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, mask: 0x20, val: 0x20); |
2142 | for (i = 0; i < WCD938X_ZDET_NUM_MEASUREMENTS; i++) { |
2143 | regmap_read(map: wcd938x->regmap, WCD938X_ANA_MBHC_RESULT_2, val: &val); |
2144 | if (val & 0x80) |
2145 | break; |
2146 | } |
2147 | val = val << 0x8; |
2148 | regmap_read(map: wcd938x->regmap, WCD938X_ANA_MBHC_RESULT_1, val: &val1); |
2149 | val |= val1; |
2150 | regmap_update_bits(map: wcd938x->regmap, WCD938X_ANA_MBHC_ZDET, mask: 0x20, val: 0x00); |
2151 | x1 = WCD938X_MBHC_GET_X1(val); |
2152 | c1 = WCD938X_MBHC_GET_C1(val); |
2153 | /* If ramp is not complete, give additional 5ms */ |
2154 | if ((c1 < 2) && x1) |
2155 | usleep_range(min: 5000, max: 5050); |
2156 | |
2157 | if (!c1 || !x1) { |
2158 | dev_err(component->dev, "Impedance detect ramp error, c1=%d, x1=0x%x\n" , |
2159 | c1, x1); |
2160 | goto ramp_down; |
2161 | } |
2162 | d1 = d1_a[c1]; |
2163 | denom = (x1 * d1) - (1 << (14 - noff)); |
2164 | if (denom > 0) |
2165 | *zdet = (WCD938X_MBHC_ZDET_CONST * 1000) / denom; |
2166 | else if (x1 < minCode_param[noff]) |
2167 | *zdet = WCD938X_ZDET_FLOATING_IMPEDANCE; |
2168 | |
2169 | dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d (milliohm)\n" , |
2170 | __func__, d1, c1, x1, *zdet); |
2171 | ramp_down: |
2172 | i = 0; |
2173 | while (x1) { |
2174 | regmap_read(map: wcd938x->regmap, |
2175 | WCD938X_ANA_MBHC_RESULT_1, val: &val); |
2176 | regmap_read(map: wcd938x->regmap, |
2177 | WCD938X_ANA_MBHC_RESULT_2, val: &val1); |
2178 | val = val << 0x08; |
2179 | val |= val1; |
2180 | x1 = WCD938X_MBHC_GET_X1(val); |
2181 | i++; |
2182 | if (i == WCD938X_ZDET_NUM_MEASUREMENTS) |
2183 | break; |
2184 | } |
2185 | } |
2186 | |
2187 | static void wcd938x_mbhc_zdet_ramp(struct snd_soc_component *component, |
2188 | struct wcd938x_mbhc_zdet_param *zdet_param, |
2189 | int32_t *zl, int32_t *zr, s16 *d1_a) |
2190 | { |
2191 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2192 | int32_t zdet = 0; |
2193 | |
2194 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, |
2195 | WCD938X_ZDET_MAXV_CTL_MASK, val: zdet_param->ldo_ctl); |
2196 | snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN5, |
2197 | WCD938X_VTH_MASK, val: zdet_param->btn5); |
2198 | snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN6, |
2199 | WCD938X_VTH_MASK, val: zdet_param->btn6); |
2200 | snd_soc_component_update_bits(component, WCD938X_ANA_MBHC_BTN7, |
2201 | WCD938X_VTH_MASK, val: zdet_param->btn7); |
2202 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, |
2203 | WCD938X_ZDET_RANGE_CTL_MASK, val: zdet_param->noff); |
2204 | snd_soc_component_update_bits(component, WCD938X_MBHC_NEW_ZDET_RAMP_CTL, |
2205 | mask: 0x0F, val: zdet_param->nshift); |
2206 | |
2207 | if (!zl) |
2208 | goto z_right; |
2209 | /* Start impedance measurement for HPH_L */ |
2210 | regmap_update_bits(map: wcd938x->regmap, |
2211 | WCD938X_ANA_MBHC_ZDET, mask: 0x80, val: 0x80); |
2212 | dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n" , |
2213 | __func__, zdet_param->noff); |
2214 | wcd938x_mbhc_get_result_params(component, d1_a, noff: zdet_param->noff, zdet: &zdet); |
2215 | regmap_update_bits(map: wcd938x->regmap, |
2216 | WCD938X_ANA_MBHC_ZDET, mask: 0x80, val: 0x00); |
2217 | |
2218 | *zl = zdet; |
2219 | |
2220 | z_right: |
2221 | if (!zr) |
2222 | return; |
2223 | /* Start impedance measurement for HPH_R */ |
2224 | regmap_update_bits(map: wcd938x->regmap, |
2225 | WCD938X_ANA_MBHC_ZDET, mask: 0x40, val: 0x40); |
2226 | dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n" , |
2227 | __func__, zdet_param->noff); |
2228 | wcd938x_mbhc_get_result_params(component, d1_a, noff: zdet_param->noff, zdet: &zdet); |
2229 | regmap_update_bits(map: wcd938x->regmap, |
2230 | WCD938X_ANA_MBHC_ZDET, mask: 0x40, val: 0x00); |
2231 | |
2232 | *zr = zdet; |
2233 | } |
2234 | |
2235 | static void wcd938x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, |
2236 | int32_t *z_val, int flag_l_r) |
2237 | { |
2238 | s16 q1; |
2239 | int q1_cal; |
2240 | |
2241 | if (*z_val < (WCD938X_ZDET_VAL_400/1000)) |
2242 | q1 = snd_soc_component_read(component, |
2243 | WCD938X_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r)); |
2244 | else |
2245 | q1 = snd_soc_component_read(component, |
2246 | WCD938X_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r)); |
2247 | if (q1 & 0x80) |
2248 | q1_cal = (10000 - ((q1 & 0x7F) * 25)); |
2249 | else |
2250 | q1_cal = (10000 + (q1 * 25)); |
2251 | if (q1_cal > 0) |
2252 | *z_val = ((*z_val) * 10000) / q1_cal; |
2253 | } |
2254 | |
2255 | static void wcd938x_wcd_mbhc_calc_impedance(struct snd_soc_component *component, |
2256 | uint32_t *zl, uint32_t *zr) |
2257 | { |
2258 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2259 | s16 reg0, reg1, reg2, reg3, reg4; |
2260 | int32_t z1L, z1R, z1Ls; |
2261 | int zMono, z_diff1, z_diff2; |
2262 | bool is_fsm_disable = false; |
2263 | struct wcd938x_mbhc_zdet_param zdet_param[] = { |
2264 | {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ |
2265 | {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ |
2266 | {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ |
2267 | {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ |
2268 | }; |
2269 | struct wcd938x_mbhc_zdet_param *zdet_param_ptr = NULL; |
2270 | s16 d1_a[][4] = { |
2271 | {0, 30, 90, 30}, |
2272 | {0, 30, 30, 5}, |
2273 | {0, 30, 30, 5}, |
2274 | {0, 30, 30, 5}, |
2275 | }; |
2276 | s16 *d1 = NULL; |
2277 | |
2278 | reg0 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN5); |
2279 | reg1 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN6); |
2280 | reg2 = snd_soc_component_read(component, WCD938X_ANA_MBHC_BTN7); |
2281 | reg3 = snd_soc_component_read(component, WCD938X_MBHC_CTL_CLK); |
2282 | reg4 = snd_soc_component_read(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL); |
2283 | |
2284 | if (snd_soc_component_read(component, WCD938X_ANA_MBHC_ELECT) & 0x80) { |
2285 | is_fsm_disable = true; |
2286 | regmap_update_bits(map: wcd938x->regmap, |
2287 | WCD938X_ANA_MBHC_ELECT, mask: 0x80, val: 0x00); |
2288 | } |
2289 | |
2290 | /* For NO-jack, disable L_DET_EN before Z-det measurements */ |
2291 | if (wcd938x->mbhc_cfg.hphl_swh) |
2292 | regmap_update_bits(map: wcd938x->regmap, |
2293 | WCD938X_ANA_MBHC_MECH, mask: 0x80, val: 0x00); |
2294 | |
2295 | /* Turn off 100k pull down on HPHL */ |
2296 | regmap_update_bits(map: wcd938x->regmap, |
2297 | WCD938X_ANA_MBHC_MECH, mask: 0x01, val: 0x00); |
2298 | |
2299 | /* Disable surge protection before impedance detection. |
2300 | * This is done to give correct value for high impedance. |
2301 | */ |
2302 | regmap_update_bits(map: wcd938x->regmap, |
2303 | WCD938X_HPH_SURGE_HPHLR_SURGE_EN, mask: 0xC0, val: 0x00); |
2304 | /* 1ms delay needed after disable surge protection */ |
2305 | usleep_range(min: 1000, max: 1010); |
2306 | |
2307 | /* First get impedance on Left */ |
2308 | d1 = d1_a[1]; |
2309 | zdet_param_ptr = &zdet_param[1]; |
2310 | wcd938x_mbhc_zdet_ramp(component, zdet_param: zdet_param_ptr, zl: &z1L, NULL, d1_a: d1); |
2311 | |
2312 | if (!WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) |
2313 | goto left_ch_impedance; |
2314 | |
2315 | /* Second ramp for left ch */ |
2316 | if (z1L < WCD938X_ZDET_VAL_32) { |
2317 | zdet_param_ptr = &zdet_param[0]; |
2318 | d1 = d1_a[0]; |
2319 | } else if ((z1L > WCD938X_ZDET_VAL_400) && |
2320 | (z1L <= WCD938X_ZDET_VAL_1200)) { |
2321 | zdet_param_ptr = &zdet_param[2]; |
2322 | d1 = d1_a[2]; |
2323 | } else if (z1L > WCD938X_ZDET_VAL_1200) { |
2324 | zdet_param_ptr = &zdet_param[3]; |
2325 | d1 = d1_a[3]; |
2326 | } |
2327 | wcd938x_mbhc_zdet_ramp(component, zdet_param: zdet_param_ptr, zl: &z1L, NULL, d1_a: d1); |
2328 | |
2329 | left_ch_impedance: |
2330 | if ((z1L == WCD938X_ZDET_FLOATING_IMPEDANCE) || |
2331 | (z1L > WCD938X_ZDET_VAL_100K)) { |
2332 | *zl = WCD938X_ZDET_FLOATING_IMPEDANCE; |
2333 | zdet_param_ptr = &zdet_param[1]; |
2334 | d1 = d1_a[1]; |
2335 | } else { |
2336 | *zl = z1L/1000; |
2337 | wcd938x_wcd_mbhc_qfuse_cal(component, z_val: zl, flag_l_r: 0); |
2338 | } |
2339 | dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n" , |
2340 | __func__, *zl); |
2341 | |
2342 | /* Start of right impedance ramp and calculation */ |
2343 | wcd938x_mbhc_zdet_ramp(component, zdet_param: zdet_param_ptr, NULL, zr: &z1R, d1_a: d1); |
2344 | if (WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { |
2345 | if (((z1R > WCD938X_ZDET_VAL_1200) && |
2346 | (zdet_param_ptr->noff == 0x6)) || |
2347 | ((*zl) != WCD938X_ZDET_FLOATING_IMPEDANCE)) |
2348 | goto right_ch_impedance; |
2349 | /* Second ramp for right ch */ |
2350 | if (z1R < WCD938X_ZDET_VAL_32) { |
2351 | zdet_param_ptr = &zdet_param[0]; |
2352 | d1 = d1_a[0]; |
2353 | } else if ((z1R > WCD938X_ZDET_VAL_400) && |
2354 | (z1R <= WCD938X_ZDET_VAL_1200)) { |
2355 | zdet_param_ptr = &zdet_param[2]; |
2356 | d1 = d1_a[2]; |
2357 | } else if (z1R > WCD938X_ZDET_VAL_1200) { |
2358 | zdet_param_ptr = &zdet_param[3]; |
2359 | d1 = d1_a[3]; |
2360 | } |
2361 | wcd938x_mbhc_zdet_ramp(component, zdet_param: zdet_param_ptr, NULL, zr: &z1R, d1_a: d1); |
2362 | } |
2363 | right_ch_impedance: |
2364 | if ((z1R == WCD938X_ZDET_FLOATING_IMPEDANCE) || |
2365 | (z1R > WCD938X_ZDET_VAL_100K)) { |
2366 | *zr = WCD938X_ZDET_FLOATING_IMPEDANCE; |
2367 | } else { |
2368 | *zr = z1R/1000; |
2369 | wcd938x_wcd_mbhc_qfuse_cal(component, z_val: zr, flag_l_r: 1); |
2370 | } |
2371 | dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n" , |
2372 | __func__, *zr); |
2373 | |
2374 | /* Mono/stereo detection */ |
2375 | if ((*zl == WCD938X_ZDET_FLOATING_IMPEDANCE) && |
2376 | (*zr == WCD938X_ZDET_FLOATING_IMPEDANCE)) { |
2377 | dev_dbg(component->dev, |
2378 | "%s: plug type is invalid or extension cable\n" , |
2379 | __func__); |
2380 | goto zdet_complete; |
2381 | } |
2382 | if ((*zl == WCD938X_ZDET_FLOATING_IMPEDANCE) || |
2383 | (*zr == WCD938X_ZDET_FLOATING_IMPEDANCE) || |
2384 | ((*zl < WCD_MONO_HS_MIN_THR) && (*zr > WCD_MONO_HS_MIN_THR)) || |
2385 | ((*zl > WCD_MONO_HS_MIN_THR) && (*zr < WCD_MONO_HS_MIN_THR))) { |
2386 | dev_dbg(component->dev, |
2387 | "%s: Mono plug type with one ch floating or shorted to GND\n" , |
2388 | __func__); |
2389 | wcd_mbhc_set_hph_type(mbhc: wcd938x->wcd_mbhc, hph_type: WCD_MBHC_HPH_MONO); |
2390 | goto zdet_complete; |
2391 | } |
2392 | snd_soc_component_write_field(component, WCD938X_HPH_R_ATEST, |
2393 | WCD938X_HPHPA_GND_OVR_MASK, val: 1); |
2394 | snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2, |
2395 | WCD938X_HPHPA_GND_R_MASK, val: 1); |
2396 | if (*zl < (WCD938X_ZDET_VAL_32/1000)) |
2397 | wcd938x_mbhc_zdet_ramp(component, zdet_param: &zdet_param[0], zl: &z1Ls, NULL, d1_a: d1); |
2398 | else |
2399 | wcd938x_mbhc_zdet_ramp(component, zdet_param: &zdet_param[1], zl: &z1Ls, NULL, d1_a: d1); |
2400 | snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2, |
2401 | WCD938X_HPHPA_GND_R_MASK, val: 0); |
2402 | snd_soc_component_write_field(component, WCD938X_HPH_R_ATEST, |
2403 | WCD938X_HPHPA_GND_OVR_MASK, val: 0); |
2404 | z1Ls /= 1000; |
2405 | wcd938x_wcd_mbhc_qfuse_cal(component, z_val: &z1Ls, flag_l_r: 0); |
2406 | /* Parallel of left Z and 9 ohm pull down resistor */ |
2407 | zMono = ((*zl) * 9) / ((*zl) + 9); |
2408 | z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls); |
2409 | z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl)); |
2410 | if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) { |
2411 | dev_dbg(component->dev, "%s: stereo plug type detected\n" , |
2412 | __func__); |
2413 | wcd_mbhc_set_hph_type(mbhc: wcd938x->wcd_mbhc, hph_type: WCD_MBHC_HPH_STEREO); |
2414 | } else { |
2415 | dev_dbg(component->dev, "%s: MONO plug type detected\n" , |
2416 | __func__); |
2417 | wcd_mbhc_set_hph_type(mbhc: wcd938x->wcd_mbhc, hph_type: WCD_MBHC_HPH_MONO); |
2418 | } |
2419 | |
2420 | /* Enable surge protection again after impedance detection */ |
2421 | regmap_update_bits(map: wcd938x->regmap, |
2422 | WCD938X_HPH_SURGE_HPHLR_SURGE_EN, mask: 0xC0, val: 0xC0); |
2423 | zdet_complete: |
2424 | snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN5, val: reg0); |
2425 | snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN6, val: reg1); |
2426 | snd_soc_component_write(component, WCD938X_ANA_MBHC_BTN7, val: reg2); |
2427 | /* Turn on 100k pull down on HPHL */ |
2428 | regmap_update_bits(map: wcd938x->regmap, |
2429 | WCD938X_ANA_MBHC_MECH, mask: 0x01, val: 0x01); |
2430 | |
2431 | /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ |
2432 | if (wcd938x->mbhc_cfg.hphl_swh) |
2433 | regmap_update_bits(map: wcd938x->regmap, |
2434 | WCD938X_ANA_MBHC_MECH, mask: 0x80, val: 0x80); |
2435 | |
2436 | snd_soc_component_write(component, WCD938X_MBHC_NEW_ZDET_ANA_CTL, val: reg4); |
2437 | snd_soc_component_write(component, WCD938X_MBHC_CTL_CLK, val: reg3); |
2438 | if (is_fsm_disable) |
2439 | regmap_update_bits(map: wcd938x->regmap, |
2440 | WCD938X_ANA_MBHC_ELECT, mask: 0x80, val: 0x80); |
2441 | } |
2442 | |
2443 | static void wcd938x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, |
2444 | bool enable) |
2445 | { |
2446 | if (enable) { |
2447 | snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH, |
2448 | WCD938X_MBHC_HSG_PULLUP_COMP_EN, val: 1); |
2449 | snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH, |
2450 | WCD938X_MBHC_GND_DET_EN_MASK, val: 1); |
2451 | } else { |
2452 | snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH, |
2453 | WCD938X_MBHC_GND_DET_EN_MASK, val: 0); |
2454 | snd_soc_component_write_field(component, WCD938X_ANA_MBHC_MECH, |
2455 | WCD938X_MBHC_HSG_PULLUP_COMP_EN, val: 0); |
2456 | } |
2457 | } |
2458 | |
2459 | static void wcd938x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, |
2460 | bool enable) |
2461 | { |
2462 | snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2, |
2463 | WCD938X_HPHPA_GND_R_MASK, val: enable); |
2464 | snd_soc_component_write_field(component, WCD938X_HPH_PA_CTL2, |
2465 | WCD938X_HPHPA_GND_L_MASK, val: enable); |
2466 | } |
2467 | |
2468 | static void wcd938x_mbhc_moisture_config(struct snd_soc_component *component) |
2469 | { |
2470 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2471 | |
2472 | if (wcd938x->mbhc_cfg.moist_rref == R_OFF) { |
2473 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2474 | WCD938X_M_RTH_CTL_MASK, val: R_OFF); |
2475 | return; |
2476 | } |
2477 | |
2478 | /* Do not enable moisture detection if jack type is NC */ |
2479 | if (!wcd938x->mbhc_cfg.hphl_swh) { |
2480 | dev_dbg(component->dev, "%s: disable moisture detection for NC\n" , |
2481 | __func__); |
2482 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2483 | WCD938X_M_RTH_CTL_MASK, val: R_OFF); |
2484 | return; |
2485 | } |
2486 | |
2487 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2488 | WCD938X_M_RTH_CTL_MASK, val: wcd938x->mbhc_cfg.moist_rref); |
2489 | } |
2490 | |
2491 | static void wcd938x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable) |
2492 | { |
2493 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2494 | |
2495 | if (enable) |
2496 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2497 | WCD938X_M_RTH_CTL_MASK, val: wcd938x->mbhc_cfg.moist_rref); |
2498 | else |
2499 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2500 | WCD938X_M_RTH_CTL_MASK, val: R_OFF); |
2501 | } |
2502 | |
2503 | static bool wcd938x_mbhc_get_moisture_status(struct snd_soc_component *component) |
2504 | { |
2505 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2506 | bool ret = false; |
2507 | |
2508 | if (wcd938x->mbhc_cfg.moist_rref == R_OFF) { |
2509 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2510 | WCD938X_M_RTH_CTL_MASK, val: R_OFF); |
2511 | goto done; |
2512 | } |
2513 | |
2514 | /* Do not enable moisture detection if jack type is NC */ |
2515 | if (!wcd938x->mbhc_cfg.hphl_swh) { |
2516 | dev_dbg(component->dev, "%s: disable moisture detection for NC\n" , |
2517 | __func__); |
2518 | snd_soc_component_write_field(component, WCD938X_MBHC_NEW_CTL_2, |
2519 | WCD938X_M_RTH_CTL_MASK, val: R_OFF); |
2520 | goto done; |
2521 | } |
2522 | |
2523 | /* |
2524 | * If moisture_en is already enabled, then skip to plug type |
2525 | * detection. |
2526 | */ |
2527 | if (snd_soc_component_read_field(component, WCD938X_MBHC_NEW_CTL_2, WCD938X_M_RTH_CTL_MASK)) |
2528 | goto done; |
2529 | |
2530 | wcd938x_mbhc_moisture_detect_en(component, enable: true); |
2531 | /* Read moisture comparator status */ |
2532 | ret = ((snd_soc_component_read(component, WCD938X_MBHC_NEW_FSM_STATUS) |
2533 | & 0x20) ? 0 : 1); |
2534 | |
2535 | done: |
2536 | return ret; |
2537 | |
2538 | } |
2539 | |
2540 | static void wcd938x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component, |
2541 | bool enable) |
2542 | { |
2543 | snd_soc_component_write_field(component, |
2544 | WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, |
2545 | WCD938X_MOISTURE_EN_POLLING_MASK, val: enable); |
2546 | } |
2547 | |
2548 | static const struct wcd_mbhc_cb mbhc_cb = { |
2549 | .clk_setup = wcd938x_mbhc_clk_setup, |
2550 | .mbhc_bias = wcd938x_mbhc_mbhc_bias_control, |
2551 | .set_btn_thr = wcd938x_mbhc_program_btn_thr, |
2552 | .micbias_enable_status = wcd938x_mbhc_micb_en_status, |
2553 | .hph_pull_up_control_v2 = wcd938x_mbhc_hph_l_pull_up_control, |
2554 | .mbhc_micbias_control = wcd938x_mbhc_request_micbias, |
2555 | .mbhc_micb_ramp_control = wcd938x_mbhc_micb_ramp_control, |
2556 | .mbhc_micb_ctrl_thr_mic = wcd938x_mbhc_micb_ctrl_threshold_mic, |
2557 | .compute_impedance = wcd938x_wcd_mbhc_calc_impedance, |
2558 | .mbhc_gnd_det_ctrl = wcd938x_mbhc_gnd_det_ctrl, |
2559 | .hph_pull_down_ctrl = wcd938x_mbhc_hph_pull_down_ctrl, |
2560 | .mbhc_moisture_config = wcd938x_mbhc_moisture_config, |
2561 | .mbhc_get_moisture_status = wcd938x_mbhc_get_moisture_status, |
2562 | .mbhc_moisture_polling_ctrl = wcd938x_mbhc_moisture_polling_ctrl, |
2563 | .mbhc_moisture_detect_en = wcd938x_mbhc_moisture_detect_en, |
2564 | }; |
2565 | |
2566 | static int wcd938x_get_hph_type(struct snd_kcontrol *kcontrol, |
2567 | struct snd_ctl_elem_value *ucontrol) |
2568 | { |
2569 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
2570 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2571 | |
2572 | ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(mbhc: wcd938x->wcd_mbhc); |
2573 | |
2574 | return 0; |
2575 | } |
2576 | |
2577 | static int wcd938x_hph_impedance_get(struct snd_kcontrol *kcontrol, |
2578 | struct snd_ctl_elem_value *ucontrol) |
2579 | { |
2580 | uint32_t zl, zr; |
2581 | bool hphr; |
2582 | struct soc_mixer_control *mc; |
2583 | struct snd_soc_component *component = |
2584 | snd_soc_kcontrol_component(kcontrol); |
2585 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2586 | |
2587 | mc = (struct soc_mixer_control *)(kcontrol->private_value); |
2588 | hphr = mc->shift; |
2589 | wcd_mbhc_get_impedance(mbhc: wcd938x->wcd_mbhc, zl: &zl, zr: &zr); |
2590 | dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n" , __func__, zl, zr); |
2591 | ucontrol->value.integer.value[0] = hphr ? zr : zl; |
2592 | |
2593 | return 0; |
2594 | } |
2595 | |
2596 | static const struct snd_kcontrol_new hph_type_detect_controls[] = { |
2597 | SOC_SINGLE_EXT("HPH Type" , 0, 0, WCD_MBHC_HPH_STEREO, 0, |
2598 | wcd938x_get_hph_type, NULL), |
2599 | }; |
2600 | |
2601 | static const struct snd_kcontrol_new impedance_detect_controls[] = { |
2602 | SOC_SINGLE_EXT("HPHL Impedance" , 0, 0, INT_MAX, 0, |
2603 | wcd938x_hph_impedance_get, NULL), |
2604 | SOC_SINGLE_EXT("HPHR Impedance" , 0, 1, INT_MAX, 0, |
2605 | wcd938x_hph_impedance_get, NULL), |
2606 | }; |
2607 | |
2608 | static int wcd938x_mbhc_init(struct snd_soc_component *component) |
2609 | { |
2610 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2611 | struct wcd_mbhc_intr *intr_ids = &wcd938x->intr_ids; |
2612 | |
2613 | intr_ids->mbhc_sw_intr = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2614 | irq: WCD938X_IRQ_MBHC_SW_DET); |
2615 | intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2616 | irq: WCD938X_IRQ_MBHC_BUTTON_PRESS_DET); |
2617 | intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2618 | irq: WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET); |
2619 | intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2620 | irq: WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET); |
2621 | intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2622 | irq: WCD938X_IRQ_MBHC_ELECT_INS_REM_DET); |
2623 | intr_ids->hph_left_ocp = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2624 | irq: WCD938X_IRQ_HPHL_OCP_INT); |
2625 | intr_ids->hph_right_ocp = regmap_irq_get_virq(data: wcd938x->irq_chip, |
2626 | irq: WCD938X_IRQ_HPHR_OCP_INT); |
2627 | |
2628 | wcd938x->wcd_mbhc = wcd_mbhc_init(component, mbhc_cb: &mbhc_cb, mbhc_cdc_intr_ids: intr_ids, fields: wcd_mbhc_fields, impedance_det_en: true); |
2629 | if (IS_ERR(ptr: wcd938x->wcd_mbhc)) |
2630 | return PTR_ERR(ptr: wcd938x->wcd_mbhc); |
2631 | |
2632 | snd_soc_add_component_controls(component, controls: impedance_detect_controls, |
2633 | ARRAY_SIZE(impedance_detect_controls)); |
2634 | snd_soc_add_component_controls(component, controls: hph_type_detect_controls, |
2635 | ARRAY_SIZE(hph_type_detect_controls)); |
2636 | |
2637 | return 0; |
2638 | } |
2639 | |
2640 | static void wcd938x_mbhc_deinit(struct snd_soc_component *component) |
2641 | { |
2642 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
2643 | |
2644 | wcd_mbhc_deinit(mbhc: wcd938x->wcd_mbhc); |
2645 | } |
2646 | |
2647 | /* END MBHC */ |
2648 | |
2649 | static const struct snd_kcontrol_new wcd938x_snd_controls[] = { |
2650 | SOC_SINGLE_EXT("HPHL_COMP Switch" , WCD938X_COMP_L, 0, 1, 0, |
2651 | wcd938x_get_compander, wcd938x_set_compander), |
2652 | SOC_SINGLE_EXT("HPHR_COMP Switch" , WCD938X_COMP_R, 1, 1, 0, |
2653 | wcd938x_get_compander, wcd938x_set_compander), |
2654 | SOC_SINGLE_EXT("HPHL Switch" , WCD938X_HPH_L, 0, 1, 0, |
2655 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2656 | SOC_SINGLE_EXT("HPHR Switch" , WCD938X_HPH_R, 0, 1, 0, |
2657 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2658 | SOC_SINGLE_EXT("CLSH Switch" , WCD938X_CLSH, 0, 1, 0, |
2659 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2660 | SOC_SINGLE_EXT("LO Switch" , WCD938X_LO, 0, 1, 0, |
2661 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2662 | SOC_SINGLE_EXT("DSD_L Switch" , WCD938X_DSD_L, 0, 1, 0, |
2663 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2664 | SOC_SINGLE_EXT("DSD_R Switch" , WCD938X_DSD_R, 0, 1, 0, |
2665 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2666 | SOC_SINGLE_TLV("HPHL Volume" , WCD938X_HPH_L_EN, 0, 0x18, 1, line_gain), |
2667 | SOC_SINGLE_TLV("HPHR Volume" , WCD938X_HPH_R_EN, 0, 0x18, 1, line_gain), |
2668 | WCD938X_EAR_PA_GAIN_TLV("EAR_PA Volume" , WCD938X_ANA_EAR_COMPANDER_CTL, |
2669 | 2, 0x10, 0, ear_pa_gain), |
2670 | SOC_SINGLE_EXT("ADC1 Switch" , WCD938X_ADC1, 1, 1, 0, |
2671 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2672 | SOC_SINGLE_EXT("ADC2 Switch" , WCD938X_ADC2, 1, 1, 0, |
2673 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2674 | SOC_SINGLE_EXT("ADC3 Switch" , WCD938X_ADC3, 1, 1, 0, |
2675 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2676 | SOC_SINGLE_EXT("ADC4 Switch" , WCD938X_ADC4, 1, 1, 0, |
2677 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2678 | SOC_SINGLE_EXT("DMIC0 Switch" , WCD938X_DMIC0, 1, 1, 0, |
2679 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2680 | SOC_SINGLE_EXT("DMIC1 Switch" , WCD938X_DMIC1, 1, 1, 0, |
2681 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2682 | SOC_SINGLE_EXT("MBHC Switch" , WCD938X_MBHC, 1, 1, 0, |
2683 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2684 | SOC_SINGLE_EXT("DMIC2 Switch" , WCD938X_DMIC2, 1, 1, 0, |
2685 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2686 | SOC_SINGLE_EXT("DMIC3 Switch" , WCD938X_DMIC3, 1, 1, 0, |
2687 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2688 | SOC_SINGLE_EXT("DMIC4 Switch" , WCD938X_DMIC4, 1, 1, 0, |
2689 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2690 | SOC_SINGLE_EXT("DMIC5 Switch" , WCD938X_DMIC5, 1, 1, 0, |
2691 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2692 | SOC_SINGLE_EXT("DMIC6 Switch" , WCD938X_DMIC6, 1, 1, 0, |
2693 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2694 | SOC_SINGLE_EXT("DMIC7 Switch" , WCD938X_DMIC7, 1, 1, 0, |
2695 | wcd938x_get_swr_port, wcd938x_set_swr_port), |
2696 | SOC_SINGLE_EXT("LDOH Enable Switch" , SND_SOC_NOPM, 0, 1, 0, |
2697 | wcd938x_ldoh_get, wcd938x_ldoh_put), |
2698 | SOC_SINGLE_EXT("ADC2_BCS Disable Switch" , SND_SOC_NOPM, 0, 1, 0, |
2699 | wcd938x_bcs_get, wcd938x_bcs_put), |
2700 | |
2701 | SOC_SINGLE_TLV("ADC1 Volume" , WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain), |
2702 | SOC_SINGLE_TLV("ADC2 Volume" , WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain), |
2703 | SOC_SINGLE_TLV("ADC3 Volume" , WCD938X_ANA_TX_CH3, 0, 20, 0, analog_gain), |
2704 | SOC_SINGLE_TLV("ADC4 Volume" , WCD938X_ANA_TX_CH4, 0, 20, 0, analog_gain), |
2705 | }; |
2706 | |
2707 | static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { |
2708 | |
2709 | /*input widgets*/ |
2710 | SND_SOC_DAPM_INPUT("AMIC1" ), |
2711 | SND_SOC_DAPM_INPUT("AMIC2" ), |
2712 | SND_SOC_DAPM_INPUT("AMIC3" ), |
2713 | SND_SOC_DAPM_INPUT("AMIC4" ), |
2714 | SND_SOC_DAPM_INPUT("AMIC5" ), |
2715 | SND_SOC_DAPM_INPUT("AMIC6" ), |
2716 | SND_SOC_DAPM_INPUT("AMIC7" ), |
2717 | SND_SOC_DAPM_MIC("Analog Mic1" , NULL), |
2718 | SND_SOC_DAPM_MIC("Analog Mic2" , NULL), |
2719 | SND_SOC_DAPM_MIC("Analog Mic3" , NULL), |
2720 | SND_SOC_DAPM_MIC("Analog Mic4" , NULL), |
2721 | SND_SOC_DAPM_MIC("Analog Mic5" , NULL), |
2722 | |
2723 | /*tx widgets*/ |
2724 | SND_SOC_DAPM_ADC_E("ADC1" , NULL, SND_SOC_NOPM, 0, 0, |
2725 | wcd938x_codec_enable_adc, |
2726 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2727 | SND_SOC_DAPM_ADC_E("ADC2" , NULL, SND_SOC_NOPM, 1, 0, |
2728 | wcd938x_codec_enable_adc, |
2729 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2730 | SND_SOC_DAPM_ADC_E("ADC3" , NULL, SND_SOC_NOPM, 2, 0, |
2731 | wcd938x_codec_enable_adc, |
2732 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2733 | SND_SOC_DAPM_ADC_E("ADC4" , NULL, SND_SOC_NOPM, 3, 0, |
2734 | wcd938x_codec_enable_adc, |
2735 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2736 | SND_SOC_DAPM_ADC_E("DMIC1" , NULL, SND_SOC_NOPM, 0, 0, |
2737 | wcd938x_codec_enable_dmic, |
2738 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2739 | SND_SOC_DAPM_ADC_E("DMIC2" , NULL, SND_SOC_NOPM, 1, 0, |
2740 | wcd938x_codec_enable_dmic, |
2741 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2742 | SND_SOC_DAPM_ADC_E("DMIC3" , NULL, SND_SOC_NOPM, 2, 0, |
2743 | wcd938x_codec_enable_dmic, |
2744 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2745 | SND_SOC_DAPM_ADC_E("DMIC4" , NULL, SND_SOC_NOPM, 3, 0, |
2746 | wcd938x_codec_enable_dmic, |
2747 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2748 | SND_SOC_DAPM_ADC_E("DMIC5" , NULL, SND_SOC_NOPM, 4, 0, |
2749 | wcd938x_codec_enable_dmic, |
2750 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2751 | SND_SOC_DAPM_ADC_E("DMIC6" , NULL, SND_SOC_NOPM, 5, 0, |
2752 | wcd938x_codec_enable_dmic, |
2753 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2754 | SND_SOC_DAPM_ADC_E("DMIC7" , NULL, SND_SOC_NOPM, 6, 0, |
2755 | wcd938x_codec_enable_dmic, |
2756 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2757 | SND_SOC_DAPM_ADC_E("DMIC8" , NULL, SND_SOC_NOPM, 7, 0, |
2758 | wcd938x_codec_enable_dmic, |
2759 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2760 | |
2761 | SND_SOC_DAPM_MIXER_E("ADC1 REQ" , SND_SOC_NOPM, 0, 0, |
2762 | NULL, 0, wcd938x_adc_enable_req, |
2763 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2764 | SND_SOC_DAPM_MIXER_E("ADC2 REQ" , SND_SOC_NOPM, 1, 0, |
2765 | NULL, 0, wcd938x_adc_enable_req, |
2766 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2767 | SND_SOC_DAPM_MIXER_E("ADC3 REQ" , SND_SOC_NOPM, 2, 0, |
2768 | NULL, 0, wcd938x_adc_enable_req, |
2769 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2770 | SND_SOC_DAPM_MIXER_E("ADC4 REQ" , SND_SOC_NOPM, 3, 0, NULL, 0, |
2771 | wcd938x_adc_enable_req, |
2772 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2773 | |
2774 | SND_SOC_DAPM_MUX("ADC2 MUX" , SND_SOC_NOPM, 0, 0, &tx_adc2_mux), |
2775 | SND_SOC_DAPM_MUX("ADC3 MUX" , SND_SOC_NOPM, 0, 0, &tx_adc3_mux), |
2776 | SND_SOC_DAPM_MUX("ADC4 MUX" , SND_SOC_NOPM, 0, 0, &tx_adc4_mux), |
2777 | SND_SOC_DAPM_MUX("HDR12 MUX" , SND_SOC_NOPM, 0, 0, &tx_hdr12_mux), |
2778 | SND_SOC_DAPM_MUX("HDR34 MUX" , SND_SOC_NOPM, 0, 0, &tx_hdr34_mux), |
2779 | |
2780 | /*tx mixers*/ |
2781 | SND_SOC_DAPM_MIXER_E("ADC1_MIXER" , SND_SOC_NOPM, 0, 0, adc1_switch, |
2782 | ARRAY_SIZE(adc1_switch), wcd938x_tx_swr_ctrl, |
2783 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2784 | SND_SOC_DAPM_MIXER_E("ADC2_MIXER" , SND_SOC_NOPM, 0, 0, adc2_switch, |
2785 | ARRAY_SIZE(adc2_switch), wcd938x_tx_swr_ctrl, |
2786 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2787 | SND_SOC_DAPM_MIXER_E("ADC3_MIXER" , SND_SOC_NOPM, 0, 0, adc3_switch, |
2788 | ARRAY_SIZE(adc3_switch), wcd938x_tx_swr_ctrl, |
2789 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2790 | SND_SOC_DAPM_MIXER_E("ADC4_MIXER" , SND_SOC_NOPM, 0, 0, adc4_switch, |
2791 | ARRAY_SIZE(adc4_switch), wcd938x_tx_swr_ctrl, |
2792 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2793 | SND_SOC_DAPM_MIXER_E("DMIC1_MIXER" , SND_SOC_NOPM, 0, 0, dmic1_switch, |
2794 | ARRAY_SIZE(dmic1_switch), wcd938x_tx_swr_ctrl, |
2795 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2796 | SND_SOC_DAPM_MIXER_E("DMIC2_MIXER" , SND_SOC_NOPM, 0, 0, dmic2_switch, |
2797 | ARRAY_SIZE(dmic2_switch), wcd938x_tx_swr_ctrl, |
2798 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2799 | SND_SOC_DAPM_MIXER_E("DMIC3_MIXER" , SND_SOC_NOPM, 0, 0, dmic3_switch, |
2800 | ARRAY_SIZE(dmic3_switch), wcd938x_tx_swr_ctrl, |
2801 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2802 | SND_SOC_DAPM_MIXER_E("DMIC4_MIXER" , SND_SOC_NOPM, 0, 0, dmic4_switch, |
2803 | ARRAY_SIZE(dmic4_switch), wcd938x_tx_swr_ctrl, |
2804 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2805 | SND_SOC_DAPM_MIXER_E("DMIC5_MIXER" , SND_SOC_NOPM, 0, 0, dmic5_switch, |
2806 | ARRAY_SIZE(dmic5_switch), wcd938x_tx_swr_ctrl, |
2807 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2808 | SND_SOC_DAPM_MIXER_E("DMIC6_MIXER" , SND_SOC_NOPM, 0, 0, dmic6_switch, |
2809 | ARRAY_SIZE(dmic6_switch), wcd938x_tx_swr_ctrl, |
2810 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2811 | SND_SOC_DAPM_MIXER_E("DMIC7_MIXER" , SND_SOC_NOPM, 0, 0, dmic7_switch, |
2812 | ARRAY_SIZE(dmic7_switch), wcd938x_tx_swr_ctrl, |
2813 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2814 | SND_SOC_DAPM_MIXER_E("DMIC8_MIXER" , SND_SOC_NOPM, 0, 0, dmic8_switch, |
2815 | ARRAY_SIZE(dmic8_switch), wcd938x_tx_swr_ctrl, |
2816 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
2817 | /* micbias widgets*/ |
2818 | SND_SOC_DAPM_SUPPLY("MIC BIAS1" , SND_SOC_NOPM, MIC_BIAS_1, 0, |
2819 | wcd938x_codec_enable_micbias, |
2820 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2821 | SND_SOC_DAPM_POST_PMD), |
2822 | SND_SOC_DAPM_SUPPLY("MIC BIAS2" , SND_SOC_NOPM, MIC_BIAS_2, 0, |
2823 | wcd938x_codec_enable_micbias, |
2824 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2825 | SND_SOC_DAPM_POST_PMD), |
2826 | SND_SOC_DAPM_SUPPLY("MIC BIAS3" , SND_SOC_NOPM, MIC_BIAS_3, 0, |
2827 | wcd938x_codec_enable_micbias, |
2828 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2829 | SND_SOC_DAPM_POST_PMD), |
2830 | SND_SOC_DAPM_SUPPLY("MIC BIAS4" , SND_SOC_NOPM, MIC_BIAS_4, 0, |
2831 | wcd938x_codec_enable_micbias, |
2832 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2833 | SND_SOC_DAPM_POST_PMD), |
2834 | |
2835 | /* micbias pull up widgets*/ |
2836 | SND_SOC_DAPM_SUPPLY("VA MIC BIAS1" , SND_SOC_NOPM, MIC_BIAS_1, 0, |
2837 | wcd938x_codec_enable_micbias_pullup, |
2838 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2839 | SND_SOC_DAPM_POST_PMD), |
2840 | SND_SOC_DAPM_SUPPLY("VA MIC BIAS2" , SND_SOC_NOPM, MIC_BIAS_2, 0, |
2841 | wcd938x_codec_enable_micbias_pullup, |
2842 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2843 | SND_SOC_DAPM_POST_PMD), |
2844 | SND_SOC_DAPM_SUPPLY("VA MIC BIAS3" , SND_SOC_NOPM, MIC_BIAS_3, 0, |
2845 | wcd938x_codec_enable_micbias_pullup, |
2846 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2847 | SND_SOC_DAPM_POST_PMD), |
2848 | SND_SOC_DAPM_SUPPLY("VA MIC BIAS4" , SND_SOC_NOPM, MIC_BIAS_4, 0, |
2849 | wcd938x_codec_enable_micbias_pullup, |
2850 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2851 | SND_SOC_DAPM_POST_PMD), |
2852 | |
2853 | /*output widgets tx*/ |
2854 | SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT" ), |
2855 | SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT" ), |
2856 | SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT" ), |
2857 | SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT" ), |
2858 | SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT" ), |
2859 | SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT" ), |
2860 | SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT" ), |
2861 | SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT" ), |
2862 | SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT" ), |
2863 | SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT" ), |
2864 | SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT" ), |
2865 | SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT" ), |
2866 | |
2867 | SND_SOC_DAPM_INPUT("IN1_HPHL" ), |
2868 | SND_SOC_DAPM_INPUT("IN2_HPHR" ), |
2869 | SND_SOC_DAPM_INPUT("IN3_AUX" ), |
2870 | |
2871 | /*rx widgets*/ |
2872 | SND_SOC_DAPM_PGA_E("EAR PGA" , WCD938X_ANA_EAR, 7, 0, NULL, 0, |
2873 | wcd938x_codec_enable_ear_pa, |
2874 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2875 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2876 | SND_SOC_DAPM_PGA_E("AUX PGA" , WCD938X_AUX_AUXPA, 7, 0, NULL, 0, |
2877 | wcd938x_codec_enable_aux_pa, |
2878 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2879 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2880 | SND_SOC_DAPM_PGA_E("HPHL PGA" , WCD938X_ANA_HPH, 7, 0, NULL, 0, |
2881 | wcd938x_codec_enable_hphl_pa, |
2882 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2883 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2884 | SND_SOC_DAPM_PGA_E("HPHR PGA" , WCD938X_ANA_HPH, 6, 0, NULL, 0, |
2885 | wcd938x_codec_enable_hphr_pa, |
2886 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2887 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2888 | |
2889 | SND_SOC_DAPM_DAC_E("RDAC1" , NULL, SND_SOC_NOPM, 0, 0, |
2890 | wcd938x_codec_hphl_dac_event, |
2891 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2892 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2893 | SND_SOC_DAPM_DAC_E("RDAC2" , NULL, SND_SOC_NOPM, 0, 0, |
2894 | wcd938x_codec_hphr_dac_event, |
2895 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2896 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2897 | SND_SOC_DAPM_DAC_E("RDAC3" , NULL, SND_SOC_NOPM, 0, 0, |
2898 | wcd938x_codec_ear_dac_event, |
2899 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2900 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2901 | SND_SOC_DAPM_DAC_E("RDAC4" , NULL, SND_SOC_NOPM, 0, 0, |
2902 | wcd938x_codec_aux_dac_event, |
2903 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2904 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), |
2905 | |
2906 | SND_SOC_DAPM_MUX("RDAC3_MUX" , SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), |
2907 | |
2908 | SND_SOC_DAPM_SUPPLY("VDD_BUCK" , SND_SOC_NOPM, 0, 0, NULL, 0), |
2909 | SND_SOC_DAPM_SUPPLY("RXCLK" , SND_SOC_NOPM, 0, 0, |
2910 | wcd938x_codec_enable_rxclk, |
2911 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
2912 | SND_SOC_DAPM_POST_PMD), |
2913 | |
2914 | SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT" , 1, SND_SOC_NOPM, 0, 0, NULL, 0), |
2915 | |
2916 | SND_SOC_DAPM_MIXER_E("RX1" , SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), |
2917 | SND_SOC_DAPM_MIXER_E("RX2" , SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), |
2918 | SND_SOC_DAPM_MIXER_E("RX3" , SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), |
2919 | |
2920 | /* rx mixer widgets*/ |
2921 | SND_SOC_DAPM_MIXER("EAR_RDAC" , SND_SOC_NOPM, 0, 0, |
2922 | ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), |
2923 | SND_SOC_DAPM_MIXER("AUX_RDAC" , SND_SOC_NOPM, 0, 0, |
2924 | aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)), |
2925 | SND_SOC_DAPM_MIXER("HPHL_RDAC" , SND_SOC_NOPM, 0, 0, |
2926 | hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), |
2927 | SND_SOC_DAPM_MIXER("HPHR_RDAC" , SND_SOC_NOPM, 0, 0, |
2928 | hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), |
2929 | |
2930 | /*output widgets rx*/ |
2931 | SND_SOC_DAPM_OUTPUT("EAR" ), |
2932 | SND_SOC_DAPM_OUTPUT("AUX" ), |
2933 | SND_SOC_DAPM_OUTPUT("HPHL" ), |
2934 | SND_SOC_DAPM_OUTPUT("HPHR" ), |
2935 | |
2936 | }; |
2937 | |
2938 | static const struct snd_soc_dapm_route wcd938x_audio_map[] = { |
2939 | {"ADC1_OUTPUT" , NULL, "ADC1_MIXER" }, |
2940 | {"ADC1_MIXER" , "Switch" , "ADC1 REQ" }, |
2941 | {"ADC1 REQ" , NULL, "ADC1" }, |
2942 | {"ADC1" , NULL, "AMIC1" }, |
2943 | |
2944 | {"ADC2_OUTPUT" , NULL, "ADC2_MIXER" }, |
2945 | {"ADC2_MIXER" , "Switch" , "ADC2 REQ" }, |
2946 | {"ADC2 REQ" , NULL, "ADC2" }, |
2947 | {"ADC2" , NULL, "HDR12 MUX" }, |
2948 | {"HDR12 MUX" , "NO_HDR12" , "ADC2 MUX" }, |
2949 | {"HDR12 MUX" , "HDR12" , "AMIC1" }, |
2950 | {"ADC2 MUX" , "INP3" , "AMIC3" }, |
2951 | {"ADC2 MUX" , "INP2" , "AMIC2" }, |
2952 | |
2953 | {"ADC3_OUTPUT" , NULL, "ADC3_MIXER" }, |
2954 | {"ADC3_MIXER" , "Switch" , "ADC3 REQ" }, |
2955 | {"ADC3 REQ" , NULL, "ADC3" }, |
2956 | {"ADC3" , NULL, "HDR34 MUX" }, |
2957 | {"HDR34 MUX" , "NO_HDR34" , "ADC3 MUX" }, |
2958 | {"HDR34 MUX" , "HDR34" , "AMIC5" }, |
2959 | {"ADC3 MUX" , "INP4" , "AMIC4" }, |
2960 | {"ADC3 MUX" , "INP6" , "AMIC6" }, |
2961 | |
2962 | {"ADC4_OUTPUT" , NULL, "ADC4_MIXER" }, |
2963 | {"ADC4_MIXER" , "Switch" , "ADC4 REQ" }, |
2964 | {"ADC4 REQ" , NULL, "ADC4" }, |
2965 | {"ADC4" , NULL, "ADC4 MUX" }, |
2966 | {"ADC4 MUX" , "INP5" , "AMIC5" }, |
2967 | {"ADC4 MUX" , "INP7" , "AMIC7" }, |
2968 | |
2969 | {"DMIC1_OUTPUT" , NULL, "DMIC1_MIXER" }, |
2970 | {"DMIC1_MIXER" , "Switch" , "DMIC1" }, |
2971 | |
2972 | {"DMIC2_OUTPUT" , NULL, "DMIC2_MIXER" }, |
2973 | {"DMIC2_MIXER" , "Switch" , "DMIC2" }, |
2974 | |
2975 | {"DMIC3_OUTPUT" , NULL, "DMIC3_MIXER" }, |
2976 | {"DMIC3_MIXER" , "Switch" , "DMIC3" }, |
2977 | |
2978 | {"DMIC4_OUTPUT" , NULL, "DMIC4_MIXER" }, |
2979 | {"DMIC4_MIXER" , "Switch" , "DMIC4" }, |
2980 | |
2981 | {"DMIC5_OUTPUT" , NULL, "DMIC5_MIXER" }, |
2982 | {"DMIC5_MIXER" , "Switch" , "DMIC5" }, |
2983 | |
2984 | {"DMIC6_OUTPUT" , NULL, "DMIC6_MIXER" }, |
2985 | {"DMIC6_MIXER" , "Switch" , "DMIC6" }, |
2986 | |
2987 | {"DMIC7_OUTPUT" , NULL, "DMIC7_MIXER" }, |
2988 | {"DMIC7_MIXER" , "Switch" , "DMIC7" }, |
2989 | |
2990 | {"DMIC8_OUTPUT" , NULL, "DMIC8_MIXER" }, |
2991 | {"DMIC8_MIXER" , "Switch" , "DMIC8" }, |
2992 | |
2993 | {"IN1_HPHL" , NULL, "VDD_BUCK" }, |
2994 | {"IN1_HPHL" , NULL, "CLS_H_PORT" }, |
2995 | |
2996 | {"RX1" , NULL, "IN1_HPHL" }, |
2997 | {"RX1" , NULL, "RXCLK" }, |
2998 | {"RDAC1" , NULL, "RX1" }, |
2999 | {"HPHL_RDAC" , "Switch" , "RDAC1" }, |
3000 | {"HPHL PGA" , NULL, "HPHL_RDAC" }, |
3001 | {"HPHL" , NULL, "HPHL PGA" }, |
3002 | |
3003 | {"IN2_HPHR" , NULL, "VDD_BUCK" }, |
3004 | {"IN2_HPHR" , NULL, "CLS_H_PORT" }, |
3005 | {"RX2" , NULL, "IN2_HPHR" }, |
3006 | {"RDAC2" , NULL, "RX2" }, |
3007 | {"RX2" , NULL, "RXCLK" }, |
3008 | {"HPHR_RDAC" , "Switch" , "RDAC2" }, |
3009 | {"HPHR PGA" , NULL, "HPHR_RDAC" }, |
3010 | {"HPHR" , NULL, "HPHR PGA" }, |
3011 | |
3012 | {"IN3_AUX" , NULL, "VDD_BUCK" }, |
3013 | {"IN3_AUX" , NULL, "CLS_H_PORT" }, |
3014 | {"RX3" , NULL, "IN3_AUX" }, |
3015 | {"RDAC4" , NULL, "RX3" }, |
3016 | {"RX3" , NULL, "RXCLK" }, |
3017 | {"AUX_RDAC" , "Switch" , "RDAC4" }, |
3018 | {"AUX PGA" , NULL, "AUX_RDAC" }, |
3019 | {"AUX" , NULL, "AUX PGA" }, |
3020 | |
3021 | {"RDAC3_MUX" , "RX3" , "RX3" }, |
3022 | {"RDAC3_MUX" , "RX1" , "RX1" }, |
3023 | {"RDAC3" , NULL, "RDAC3_MUX" }, |
3024 | {"EAR_RDAC" , "Switch" , "RDAC3" }, |
3025 | {"EAR PGA" , NULL, "EAR_RDAC" }, |
3026 | {"EAR" , NULL, "EAR PGA" }, |
3027 | }; |
3028 | |
3029 | static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x) |
3030 | { |
3031 | int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; |
3032 | |
3033 | /* set micbias voltage */ |
3034 | vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(micb_mv: wcd938x->micb1_mv); |
3035 | vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(micb_mv: wcd938x->micb2_mv); |
3036 | vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(micb_mv: wcd938x->micb3_mv); |
3037 | vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(micb_mv: wcd938x->micb4_mv); |
3038 | if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0) |
3039 | return -EINVAL; |
3040 | |
3041 | regmap_update_bits(map: wcd938x->regmap, WCD938X_ANA_MICB1, |
3042 | WCD938X_MICB_VOUT_MASK, val: vout_ctl_1); |
3043 | regmap_update_bits(map: wcd938x->regmap, WCD938X_ANA_MICB2, |
3044 | WCD938X_MICB_VOUT_MASK, val: vout_ctl_2); |
3045 | regmap_update_bits(map: wcd938x->regmap, WCD938X_ANA_MICB3, |
3046 | WCD938X_MICB_VOUT_MASK, val: vout_ctl_3); |
3047 | regmap_update_bits(map: wcd938x->regmap, WCD938X_ANA_MICB4, |
3048 | WCD938X_MICB_VOUT_MASK, val: vout_ctl_4); |
3049 | |
3050 | return 0; |
3051 | } |
3052 | |
3053 | static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data) |
3054 | { |
3055 | return IRQ_HANDLED; |
3056 | } |
3057 | |
3058 | static struct irq_chip wcd_irq_chip = { |
3059 | .name = "WCD938x" , |
3060 | }; |
3061 | |
3062 | static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, |
3063 | irq_hw_number_t hw) |
3064 | { |
3065 | irq_set_chip_and_handler(irq: virq, chip: &wcd_irq_chip, handle: handle_simple_irq); |
3066 | irq_set_nested_thread(irq: virq, nest: 1); |
3067 | irq_set_noprobe(irq: virq); |
3068 | |
3069 | return 0; |
3070 | } |
3071 | |
3072 | static const struct irq_domain_ops wcd_domain_ops = { |
3073 | .map = wcd_irq_chip_map, |
3074 | }; |
3075 | |
3076 | static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev) |
3077 | { |
3078 | |
3079 | wcd->virq = irq_domain_add_linear(NULL, size: 1, ops: &wcd_domain_ops, NULL); |
3080 | if (!(wcd->virq)) { |
3081 | dev_err(dev, "%s: Failed to add IRQ domain\n" , __func__); |
3082 | return -EINVAL; |
3083 | } |
3084 | |
3085 | return devm_regmap_add_irq_chip(dev, map: wcd->regmap, |
3086 | irq: irq_create_mapping(host: wcd->virq, hwirq: 0), |
3087 | IRQF_ONESHOT, irq_base: 0, chip: &wcd938x_regmap_irq_chip, |
3088 | data: &wcd->irq_chip); |
3089 | } |
3090 | |
3091 | static int wcd938x_soc_codec_probe(struct snd_soc_component *component) |
3092 | { |
3093 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
3094 | struct sdw_slave *tx_sdw_dev = wcd938x->tx_sdw_dev; |
3095 | struct device *dev = component->dev; |
3096 | unsigned long time_left; |
3097 | int ret, i; |
3098 | |
3099 | time_left = wait_for_completion_timeout(x: &tx_sdw_dev->initialization_complete, |
3100 | timeout: msecs_to_jiffies(m: 2000)); |
3101 | if (!time_left) { |
3102 | dev_err(dev, "soundwire device init timeout\n" ); |
3103 | return -ETIMEDOUT; |
3104 | } |
3105 | |
3106 | snd_soc_component_init_regmap(component, regmap: wcd938x->regmap); |
3107 | |
3108 | ret = pm_runtime_resume_and_get(dev); |
3109 | if (ret < 0) |
3110 | return ret; |
3111 | |
3112 | wcd938x->variant = snd_soc_component_read_field(component, |
3113 | WCD938X_DIGITAL_EFUSE_REG_0, |
3114 | WCD938X_ID_MASK); |
3115 | |
3116 | wcd938x->clsh_info = wcd_clsh_ctrl_alloc(comp: component, version: WCD938X); |
3117 | if (IS_ERR(ptr: wcd938x->clsh_info)) { |
3118 | pm_runtime_put(dev); |
3119 | return PTR_ERR(ptr: wcd938x->clsh_info); |
3120 | } |
3121 | |
3122 | wcd938x_io_init(wcd938x); |
3123 | /* Set all interrupts as edge triggered */ |
3124 | for (i = 0; i < wcd938x_regmap_irq_chip.num_regs; i++) { |
3125 | regmap_write(map: wcd938x->regmap, |
3126 | reg: (WCD938X_DIGITAL_INTR_LEVEL_0 + i), val: 0); |
3127 | } |
3128 | |
3129 | pm_runtime_put(dev); |
3130 | |
3131 | wcd938x->hphr_pdm_wd_int = regmap_irq_get_virq(data: wcd938x->irq_chip, |
3132 | irq: WCD938X_IRQ_HPHR_PDM_WD_INT); |
3133 | wcd938x->hphl_pdm_wd_int = regmap_irq_get_virq(data: wcd938x->irq_chip, |
3134 | irq: WCD938X_IRQ_HPHL_PDM_WD_INT); |
3135 | wcd938x->aux_pdm_wd_int = regmap_irq_get_virq(data: wcd938x->irq_chip, |
3136 | irq: WCD938X_IRQ_AUX_PDM_WD_INT); |
3137 | |
3138 | /* Request for watchdog interrupt */ |
3139 | ret = request_threaded_irq(irq: wcd938x->hphr_pdm_wd_int, NULL, thread_fn: wcd938x_wd_handle_irq, |
3140 | IRQF_ONESHOT | IRQF_TRIGGER_RISING, |
3141 | name: "HPHR PDM WD INT" , dev: wcd938x); |
3142 | if (ret) { |
3143 | dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n" , ret); |
3144 | goto err_free_clsh_ctrl; |
3145 | } |
3146 | |
3147 | ret = request_threaded_irq(irq: wcd938x->hphl_pdm_wd_int, NULL, thread_fn: wcd938x_wd_handle_irq, |
3148 | IRQF_ONESHOT | IRQF_TRIGGER_RISING, |
3149 | name: "HPHL PDM WD INT" , dev: wcd938x); |
3150 | if (ret) { |
3151 | dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n" , ret); |
3152 | goto err_free_hphr_pdm_wd_int; |
3153 | } |
3154 | |
3155 | ret = request_threaded_irq(irq: wcd938x->aux_pdm_wd_int, NULL, thread_fn: wcd938x_wd_handle_irq, |
3156 | IRQF_ONESHOT | IRQF_TRIGGER_RISING, |
3157 | name: "AUX PDM WD INT" , dev: wcd938x); |
3158 | if (ret) { |
3159 | dev_err(dev, "Failed to request Aux WD interrupt (%d)\n" , ret); |
3160 | goto err_free_hphl_pdm_wd_int; |
3161 | } |
3162 | |
3163 | /* Disable watchdog interrupt for HPH and AUX */ |
3164 | disable_irq_nosync(irq: wcd938x->hphr_pdm_wd_int); |
3165 | disable_irq_nosync(irq: wcd938x->hphl_pdm_wd_int); |
3166 | disable_irq_nosync(irq: wcd938x->aux_pdm_wd_int); |
3167 | |
3168 | switch (wcd938x->variant) { |
3169 | case WCD9380: |
3170 | ret = snd_soc_add_component_controls(component, controls: wcd9380_snd_controls, |
3171 | ARRAY_SIZE(wcd9380_snd_controls)); |
3172 | if (ret < 0) { |
3173 | dev_err(component->dev, |
3174 | "%s: Failed to add snd ctrls for variant: %d\n" , |
3175 | __func__, wcd938x->variant); |
3176 | goto err_free_aux_pdm_wd_int; |
3177 | } |
3178 | break; |
3179 | case WCD9385: |
3180 | ret = snd_soc_add_component_controls(component, controls: wcd9385_snd_controls, |
3181 | ARRAY_SIZE(wcd9385_snd_controls)); |
3182 | if (ret < 0) { |
3183 | dev_err(component->dev, |
3184 | "%s: Failed to add snd ctrls for variant: %d\n" , |
3185 | __func__, wcd938x->variant); |
3186 | goto err_free_aux_pdm_wd_int; |
3187 | } |
3188 | break; |
3189 | default: |
3190 | break; |
3191 | } |
3192 | |
3193 | ret = wcd938x_mbhc_init(component); |
3194 | if (ret) { |
3195 | dev_err(component->dev, "mbhc initialization failed\n" ); |
3196 | goto err_free_aux_pdm_wd_int; |
3197 | } |
3198 | |
3199 | return 0; |
3200 | |
3201 | err_free_aux_pdm_wd_int: |
3202 | free_irq(wcd938x->aux_pdm_wd_int, wcd938x); |
3203 | err_free_hphl_pdm_wd_int: |
3204 | free_irq(wcd938x->hphl_pdm_wd_int, wcd938x); |
3205 | err_free_hphr_pdm_wd_int: |
3206 | free_irq(wcd938x->hphr_pdm_wd_int, wcd938x); |
3207 | err_free_clsh_ctrl: |
3208 | wcd_clsh_ctrl_free(ctrl: wcd938x->clsh_info); |
3209 | |
3210 | return ret; |
3211 | } |
3212 | |
3213 | static void wcd938x_soc_codec_remove(struct snd_soc_component *component) |
3214 | { |
3215 | struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(c: component); |
3216 | |
3217 | wcd938x_mbhc_deinit(component); |
3218 | |
3219 | free_irq(wcd938x->aux_pdm_wd_int, wcd938x); |
3220 | free_irq(wcd938x->hphl_pdm_wd_int, wcd938x); |
3221 | free_irq(wcd938x->hphr_pdm_wd_int, wcd938x); |
3222 | |
3223 | wcd_clsh_ctrl_free(ctrl: wcd938x->clsh_info); |
3224 | } |
3225 | |
3226 | static int wcd938x_codec_set_jack(struct snd_soc_component *comp, |
3227 | struct snd_soc_jack *jack, void *data) |
3228 | { |
3229 | struct wcd938x_priv *wcd = dev_get_drvdata(dev: comp->dev); |
3230 | |
3231 | if (jack) |
3232 | return wcd_mbhc_start(mbhc: wcd->wcd_mbhc, mbhc_cfg: &wcd->mbhc_cfg, jack); |
3233 | else |
3234 | wcd_mbhc_stop(mbhc: wcd->wcd_mbhc); |
3235 | |
3236 | return 0; |
3237 | } |
3238 | |
3239 | static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { |
3240 | .name = "wcd938x_codec" , |
3241 | .probe = wcd938x_soc_codec_probe, |
3242 | .remove = wcd938x_soc_codec_remove, |
3243 | .controls = wcd938x_snd_controls, |
3244 | .num_controls = ARRAY_SIZE(wcd938x_snd_controls), |
3245 | .dapm_widgets = wcd938x_dapm_widgets, |
3246 | .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), |
3247 | .dapm_routes = wcd938x_audio_map, |
3248 | .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), |
3249 | .set_jack = wcd938x_codec_set_jack, |
3250 | .endianness = 1, |
3251 | }; |
3252 | |
3253 | static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd) |
3254 | { |
3255 | struct device_node *np = dev->of_node; |
3256 | u32 prop_val = 0; |
3257 | int rc = 0; |
3258 | |
3259 | rc = of_property_read_u32(np, propname: "qcom,micbias1-microvolt" , out_value: &prop_val); |
3260 | if (!rc) |
3261 | wcd->micb1_mv = prop_val/1000; |
3262 | else |
3263 | dev_info(dev, "%s: Micbias1 DT property not found\n" , __func__); |
3264 | |
3265 | rc = of_property_read_u32(np, propname: "qcom,micbias2-microvolt" , out_value: &prop_val); |
3266 | if (!rc) |
3267 | wcd->micb2_mv = prop_val/1000; |
3268 | else |
3269 | dev_info(dev, "%s: Micbias2 DT property not found\n" , __func__); |
3270 | |
3271 | rc = of_property_read_u32(np, propname: "qcom,micbias3-microvolt" , out_value: &prop_val); |
3272 | if (!rc) |
3273 | wcd->micb3_mv = prop_val/1000; |
3274 | else |
3275 | dev_info(dev, "%s: Micbias3 DT property not found\n" , __func__); |
3276 | |
3277 | rc = of_property_read_u32(np, propname: "qcom,micbias4-microvolt" , out_value: &prop_val); |
3278 | if (!rc) |
3279 | wcd->micb4_mv = prop_val/1000; |
3280 | else |
3281 | dev_info(dev, "%s: Micbias4 DT property not found\n" , __func__); |
3282 | } |
3283 | |
3284 | static bool wcd938x_swap_gnd_mic(struct snd_soc_component *component, bool active) |
3285 | { |
3286 | int value; |
3287 | |
3288 | struct wcd938x_priv *wcd938x; |
3289 | |
3290 | wcd938x = snd_soc_component_get_drvdata(c: component); |
3291 | |
3292 | value = gpiod_get_value(desc: wcd938x->us_euro_gpio); |
3293 | |
3294 | gpiod_set_value(desc: wcd938x->us_euro_gpio, value: !value); |
3295 | |
3296 | return true; |
3297 | } |
3298 | |
3299 | |
3300 | static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device *dev) |
3301 | { |
3302 | struct wcd_mbhc_config *cfg = &wcd938x->mbhc_cfg; |
3303 | int ret; |
3304 | |
3305 | wcd938x->reset_gpio = of_get_named_gpio(np: dev->of_node, list_name: "reset-gpios" , index: 0); |
3306 | if (wcd938x->reset_gpio < 0) |
3307 | return dev_err_probe(dev, err: wcd938x->reset_gpio, |
3308 | fmt: "Failed to get reset gpio\n" ); |
3309 | |
3310 | wcd938x->us_euro_gpio = devm_gpiod_get_optional(dev, con_id: "us-euro" , |
3311 | flags: GPIOD_OUT_LOW); |
3312 | if (IS_ERR(ptr: wcd938x->us_euro_gpio)) |
3313 | return dev_err_probe(dev, err: PTR_ERR(ptr: wcd938x->us_euro_gpio), |
3314 | fmt: "us-euro swap Control GPIO not found\n" ); |
3315 | |
3316 | cfg->swap_gnd_mic = wcd938x_swap_gnd_mic; |
3317 | |
3318 | wcd938x->supplies[0].supply = "vdd-rxtx" ; |
3319 | wcd938x->supplies[1].supply = "vdd-io" ; |
3320 | wcd938x->supplies[2].supply = "vdd-buck" ; |
3321 | wcd938x->supplies[3].supply = "vdd-mic-bias" ; |
3322 | |
3323 | ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3324 | if (ret) |
3325 | return dev_err_probe(dev, err: ret, fmt: "Failed to get supplies\n" ); |
3326 | |
3327 | ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3328 | if (ret) { |
3329 | regulator_bulk_free(WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3330 | return dev_err_probe(dev, err: ret, fmt: "Failed to enable supplies\n" ); |
3331 | } |
3332 | |
3333 | wcd938x_dt_parse_micbias_info(dev, wcd: wcd938x); |
3334 | |
3335 | cfg->mbhc_micbias = MIC_BIAS_2; |
3336 | cfg->anc_micbias = MIC_BIAS_2; |
3337 | cfg->v_hs_max = WCD_MBHC_HS_V_MAX; |
3338 | cfg->num_btn = WCD938X_MBHC_MAX_BUTTONS; |
3339 | cfg->micb_mv = wcd938x->micb2_mv; |
3340 | cfg->linein_th = 5000; |
3341 | cfg->hs_thr = 1700; |
3342 | cfg->hph_thr = 50; |
3343 | |
3344 | wcd_dt_parse_mbhc_data(dev, cfg); |
3345 | |
3346 | return 0; |
3347 | } |
3348 | |
3349 | static int wcd938x_reset(struct wcd938x_priv *wcd938x) |
3350 | { |
3351 | gpio_direction_output(gpio: wcd938x->reset_gpio, value: 0); |
3352 | /* 20us sleep required after pulling the reset gpio to LOW */ |
3353 | usleep_range(min: 20, max: 30); |
3354 | gpio_set_value(gpio: wcd938x->reset_gpio, value: 1); |
3355 | /* 20us sleep required after pulling the reset gpio to HIGH */ |
3356 | usleep_range(min: 20, max: 30); |
3357 | |
3358 | return 0; |
3359 | } |
3360 | |
3361 | static int wcd938x_codec_hw_params(struct snd_pcm_substream *substream, |
3362 | struct snd_pcm_hw_params *params, |
3363 | struct snd_soc_dai *dai) |
3364 | { |
3365 | struct wcd938x_priv *wcd938x = dev_get_drvdata(dev: dai->dev); |
3366 | struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; |
3367 | |
3368 | return wcd938x_sdw_hw_params(wcd, substream, params, dai); |
3369 | } |
3370 | |
3371 | static int wcd938x_codec_free(struct snd_pcm_substream *substream, |
3372 | struct snd_soc_dai *dai) |
3373 | { |
3374 | struct wcd938x_priv *wcd938x = dev_get_drvdata(dev: dai->dev); |
3375 | struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; |
3376 | |
3377 | return wcd938x_sdw_free(wcd, substream, dai); |
3378 | } |
3379 | |
3380 | static int wcd938x_codec_set_sdw_stream(struct snd_soc_dai *dai, |
3381 | void *stream, int direction) |
3382 | { |
3383 | struct wcd938x_priv *wcd938x = dev_get_drvdata(dev: dai->dev); |
3384 | struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; |
3385 | |
3386 | return wcd938x_sdw_set_sdw_stream(wcd, dai, stream, direction); |
3387 | |
3388 | } |
3389 | |
3390 | static const struct snd_soc_dai_ops wcd938x_sdw_dai_ops = { |
3391 | .hw_params = wcd938x_codec_hw_params, |
3392 | .hw_free = wcd938x_codec_free, |
3393 | .set_stream = wcd938x_codec_set_sdw_stream, |
3394 | }; |
3395 | |
3396 | static struct snd_soc_dai_driver wcd938x_dais[] = { |
3397 | [AIF1_PB] = { |
3398 | .name = "wcd938x-sdw-rx" , |
3399 | .playback = { |
3400 | .stream_name = "WCD AIF1 Playback" , |
3401 | .rates = WCD938X_RATES_MASK | WCD938X_FRAC_RATES_MASK, |
3402 | .formats = WCD938X_FORMATS_S16_S24_LE, |
3403 | .rate_max = 192000, |
3404 | .rate_min = 8000, |
3405 | .channels_min = 1, |
3406 | .channels_max = 2, |
3407 | }, |
3408 | .ops = &wcd938x_sdw_dai_ops, |
3409 | }, |
3410 | [AIF1_CAP] = { |
3411 | .name = "wcd938x-sdw-tx" , |
3412 | .capture = { |
3413 | .stream_name = "WCD AIF1 Capture" , |
3414 | .rates = WCD938X_RATES_MASK, |
3415 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
3416 | .rate_min = 8000, |
3417 | .rate_max = 192000, |
3418 | .channels_min = 1, |
3419 | .channels_max = 4, |
3420 | }, |
3421 | .ops = &wcd938x_sdw_dai_ops, |
3422 | }, |
3423 | }; |
3424 | |
3425 | static int wcd938x_bind(struct device *dev) |
3426 | { |
3427 | struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); |
3428 | int ret; |
3429 | |
3430 | ret = component_bind_all(parent: dev, data: wcd938x); |
3431 | if (ret) { |
3432 | dev_err(dev, "%s: Slave bind failed, ret = %d\n" , |
3433 | __func__, ret); |
3434 | return ret; |
3435 | } |
3436 | |
3437 | wcd938x->rxdev = wcd938x_sdw_device_get(np: wcd938x->rxnode); |
3438 | if (!wcd938x->rxdev) { |
3439 | dev_err(dev, "could not find slave with matching of node\n" ); |
3440 | ret = -EINVAL; |
3441 | goto err_unbind; |
3442 | } |
3443 | wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(dev: wcd938x->rxdev); |
3444 | wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x; |
3445 | |
3446 | wcd938x->txdev = wcd938x_sdw_device_get(np: wcd938x->txnode); |
3447 | if (!wcd938x->txdev) { |
3448 | dev_err(dev, "could not find txslave with matching of node\n" ); |
3449 | ret = -EINVAL; |
3450 | goto err_put_rxdev; |
3451 | } |
3452 | wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(dev: wcd938x->txdev); |
3453 | wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x; |
3454 | wcd938x->tx_sdw_dev = dev_to_sdw_dev(wcd938x->txdev); |
3455 | |
3456 | /* As TX is main CSR reg interface, which should not be suspended first. |
3457 | * expicilty add the dependency link */ |
3458 | if (!device_link_add(consumer: wcd938x->rxdev, supplier: wcd938x->txdev, DL_FLAG_STATELESS | |
3459 | DL_FLAG_PM_RUNTIME)) { |
3460 | dev_err(dev, "could not devlink tx and rx\n" ); |
3461 | ret = -EINVAL; |
3462 | goto err_put_txdev; |
3463 | } |
3464 | |
3465 | if (!device_link_add(consumer: dev, supplier: wcd938x->txdev, DL_FLAG_STATELESS | |
3466 | DL_FLAG_PM_RUNTIME)) { |
3467 | dev_err(dev, "could not devlink wcd and tx\n" ); |
3468 | ret = -EINVAL; |
3469 | goto err_remove_rxtx_link; |
3470 | } |
3471 | |
3472 | if (!device_link_add(consumer: dev, supplier: wcd938x->rxdev, DL_FLAG_STATELESS | |
3473 | DL_FLAG_PM_RUNTIME)) { |
3474 | dev_err(dev, "could not devlink wcd and rx\n" ); |
3475 | ret = -EINVAL; |
3476 | goto err_remove_tx_link; |
3477 | } |
3478 | |
3479 | wcd938x->regmap = dev_get_regmap(dev: &wcd938x->tx_sdw_dev->dev, NULL); |
3480 | if (!wcd938x->regmap) { |
3481 | dev_err(dev, "could not get TX device regmap\n" ); |
3482 | ret = -EINVAL; |
3483 | goto err_remove_rx_link; |
3484 | } |
3485 | |
3486 | ret = wcd938x_irq_init(wcd: wcd938x, dev); |
3487 | if (ret) { |
3488 | dev_err(dev, "%s: IRQ init failed: %d\n" , __func__, ret); |
3489 | goto err_remove_rx_link; |
3490 | } |
3491 | |
3492 | wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq; |
3493 | wcd938x->sdw_priv[AIF1_CAP]->slave_irq = wcd938x->virq; |
3494 | |
3495 | ret = wcd938x_set_micbias_data(wcd938x); |
3496 | if (ret < 0) { |
3497 | dev_err(dev, "%s: bad micbias pdata\n" , __func__); |
3498 | goto err_remove_rx_link; |
3499 | } |
3500 | |
3501 | ret = snd_soc_register_component(dev, component_driver: &soc_codec_dev_wcd938x, |
3502 | dai_drv: wcd938x_dais, ARRAY_SIZE(wcd938x_dais)); |
3503 | if (ret) { |
3504 | dev_err(dev, "%s: Codec registration failed\n" , |
3505 | __func__); |
3506 | goto err_remove_rx_link; |
3507 | } |
3508 | |
3509 | return 0; |
3510 | |
3511 | err_remove_rx_link: |
3512 | device_link_remove(consumer: dev, supplier: wcd938x->rxdev); |
3513 | err_remove_tx_link: |
3514 | device_link_remove(consumer: dev, supplier: wcd938x->txdev); |
3515 | err_remove_rxtx_link: |
3516 | device_link_remove(consumer: wcd938x->rxdev, supplier: wcd938x->txdev); |
3517 | err_put_txdev: |
3518 | put_device(dev: wcd938x->txdev); |
3519 | err_put_rxdev: |
3520 | put_device(dev: wcd938x->rxdev); |
3521 | err_unbind: |
3522 | component_unbind_all(parent: dev, data: wcd938x); |
3523 | |
3524 | return ret; |
3525 | } |
3526 | |
3527 | static void wcd938x_unbind(struct device *dev) |
3528 | { |
3529 | struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); |
3530 | |
3531 | snd_soc_unregister_component(dev); |
3532 | device_link_remove(consumer: dev, supplier: wcd938x->txdev); |
3533 | device_link_remove(consumer: dev, supplier: wcd938x->rxdev); |
3534 | device_link_remove(consumer: wcd938x->rxdev, supplier: wcd938x->txdev); |
3535 | put_device(dev: wcd938x->txdev); |
3536 | put_device(dev: wcd938x->rxdev); |
3537 | component_unbind_all(parent: dev, data: wcd938x); |
3538 | } |
3539 | |
3540 | static const struct component_master_ops wcd938x_comp_ops = { |
3541 | .bind = wcd938x_bind, |
3542 | .unbind = wcd938x_unbind, |
3543 | }; |
3544 | |
3545 | static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, |
3546 | struct device *dev, |
3547 | struct component_match **matchptr) |
3548 | { |
3549 | struct device_node *np; |
3550 | |
3551 | np = dev->of_node; |
3552 | |
3553 | wcd938x->rxnode = of_parse_phandle(np, phandle_name: "qcom,rx-device" , index: 0); |
3554 | if (!wcd938x->rxnode) { |
3555 | dev_err(dev, "%s: Rx-device node not defined\n" , __func__); |
3556 | return -ENODEV; |
3557 | } |
3558 | |
3559 | of_node_get(node: wcd938x->rxnode); |
3560 | component_match_add_release(parent: dev, matchptr, release: component_release_of, |
3561 | compare: component_compare_of, compare_data: wcd938x->rxnode); |
3562 | |
3563 | wcd938x->txnode = of_parse_phandle(np, phandle_name: "qcom,tx-device" , index: 0); |
3564 | if (!wcd938x->txnode) { |
3565 | dev_err(dev, "%s: Tx-device node not defined\n" , __func__); |
3566 | return -ENODEV; |
3567 | } |
3568 | of_node_get(node: wcd938x->txnode); |
3569 | component_match_add_release(parent: dev, matchptr, release: component_release_of, |
3570 | compare: component_compare_of, compare_data: wcd938x->txnode); |
3571 | return 0; |
3572 | } |
3573 | |
3574 | static int wcd938x_probe(struct platform_device *pdev) |
3575 | { |
3576 | struct component_match *match = NULL; |
3577 | struct wcd938x_priv *wcd938x = NULL; |
3578 | struct device *dev = &pdev->dev; |
3579 | int ret; |
3580 | |
3581 | wcd938x = devm_kzalloc(dev, size: sizeof(struct wcd938x_priv), |
3582 | GFP_KERNEL); |
3583 | if (!wcd938x) |
3584 | return -ENOMEM; |
3585 | |
3586 | dev_set_drvdata(dev, data: wcd938x); |
3587 | mutex_init(&wcd938x->micb_lock); |
3588 | |
3589 | ret = wcd938x_populate_dt_data(wcd938x, dev); |
3590 | if (ret) |
3591 | return ret; |
3592 | |
3593 | ret = wcd938x_add_slave_components(wcd938x, dev, matchptr: &match); |
3594 | if (ret) |
3595 | goto err_disable_regulators; |
3596 | |
3597 | wcd938x_reset(wcd938x); |
3598 | |
3599 | ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match); |
3600 | if (ret) |
3601 | goto err_disable_regulators; |
3602 | |
3603 | pm_runtime_set_autosuspend_delay(dev, delay: 1000); |
3604 | pm_runtime_use_autosuspend(dev); |
3605 | pm_runtime_mark_last_busy(dev); |
3606 | pm_runtime_set_active(dev); |
3607 | pm_runtime_enable(dev); |
3608 | pm_runtime_idle(dev); |
3609 | |
3610 | return 0; |
3611 | |
3612 | err_disable_regulators: |
3613 | regulator_bulk_disable(WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3614 | regulator_bulk_free(WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3615 | |
3616 | return ret; |
3617 | } |
3618 | |
3619 | static void wcd938x_remove(struct platform_device *pdev) |
3620 | { |
3621 | struct device *dev = &pdev->dev; |
3622 | struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); |
3623 | |
3624 | component_master_del(dev, &wcd938x_comp_ops); |
3625 | |
3626 | pm_runtime_disable(dev); |
3627 | pm_runtime_set_suspended(dev); |
3628 | pm_runtime_dont_use_autosuspend(dev); |
3629 | |
3630 | regulator_bulk_disable(WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3631 | regulator_bulk_free(WCD938X_MAX_SUPPLY, consumers: wcd938x->supplies); |
3632 | } |
3633 | |
3634 | #if defined(CONFIG_OF) |
3635 | static const struct of_device_id wcd938x_dt_match[] = { |
3636 | { .compatible = "qcom,wcd9380-codec" }, |
3637 | { .compatible = "qcom,wcd9385-codec" }, |
3638 | {} |
3639 | }; |
3640 | MODULE_DEVICE_TABLE(of, wcd938x_dt_match); |
3641 | #endif |
3642 | |
3643 | static struct platform_driver wcd938x_codec_driver = { |
3644 | .probe = wcd938x_probe, |
3645 | .remove_new = wcd938x_remove, |
3646 | .driver = { |
3647 | .name = "wcd938x_codec" , |
3648 | .of_match_table = of_match_ptr(wcd938x_dt_match), |
3649 | .suppress_bind_attrs = true, |
3650 | }, |
3651 | }; |
3652 | |
3653 | module_platform_driver(wcd938x_codec_driver); |
3654 | MODULE_DESCRIPTION("WCD938X Codec driver" ); |
3655 | MODULE_LICENSE("GPL" ); |
3656 | |