1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. |
3 | // Copyright (c) 2017-2018, Linaro Limited |
4 | |
5 | #include <linux/slab.h> |
6 | #include <sound/soc.h> |
7 | #include <linux/kernel.h> |
8 | #include <linux/delay.h> |
9 | #include "wcd9335.h" |
10 | #include "wcd-clsh-v2.h" |
11 | |
12 | struct wcd_clsh_ctrl { |
13 | int state; |
14 | int mode; |
15 | int flyback_users; |
16 | int buck_users; |
17 | int clsh_users; |
18 | int codec_version; |
19 | struct snd_soc_component *comp; |
20 | }; |
21 | |
22 | /* Class-H registers for codecs from and above WCD9335 */ |
23 | #define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42) |
24 | #define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6) |
25 | #define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6) |
26 | #define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0 |
27 | #define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56) |
28 | #define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A) |
29 | #define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08) |
30 | #define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0) |
31 | #define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09) |
32 | #define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0) |
33 | #define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08) |
34 | #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1) |
35 | #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0 |
36 | #define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1) |
37 | #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2) |
38 | #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2) |
39 | #define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0 |
40 | #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3) |
41 | #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3) |
42 | #define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0 |
43 | #define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6) |
44 | #define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6 |
45 | #define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6) |
46 | #define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0 |
47 | #define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7) |
48 | #define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7 |
49 | #define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7) |
50 | #define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0 |
51 | #define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09) |
52 | #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2) |
53 | #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08 |
54 | #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04 |
55 | #define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0 |
56 | #define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01) |
57 | #define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0) |
58 | #define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0) |
59 | #define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0 |
60 | #define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4) |
61 | #define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5) |
62 | #define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40 |
63 | #define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4) |
64 | #define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4) |
65 | #define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 |
66 | #define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) |
67 | #define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) |
68 | #define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) |
69 | #define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) |
70 | #define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) |
71 | #define WCD9XXX_HPH_CONST_SEL_BYPASS 0 |
72 | #define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40 |
73 | #define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80 |
74 | #define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6) |
75 | #define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD) |
76 | #define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0) |
77 | #define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B) |
78 | #define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4) |
79 | #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20 |
80 | #define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0 |
81 | #define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55) |
82 | #define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69) |
83 | #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41) |
84 | #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) |
85 | #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1) |
86 | #define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C) |
87 | #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4) |
88 | #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 |
89 | #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 |
90 | |
91 | #define WCD9XXX_BASE_ADDRESS 0x3000 |
92 | #define WCD9XXX_ANA_RX_SUPPLIES (WCD9XXX_BASE_ADDRESS+0x008) |
93 | #define WCD9XXX_ANA_HPH (WCD9XXX_BASE_ADDRESS+0x009) |
94 | #define WCD9XXX_CLASSH_MODE_2 (WCD9XXX_BASE_ADDRESS+0x098) |
95 | #define WCD9XXX_CLASSH_MODE_3 (WCD9XXX_BASE_ADDRESS+0x099) |
96 | #define WCD9XXX_FLYBACK_VNEG_CTRL_1 (WCD9XXX_BASE_ADDRESS+0x0A5) |
97 | #define WCD9XXX_FLYBACK_VNEG_CTRL_4 (WCD9XXX_BASE_ADDRESS+0x0A8) |
98 | #define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 (WCD9XXX_BASE_ADDRESS+0x0AF) |
99 | #define WCD9XXX_RX_BIAS_HPH_LOWPOWER (WCD9XXX_BASE_ADDRESS+0x0BF) |
100 | #define WCD9XXX_V3_RX_BIAS_FLYB_BUFF (WCD9XXX_BASE_ADDRESS+0x0C7) |
101 | #define WCD9XXX_HPH_PA_CTL1 (WCD9XXX_BASE_ADDRESS+0x0D1) |
102 | #define WCD9XXX_HPH_NEW_INT_PA_MISC2 (WCD9XXX_BASE_ADDRESS+0x138) |
103 | |
104 | #define CLSH_REQ_ENABLE true |
105 | #define CLSH_REQ_DISABLE false |
106 | #define WCD_USLEEP_RANGE 50 |
107 | |
108 | enum { |
109 | DAC_GAIN_0DB = 0, |
110 | DAC_GAIN_0P2DB, |
111 | DAC_GAIN_0P4DB, |
112 | DAC_GAIN_0P6DB, |
113 | DAC_GAIN_0P8DB, |
114 | DAC_GAIN_M0P2DB, |
115 | DAC_GAIN_M0P4DB, |
116 | DAC_GAIN_M0P6DB, |
117 | }; |
118 | |
119 | static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, |
120 | bool enable) |
121 | { |
122 | struct snd_soc_component *comp = ctrl->comp; |
123 | |
124 | if ((enable && ++ctrl->clsh_users == 1) || |
125 | (!enable && --ctrl->clsh_users == 0)) |
126 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_CDC_CLSH_CRC, |
127 | WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK, |
128 | val: enable); |
129 | if (ctrl->clsh_users < 0) |
130 | ctrl->clsh_users = 0; |
131 | } |
132 | |
133 | static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, |
134 | int mode) |
135 | { |
136 | /* set to HIFI */ |
137 | if (mode == CLS_H_HIFI) |
138 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
139 | WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, |
140 | WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA); |
141 | else |
142 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
143 | WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, |
144 | WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); |
145 | } |
146 | |
147 | static void wcd_clsh_v3_set_buck_mode(struct snd_soc_component *component, |
148 | int mode) |
149 | { |
150 | if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || |
151 | mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) |
152 | snd_soc_component_update_bits(component, |
153 | WCD9XXX_ANA_RX_SUPPLIES, |
154 | mask: 0x08, val: 0x08); /* set to HIFI */ |
155 | else |
156 | snd_soc_component_update_bits(component, |
157 | WCD9XXX_ANA_RX_SUPPLIES, |
158 | mask: 0x08, val: 0x00); /* set to default */ |
159 | } |
160 | |
161 | static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, |
162 | int mode) |
163 | { |
164 | /* set to HIFI */ |
165 | if (mode == CLS_H_HIFI) |
166 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
167 | WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, |
168 | WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA); |
169 | else |
170 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
171 | WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, |
172 | WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT); |
173 | } |
174 | |
175 | static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, |
176 | int mode, |
177 | bool enable) |
178 | { |
179 | struct snd_soc_component *comp = ctrl->comp; |
180 | |
181 | /* enable/disable buck */ |
182 | if ((enable && (++ctrl->buck_users == 1)) || |
183 | (!enable && (--ctrl->buck_users == 0))) |
184 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
185 | WCD9XXX_A_ANA_RX_VPOS_EN_MASK, |
186 | val: enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT); |
187 | /* |
188 | * 500us sleep is required after buck enable/disable |
189 | * as per HW requirement |
190 | */ |
191 | usleep_range(min: 500, max: 500 + WCD_USLEEP_RANGE); |
192 | } |
193 | |
194 | static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component, |
195 | struct wcd_clsh_ctrl *ctrl, |
196 | int mode, |
197 | bool enable) |
198 | { |
199 | /* enable/disable buck */ |
200 | if ((enable && (++ctrl->buck_users == 1)) || |
201 | (!enable && (--ctrl->buck_users == 0))) { |
202 | snd_soc_component_update_bits(component, |
203 | WCD9XXX_ANA_RX_SUPPLIES, |
204 | mask: (1 << 7), val: (enable << 7)); |
205 | /* |
206 | * 500us sleep is required after buck enable/disable |
207 | * as per HW requirement |
208 | */ |
209 | usleep_range(min: 500, max: 510); |
210 | if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP || |
211 | mode == CLS_H_HIFI || mode == CLS_H_LP) |
212 | snd_soc_component_update_bits(component, |
213 | WCD9XXX_CLASSH_MODE_3, |
214 | mask: 0x02, val: 0x00); |
215 | |
216 | snd_soc_component_update_bits(component, |
217 | WCD9XXX_CLASSH_MODE_2, |
218 | mask: 0xFF, val: 0x3A); |
219 | /* 500usec delay is needed as per HW requirement */ |
220 | usleep_range(min: 500, max: 500 + WCD_USLEEP_RANGE); |
221 | } |
222 | } |
223 | |
224 | static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, |
225 | int mode, |
226 | bool enable) |
227 | { |
228 | struct snd_soc_component *comp = ctrl->comp; |
229 | |
230 | /* enable/disable flyback */ |
231 | if ((enable && (++ctrl->flyback_users == 1)) || |
232 | (!enable && (--ctrl->flyback_users == 0))) { |
233 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
234 | WCD9XXX_A_ANA_RX_VNEG_EN_MASK, |
235 | val: enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT); |
236 | /* 100usec delay is needed as per HW requirement */ |
237 | usleep_range(min: 100, max: 110); |
238 | } |
239 | /* |
240 | * 500us sleep is required after flyback enable/disable |
241 | * as per HW requirement |
242 | */ |
243 | usleep_range(min: 500, max: 500 + WCD_USLEEP_RANGE); |
244 | } |
245 | |
246 | static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) |
247 | { |
248 | struct snd_soc_component *comp = ctrl->comp; |
249 | int val = 0; |
250 | |
251 | switch (mode) { |
252 | case CLS_H_NORMAL: |
253 | case CLS_AB: |
254 | val = WCD9XXX_HPH_CONST_SEL_BYPASS; |
255 | break; |
256 | case CLS_H_HIFI: |
257 | val = WCD9XXX_HPH_CONST_SEL_HQ_PATH; |
258 | break; |
259 | case CLS_H_LP: |
260 | val = WCD9XXX_HPH_CONST_SEL_LP_PATH; |
261 | break; |
262 | } |
263 | |
264 | snd_soc_component_update_bits(component: comp, WCD9XXX_HPH_L_EN, |
265 | WCD9XXX_HPH_CONST_SEL_L_MASK, |
266 | val); |
267 | |
268 | snd_soc_component_update_bits(component: comp, WCD9XXX_HPH_R_EN, |
269 | WCD9XXX_HPH_CONST_SEL_L_MASK, |
270 | val); |
271 | } |
272 | |
273 | static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp, int mode) |
274 | { |
275 | int val = 0, gain = 0, res_val; |
276 | int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; |
277 | |
278 | res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM; |
279 | switch (mode) { |
280 | case CLS_H_NORMAL: |
281 | res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM; |
282 | val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; |
283 | gain = DAC_GAIN_0DB; |
284 | ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; |
285 | break; |
286 | case CLS_AB: |
287 | val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; |
288 | gain = DAC_GAIN_0DB; |
289 | ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; |
290 | break; |
291 | case CLS_H_HIFI: |
292 | val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA; |
293 | gain = DAC_GAIN_M0P2DB; |
294 | ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; |
295 | break; |
296 | case CLS_H_LP: |
297 | val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; |
298 | ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; |
299 | break; |
300 | } |
301 | |
302 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_HPH, |
303 | WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); |
304 | snd_soc_component_update_bits(component: comp, WCD9XXX_CLASSH_CTRL_VCL_2, |
305 | WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK, |
306 | val: res_val); |
307 | if (mode != CLS_H_LP) |
308 | snd_soc_component_update_bits(component: comp, |
309 | WCD9XXX_HPH_REFBUFF_UHQA_CTL, |
310 | WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK, |
311 | val: gain); |
312 | snd_soc_component_update_bits(component: comp, WCD9XXX_CLASSH_CTRL_CCL_1, |
313 | WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK, |
314 | val: ipeak); |
315 | } |
316 | |
317 | static void wcd_clsh_v3_set_hph_mode(struct snd_soc_component *component, |
318 | int mode) |
319 | { |
320 | u8 val; |
321 | |
322 | switch (mode) { |
323 | case CLS_H_NORMAL: |
324 | val = 0x00; |
325 | break; |
326 | case CLS_AB: |
327 | case CLS_H_ULP: |
328 | val = 0x0C; |
329 | break; |
330 | case CLS_AB_HIFI: |
331 | case CLS_H_HIFI: |
332 | val = 0x08; |
333 | break; |
334 | case CLS_H_LP: |
335 | case CLS_H_LOHIFI: |
336 | case CLS_AB_LP: |
337 | case CLS_AB_LOHIFI: |
338 | val = 0x04; |
339 | break; |
340 | default: |
341 | dev_err(component->dev, "%s:Invalid mode %d\n" , __func__, mode); |
342 | return; |
343 | } |
344 | |
345 | snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, mask: 0x0C, val); |
346 | } |
347 | |
348 | void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode) |
349 | { |
350 | struct snd_soc_component *comp = ctrl->comp; |
351 | |
352 | if (ctrl->codec_version >= WCD937X) |
353 | wcd_clsh_v3_set_hph_mode(component: comp, mode); |
354 | else |
355 | wcd_clsh_v2_set_hph_mode(comp, mode); |
356 | |
357 | } |
358 | EXPORT_SYMBOL_GPL(wcd_clsh_set_hph_mode); |
359 | |
360 | static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, |
361 | int mode) |
362 | { |
363 | |
364 | snd_soc_component_update_bits(component: comp, WCD9XXX_RX_BIAS_FLYB_BUFF, |
365 | WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, val: 0x0A); |
366 | snd_soc_component_update_bits(component: comp, WCD9XXX_RX_BIAS_FLYB_BUFF, |
367 | WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, val: 0x0A); |
368 | /* Sleep needed to avoid click and pop as per HW requirement */ |
369 | usleep_range(min: 100, max: 110); |
370 | } |
371 | |
372 | static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, |
373 | int mode) |
374 | { |
375 | if (mode == CLS_AB) |
376 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
377 | WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, |
378 | WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); |
379 | else |
380 | snd_soc_component_update_bits(component: comp, WCD9XXX_A_ANA_RX_SUPPLIES, |
381 | WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, |
382 | WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); |
383 | } |
384 | |
385 | static void wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component *component, |
386 | int mode) |
387 | { |
388 | snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES, |
389 | mask: 0x02, val: 0x00); |
390 | } |
391 | |
392 | static void wcd_clsh_v3_set_flyback_mode(struct snd_soc_component *component, |
393 | int mode) |
394 | { |
395 | if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || |
396 | mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) { |
397 | snd_soc_component_update_bits(component, |
398 | WCD9XXX_ANA_RX_SUPPLIES, |
399 | mask: 0x04, val: 0x04); |
400 | snd_soc_component_update_bits(component, |
401 | WCD9XXX_FLYBACK_VNEG_CTRL_4, |
402 | mask: 0xF0, val: 0x80); |
403 | } else { |
404 | snd_soc_component_update_bits(component, |
405 | WCD9XXX_ANA_RX_SUPPLIES, |
406 | mask: 0x04, val: 0x00); /* set to Default */ |
407 | snd_soc_component_update_bits(component, |
408 | WCD9XXX_FLYBACK_VNEG_CTRL_4, |
409 | mask: 0xF0, val: 0x70); |
410 | } |
411 | } |
412 | |
413 | static void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component *component, |
414 | int mode, bool enable) |
415 | { |
416 | if (enable) { |
417 | snd_soc_component_update_bits(component, |
418 | WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, |
419 | mask: 0xE0, val: 0xA0); |
420 | /* 100usec delay is needed as per HW requirement */ |
421 | usleep_range(min: 100, max: 110); |
422 | snd_soc_component_update_bits(component, |
423 | WCD9XXX_CLASSH_MODE_3, |
424 | mask: 0x02, val: 0x02); |
425 | snd_soc_component_update_bits(component, |
426 | WCD9XXX_CLASSH_MODE_2, |
427 | mask: 0xFF, val: 0x1C); |
428 | if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) { |
429 | snd_soc_component_update_bits(component, |
430 | WCD9XXX_HPH_NEW_INT_PA_MISC2, |
431 | mask: 0x20, val: 0x20); |
432 | snd_soc_component_update_bits(component, |
433 | WCD9XXX_RX_BIAS_HPH_LOWPOWER, |
434 | mask: 0xF0, val: 0xC0); |
435 | snd_soc_component_update_bits(component, |
436 | WCD9XXX_HPH_PA_CTL1, |
437 | mask: 0x0E, val: 0x02); |
438 | } |
439 | } else { |
440 | snd_soc_component_update_bits(component, |
441 | WCD9XXX_HPH_NEW_INT_PA_MISC2, |
442 | mask: 0x20, val: 0x00); |
443 | snd_soc_component_update_bits(component, |
444 | WCD9XXX_RX_BIAS_HPH_LOWPOWER, |
445 | mask: 0xF0, val: 0x80); |
446 | snd_soc_component_update_bits(component, |
447 | WCD9XXX_HPH_PA_CTL1, |
448 | mask: 0x0E, val: 0x06); |
449 | } |
450 | } |
451 | |
452 | static void wcd_clsh_v3_flyback_ctrl(struct snd_soc_component *component, |
453 | struct wcd_clsh_ctrl *ctrl, |
454 | int mode, |
455 | bool enable) |
456 | { |
457 | /* enable/disable flyback */ |
458 | if ((enable && (++ctrl->flyback_users == 1)) || |
459 | (!enable && (--ctrl->flyback_users == 0))) { |
460 | snd_soc_component_update_bits(component, |
461 | WCD9XXX_FLYBACK_VNEG_CTRL_1, |
462 | mask: 0xE0, val: 0xE0); |
463 | snd_soc_component_update_bits(component, |
464 | WCD9XXX_ANA_RX_SUPPLIES, |
465 | mask: (1 << 6), val: (enable << 6)); |
466 | /* |
467 | * 100us sleep is required after flyback enable/disable |
468 | * as per HW requirement |
469 | */ |
470 | usleep_range(min: 100, max: 110); |
471 | snd_soc_component_update_bits(component, |
472 | WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, |
473 | mask: 0xE0, val: 0xE0); |
474 | /* 500usec delay is needed as per HW requirement */ |
475 | usleep_range(min: 500, max: 500 + WCD_USLEEP_RANGE); |
476 | } |
477 | } |
478 | |
479 | static void wcd_clsh_v3_set_flyback_current(struct snd_soc_component *component, |
480 | int mode) |
481 | { |
482 | snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, |
483 | mask: 0x0F, val: 0x0A); |
484 | snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, |
485 | mask: 0xF0, val: 0xA0); |
486 | /* Sleep needed to avoid click and pop as per HW requirement */ |
487 | usleep_range(min: 100, max: 110); |
488 | } |
489 | |
490 | static void wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl *ctrl, int req_state, |
491 | bool is_enable, int mode) |
492 | { |
493 | struct snd_soc_component *component = ctrl->comp; |
494 | |
495 | if (is_enable) { |
496 | wcd_clsh_v3_set_buck_mode(component, mode); |
497 | wcd_clsh_v3_set_flyback_mode(component, mode); |
498 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, enable: true); |
499 | wcd_clsh_v3_set_flyback_current(component, mode); |
500 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode, enable: true); |
501 | } else { |
502 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode, enable: false); |
503 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, enable: false); |
504 | wcd_clsh_v3_set_flyback_mode(component, mode: CLS_H_NORMAL); |
505 | wcd_clsh_v3_set_buck_mode(component, mode: CLS_H_NORMAL); |
506 | } |
507 | } |
508 | |
509 | static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, |
510 | bool is_enable, int mode) |
511 | { |
512 | struct snd_soc_component *comp = ctrl->comp; |
513 | |
514 | if (mode != CLS_AB) { |
515 | dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n" , |
516 | __func__, mode); |
517 | return; |
518 | } |
519 | |
520 | if (is_enable) { |
521 | wcd_clsh_set_buck_regulator_mode(comp, mode); |
522 | wcd_clsh_set_buck_mode(comp, mode); |
523 | wcd_clsh_set_flyback_mode(comp, mode); |
524 | wcd_clsh_flyback_ctrl(ctrl, mode, enable: true); |
525 | wcd_clsh_set_flyback_current(comp, mode); |
526 | wcd_clsh_buck_ctrl(ctrl, mode, enable: true); |
527 | } else { |
528 | wcd_clsh_buck_ctrl(ctrl, mode, enable: false); |
529 | wcd_clsh_flyback_ctrl(ctrl, mode, enable: false); |
530 | wcd_clsh_set_flyback_mode(comp, mode: CLS_H_NORMAL); |
531 | wcd_clsh_set_buck_mode(comp, mode: CLS_H_NORMAL); |
532 | wcd_clsh_set_buck_regulator_mode(comp, mode: CLS_H_NORMAL); |
533 | } |
534 | } |
535 | |
536 | static void wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, |
537 | bool is_enable, int mode) |
538 | { |
539 | struct snd_soc_component *component = ctrl->comp; |
540 | |
541 | if (mode == CLS_H_NORMAL) { |
542 | dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n" , |
543 | __func__); |
544 | return; |
545 | } |
546 | |
547 | if (is_enable) { |
548 | wcd_clsh_v3_set_buck_regulator_mode(component, mode); |
549 | wcd_clsh_v3_set_flyback_mode(component, mode); |
550 | wcd_clsh_v3_force_iq_ctl(component, mode, enable: true); |
551 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, enable: true); |
552 | wcd_clsh_v3_set_flyback_current(component, mode); |
553 | wcd_clsh_v3_set_buck_mode(component, mode); |
554 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode, enable: true); |
555 | wcd_clsh_v3_set_hph_mode(component, mode); |
556 | } else { |
557 | wcd_clsh_v3_set_hph_mode(component, mode: CLS_H_NORMAL); |
558 | |
559 | /* buck and flyback set to default mode and disable */ |
560 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode: CLS_H_NORMAL, enable: false); |
561 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode: CLS_H_NORMAL, enable: false); |
562 | wcd_clsh_v3_force_iq_ctl(component, mode: CLS_H_NORMAL, enable: false); |
563 | wcd_clsh_v3_set_flyback_mode(component, mode: CLS_H_NORMAL); |
564 | wcd_clsh_v3_set_buck_mode(component, mode: CLS_H_NORMAL); |
565 | } |
566 | } |
567 | |
568 | static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, |
569 | bool is_enable, int mode) |
570 | { |
571 | struct snd_soc_component *comp = ctrl->comp; |
572 | |
573 | if (mode == CLS_H_NORMAL) { |
574 | dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n" , |
575 | __func__); |
576 | return; |
577 | } |
578 | |
579 | if (is_enable) { |
580 | if (mode != CLS_AB) { |
581 | wcd_enable_clsh_block(ctrl, enable: true); |
582 | /* |
583 | * These K1 values depend on the Headphone Impedance |
584 | * For now it is assumed to be 16 ohm |
585 | */ |
586 | snd_soc_component_update_bits(component: comp, |
587 | WCD9XXX_A_CDC_CLSH_K1_MSB, |
588 | WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, |
589 | val: 0x00); |
590 | snd_soc_component_update_bits(component: comp, |
591 | WCD9XXX_A_CDC_CLSH_K1_LSB, |
592 | WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, |
593 | val: 0xC0); |
594 | snd_soc_component_update_bits(component: comp, |
595 | WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, |
596 | WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, |
597 | WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); |
598 | } |
599 | wcd_clsh_set_buck_regulator_mode(comp, mode); |
600 | wcd_clsh_set_flyback_mode(comp, mode); |
601 | wcd_clsh_flyback_ctrl(ctrl, mode, enable: true); |
602 | wcd_clsh_set_flyback_current(comp, mode); |
603 | wcd_clsh_set_buck_mode(comp, mode); |
604 | wcd_clsh_buck_ctrl(ctrl, mode, enable: true); |
605 | wcd_clsh_v2_set_hph_mode(comp, mode); |
606 | wcd_clsh_set_gain_path(ctrl, mode); |
607 | } else { |
608 | wcd_clsh_v2_set_hph_mode(comp, mode: CLS_H_NORMAL); |
609 | |
610 | if (mode != CLS_AB) { |
611 | snd_soc_component_update_bits(component: comp, |
612 | WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, |
613 | WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, |
614 | WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); |
615 | wcd_enable_clsh_block(ctrl, enable: false); |
616 | } |
617 | /* buck and flyback set to default mode and disable */ |
618 | wcd_clsh_buck_ctrl(ctrl, mode: CLS_H_NORMAL, enable: false); |
619 | wcd_clsh_flyback_ctrl(ctrl, mode: CLS_H_NORMAL, enable: false); |
620 | wcd_clsh_set_flyback_mode(comp, mode: CLS_H_NORMAL); |
621 | wcd_clsh_set_buck_mode(comp, mode: CLS_H_NORMAL); |
622 | wcd_clsh_set_buck_regulator_mode(comp, mode: CLS_H_NORMAL); |
623 | } |
624 | } |
625 | |
626 | static void wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, |
627 | bool is_enable, int mode) |
628 | { |
629 | struct snd_soc_component *component = ctrl->comp; |
630 | |
631 | if (mode == CLS_H_NORMAL) { |
632 | dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n" , |
633 | __func__); |
634 | return; |
635 | } |
636 | |
637 | if (is_enable) { |
638 | wcd_clsh_v3_set_buck_regulator_mode(component, mode); |
639 | wcd_clsh_v3_set_flyback_mode(component, mode); |
640 | wcd_clsh_v3_force_iq_ctl(component, mode, enable: true); |
641 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, enable: true); |
642 | wcd_clsh_v3_set_flyback_current(component, mode); |
643 | wcd_clsh_v3_set_buck_mode(component, mode); |
644 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode, enable: true); |
645 | wcd_clsh_v3_set_hph_mode(component, mode); |
646 | } else { |
647 | wcd_clsh_v3_set_hph_mode(component, mode: CLS_H_NORMAL); |
648 | |
649 | /* set buck and flyback to Default Mode */ |
650 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode: CLS_H_NORMAL, enable: false); |
651 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode: CLS_H_NORMAL, enable: false); |
652 | wcd_clsh_v3_force_iq_ctl(component, mode: CLS_H_NORMAL, enable: false); |
653 | wcd_clsh_v3_set_flyback_mode(component, mode: CLS_H_NORMAL); |
654 | wcd_clsh_v3_set_buck_mode(component, mode: CLS_H_NORMAL); |
655 | } |
656 | } |
657 | |
658 | static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, |
659 | bool is_enable, int mode) |
660 | { |
661 | struct snd_soc_component *comp = ctrl->comp; |
662 | |
663 | if (mode == CLS_H_NORMAL) { |
664 | dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n" , |
665 | __func__); |
666 | return; |
667 | } |
668 | |
669 | if (is_enable) { |
670 | if (mode != CLS_AB) { |
671 | wcd_enable_clsh_block(ctrl, enable: true); |
672 | /* |
673 | * These K1 values depend on the Headphone Impedance |
674 | * For now it is assumed to be 16 ohm |
675 | */ |
676 | snd_soc_component_update_bits(component: comp, |
677 | WCD9XXX_A_CDC_CLSH_K1_MSB, |
678 | WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, |
679 | val: 0x00); |
680 | snd_soc_component_update_bits(component: comp, |
681 | WCD9XXX_A_CDC_CLSH_K1_LSB, |
682 | WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, |
683 | val: 0xC0); |
684 | snd_soc_component_update_bits(component: comp, |
685 | WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, |
686 | WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, |
687 | WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); |
688 | } |
689 | wcd_clsh_set_buck_regulator_mode(comp, mode); |
690 | wcd_clsh_set_flyback_mode(comp, mode); |
691 | wcd_clsh_flyback_ctrl(ctrl, mode, enable: true); |
692 | wcd_clsh_set_flyback_current(comp, mode); |
693 | wcd_clsh_set_buck_mode(comp, mode); |
694 | wcd_clsh_buck_ctrl(ctrl, mode, enable: true); |
695 | wcd_clsh_v2_set_hph_mode(comp, mode); |
696 | wcd_clsh_set_gain_path(ctrl, mode); |
697 | } else { |
698 | wcd_clsh_v2_set_hph_mode(comp, mode: CLS_H_NORMAL); |
699 | |
700 | if (mode != CLS_AB) { |
701 | snd_soc_component_update_bits(component: comp, |
702 | WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, |
703 | WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, |
704 | WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); |
705 | wcd_enable_clsh_block(ctrl, enable: false); |
706 | } |
707 | /* set buck and flyback to Default Mode */ |
708 | wcd_clsh_buck_ctrl(ctrl, mode: CLS_H_NORMAL, enable: false); |
709 | wcd_clsh_flyback_ctrl(ctrl, mode: CLS_H_NORMAL, enable: false); |
710 | wcd_clsh_set_flyback_mode(comp, mode: CLS_H_NORMAL); |
711 | wcd_clsh_set_buck_mode(comp, mode: CLS_H_NORMAL); |
712 | wcd_clsh_set_buck_regulator_mode(comp, mode: CLS_H_NORMAL); |
713 | } |
714 | } |
715 | |
716 | static void wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, |
717 | bool is_enable, int mode) |
718 | { |
719 | struct snd_soc_component *component = ctrl->comp; |
720 | |
721 | if (is_enable) { |
722 | wcd_clsh_v3_set_buck_regulator_mode(component, mode); |
723 | wcd_clsh_v3_set_flyback_mode(component, mode); |
724 | wcd_clsh_v3_force_iq_ctl(component, mode, enable: true); |
725 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, enable: true); |
726 | wcd_clsh_v3_set_flyback_current(component, mode); |
727 | wcd_clsh_v3_set_buck_mode(component, mode); |
728 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode, enable: true); |
729 | wcd_clsh_v3_set_hph_mode(component, mode); |
730 | } else { |
731 | wcd_clsh_v3_set_hph_mode(component, mode: CLS_H_NORMAL); |
732 | |
733 | /* set buck and flyback to Default Mode */ |
734 | wcd_clsh_v3_flyback_ctrl(component, ctrl, mode: CLS_H_NORMAL, enable: false); |
735 | wcd_clsh_v3_buck_ctrl(component, ctrl, mode: CLS_H_NORMAL, enable: false); |
736 | wcd_clsh_v3_force_iq_ctl(component, mode: CLS_H_NORMAL, enable: false); |
737 | wcd_clsh_v3_set_flyback_mode(component, mode: CLS_H_NORMAL); |
738 | wcd_clsh_v3_set_buck_mode(component, mode: CLS_H_NORMAL); |
739 | } |
740 | } |
741 | |
742 | static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, |
743 | bool is_enable, int mode) |
744 | { |
745 | struct snd_soc_component *comp = ctrl->comp; |
746 | |
747 | if (mode != CLS_H_NORMAL) { |
748 | dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n" , |
749 | __func__, mode); |
750 | return; |
751 | } |
752 | |
753 | if (is_enable) { |
754 | wcd_enable_clsh_block(ctrl, enable: true); |
755 | snd_soc_component_update_bits(component: comp, |
756 | WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, |
757 | WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, |
758 | WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); |
759 | wcd_clsh_set_buck_mode(comp, mode); |
760 | wcd_clsh_set_flyback_mode(comp, mode); |
761 | wcd_clsh_flyback_ctrl(ctrl, mode, enable: true); |
762 | wcd_clsh_set_flyback_current(comp, mode); |
763 | wcd_clsh_buck_ctrl(ctrl, mode, enable: true); |
764 | } else { |
765 | snd_soc_component_update_bits(component: comp, |
766 | WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, |
767 | WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, |
768 | WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); |
769 | wcd_enable_clsh_block(ctrl, enable: false); |
770 | wcd_clsh_buck_ctrl(ctrl, mode, enable: false); |
771 | wcd_clsh_flyback_ctrl(ctrl, mode, enable: false); |
772 | wcd_clsh_set_flyback_mode(comp, mode: CLS_H_NORMAL); |
773 | wcd_clsh_set_buck_mode(comp, mode: CLS_H_NORMAL); |
774 | } |
775 | } |
776 | |
777 | static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, |
778 | bool is_enable, int mode) |
779 | { |
780 | switch (req_state) { |
781 | case WCD_CLSH_STATE_EAR: |
782 | if (ctrl->codec_version >= WCD937X) |
783 | wcd_clsh_v3_state_ear(ctrl, req_state, is_enable, mode); |
784 | else |
785 | wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); |
786 | break; |
787 | case WCD_CLSH_STATE_HPHL: |
788 | if (ctrl->codec_version >= WCD937X) |
789 | wcd_clsh_v3_state_hph_l(ctrl, req_state, is_enable, mode); |
790 | else |
791 | wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); |
792 | break; |
793 | case WCD_CLSH_STATE_HPHR: |
794 | if (ctrl->codec_version >= WCD937X) |
795 | wcd_clsh_v3_state_hph_r(ctrl, req_state, is_enable, mode); |
796 | else |
797 | wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); |
798 | break; |
799 | case WCD_CLSH_STATE_LO: |
800 | if (ctrl->codec_version < WCD937X) |
801 | wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); |
802 | break; |
803 | case WCD_CLSH_STATE_AUX: |
804 | if (ctrl->codec_version >= WCD937X) |
805 | wcd_clsh_v3_state_aux(ctrl, req_state, is_enable, mode); |
806 | break; |
807 | default: |
808 | break; |
809 | } |
810 | |
811 | return 0; |
812 | } |
813 | |
814 | /* |
815 | * Function: wcd_clsh_is_state_valid |
816 | * Params: state |
817 | * Description: |
818 | * Provides information on valid states of Class H configuration |
819 | */ |
820 | static bool wcd_clsh_is_state_valid(int state) |
821 | { |
822 | switch (state) { |
823 | case WCD_CLSH_STATE_IDLE: |
824 | case WCD_CLSH_STATE_EAR: |
825 | case WCD_CLSH_STATE_HPHL: |
826 | case WCD_CLSH_STATE_HPHR: |
827 | case WCD_CLSH_STATE_LO: |
828 | case WCD_CLSH_STATE_AUX: |
829 | return true; |
830 | default: |
831 | return false; |
832 | }; |
833 | } |
834 | |
835 | /* |
836 | * Function: wcd_clsh_fsm |
837 | * Params: ctrl, req_state, req_type, clsh_event |
838 | * Description: |
839 | * This function handles PRE DAC and POST DAC conditions of different devices |
840 | * and updates class H configuration of different combination of devices |
841 | * based on validity of their states. ctrl will contain current |
842 | * class h state information |
843 | */ |
844 | int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, |
845 | enum wcd_clsh_event clsh_event, |
846 | int nstate, |
847 | enum wcd_clsh_mode mode) |
848 | { |
849 | struct snd_soc_component *comp = ctrl->comp; |
850 | |
851 | if (nstate == ctrl->state) |
852 | return 0; |
853 | |
854 | if (!wcd_clsh_is_state_valid(state: nstate)) { |
855 | dev_err(comp->dev, "Class-H not a valid new state:\n" ); |
856 | return -EINVAL; |
857 | } |
858 | |
859 | switch (clsh_event) { |
860 | case WCD_CLSH_EVENT_PRE_DAC: |
861 | _wcd_clsh_ctrl_set_state(ctrl, req_state: nstate, CLSH_REQ_ENABLE, mode); |
862 | break; |
863 | case WCD_CLSH_EVENT_POST_PA: |
864 | _wcd_clsh_ctrl_set_state(ctrl, req_state: nstate, CLSH_REQ_DISABLE, mode); |
865 | break; |
866 | } |
867 | |
868 | ctrl->state = nstate; |
869 | ctrl->mode = mode; |
870 | |
871 | return 0; |
872 | } |
873 | EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_set_state); |
874 | |
875 | int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) |
876 | { |
877 | return ctrl->state; |
878 | } |
879 | EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_get_state); |
880 | |
881 | struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, |
882 | int version) |
883 | { |
884 | struct wcd_clsh_ctrl *ctrl; |
885 | |
886 | ctrl = kzalloc(size: sizeof(*ctrl), GFP_KERNEL); |
887 | if (!ctrl) |
888 | return ERR_PTR(error: -ENOMEM); |
889 | |
890 | ctrl->state = WCD_CLSH_STATE_IDLE; |
891 | ctrl->comp = comp; |
892 | ctrl->codec_version = version; |
893 | |
894 | return ctrl; |
895 | } |
896 | EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_alloc); |
897 | |
898 | void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) |
899 | { |
900 | kfree(objp: ctrl); |
901 | } |
902 | EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_free); |
903 | |
904 | MODULE_DESCRIPTION("WCD93XX Class-H driver" ); |
905 | MODULE_LICENSE("GPL" ); |
906 | |