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