xref: /openbmc/linux/sound/soc/codecs/wcd-clsh-v2.c (revision 7f1005dd)
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 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(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(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 				0x08, 0x08); /* set to HIFI */
155 	else
156 		snd_soc_component_update_bits(component,
157 				WCD9XXX_ANA_RX_SUPPLIES,
158 				0x08, 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(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(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(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
185 				WCD9XXX_A_ANA_RX_VPOS_EN_MASK,
186 				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(500, 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 				(1 << 7), (enable << 7));
205 		/*
206 		 * 500us sleep is required after buck enable/disable
207 		 * as per HW requirement
208 		 */
209 		usleep_range(500, 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 					0x02, 0x00);
215 
216 		snd_soc_component_update_bits(component,
217 					WCD9XXX_CLASSH_MODE_2,
218 					0xFF, 0x3A);
219 		/* 500usec delay is needed as per HW requirement */
220 		usleep_range(500, 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(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
234 				WCD9XXX_A_ANA_RX_VNEG_EN_MASK,
235 				enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT);
236 		/* 100usec delay is needed as per HW requirement */
237 		usleep_range(100, 110);
238 	}
239 	/*
240 	 * 500us sleep is required after flyback enable/disable
241 	 * as per HW requirement
242 	 */
243 	usleep_range(500, 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(comp, WCD9XXX_HPH_L_EN,
265 					WCD9XXX_HPH_CONST_SEL_L_MASK,
266 					val);
267 
268 	snd_soc_component_update_bits(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(comp, WCD9XXX_A_ANA_HPH,
303 					WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val);
304 	snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2,
305 				WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK,
306 				res_val);
307 	if (mode != CLS_H_LP)
308 		snd_soc_component_update_bits(comp,
309 					WCD9XXX_HPH_REFBUFF_UHQA_CTL,
310 					WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK,
311 					gain);
312 	snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1,
313 				WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK,
314 				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, 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(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(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
365 				WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A);
366 	snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
367 				WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A);
368 	/* Sleep needed to avoid click and pop as per HW requirement */
369 	usleep_range(100, 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(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(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 			    0x02, 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 				0x04, 0x04);
400 		snd_soc_component_update_bits(component,
401 				WCD9XXX_FLYBACK_VNEG_CTRL_4,
402 				0xF0, 0x80);
403 	} else {
404 		snd_soc_component_update_bits(component,
405 				WCD9XXX_ANA_RX_SUPPLIES,
406 				0x04, 0x00); /* set to Default */
407 		snd_soc_component_update_bits(component,
408 				WCD9XXX_FLYBACK_VNEG_CTRL_4,
409 				0xF0, 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 				0xE0, 0xA0);
420 		/* 100usec delay is needed as per HW requirement */
421 		usleep_range(100, 110);
422 		snd_soc_component_update_bits(component,
423 				WCD9XXX_CLASSH_MODE_3,
424 				0x02, 0x02);
425 		snd_soc_component_update_bits(component,
426 				WCD9XXX_CLASSH_MODE_2,
427 				0xFF, 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 					0x20, 0x20);
432 			snd_soc_component_update_bits(component,
433 					WCD9XXX_RX_BIAS_HPH_LOWPOWER,
434 					0xF0, 0xC0);
435 			snd_soc_component_update_bits(component,
436 					WCD9XXX_HPH_PA_CTL1,
437 					0x0E, 0x02);
438 		}
439 	} else {
440 		snd_soc_component_update_bits(component,
441 				WCD9XXX_HPH_NEW_INT_PA_MISC2,
442 				0x20, 0x00);
443 		snd_soc_component_update_bits(component,
444 				WCD9XXX_RX_BIAS_HPH_LOWPOWER,
445 				0xF0, 0x80);
446 		snd_soc_component_update_bits(component,
447 				WCD9XXX_HPH_PA_CTL1,
448 				0x0E, 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 				0xE0, 0xE0);
463 		snd_soc_component_update_bits(component,
464 				WCD9XXX_ANA_RX_SUPPLIES,
465 				(1 << 6), (enable << 6));
466 		/*
467 		 * 100us sleep is required after flyback enable/disable
468 		 * as per HW requirement
469 		 */
470 		usleep_range(100, 110);
471 		snd_soc_component_update_bits(component,
472 				WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
473 				0xE0, 0xE0);
474 		/* 500usec delay is needed as per HW requirement */
475 		usleep_range(500, 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 				0x0F, 0x0A);
484 	snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF,
485 				0xF0, 0xA0);
486 	/* Sleep needed to avoid click and pop as per HW requirement */
487 	usleep_range(100, 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, true);
499 		wcd_clsh_v3_set_flyback_current(component, mode);
500 		wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true);
501 	} else {
502 		wcd_clsh_v3_buck_ctrl(component, ctrl, mode, false);
503 		wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, false);
504 		wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
505 		wcd_clsh_v3_set_buck_mode(component, 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, true);
525 		wcd_clsh_set_flyback_current(comp, mode);
526 		wcd_clsh_buck_ctrl(ctrl, mode, true);
527 	} else {
528 		wcd_clsh_buck_ctrl(ctrl, mode, false);
529 		wcd_clsh_flyback_ctrl(ctrl, mode, false);
530 		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
531 		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
532 		wcd_clsh_set_buck_regulator_mode(comp, 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, true);
551 		wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, 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, true);
555 		wcd_clsh_v3_set_hph_mode(component, mode);
556 	} else {
557 		wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL);
558 
559 		/* buck and flyback set to default mode and disable */
560 		wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false);
561 		wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false);
562 		wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false);
563 		wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
564 		wcd_clsh_v3_set_buck_mode(component, 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, 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(comp,
587 					WCD9XXX_A_CDC_CLSH_K1_MSB,
588 					WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
589 					0x00);
590 			snd_soc_component_update_bits(comp,
591 					WCD9XXX_A_CDC_CLSH_K1_LSB,
592 					WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
593 					0xC0);
594 			snd_soc_component_update_bits(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, true);
602 		wcd_clsh_set_flyback_current(comp, mode);
603 		wcd_clsh_set_buck_mode(comp, mode);
604 		wcd_clsh_buck_ctrl(ctrl, mode, 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, CLS_H_NORMAL);
609 
610 		if (mode != CLS_AB) {
611 			snd_soc_component_update_bits(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, false);
616 		}
617 		/* buck and flyback set to default mode and disable */
618 		wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
619 		wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
620 		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
621 		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
622 		wcd_clsh_set_buck_regulator_mode(comp, 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, true);
641 		wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, 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, true);
645 		wcd_clsh_v3_set_hph_mode(component, mode);
646 	} else {
647 		wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL);
648 
649 		/* set buck and flyback to Default Mode */
650 		wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false);
651 		wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false);
652 		wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false);
653 		wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
654 		wcd_clsh_v3_set_buck_mode(component, 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, 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(comp,
677 					WCD9XXX_A_CDC_CLSH_K1_MSB,
678 					WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
679 					0x00);
680 			snd_soc_component_update_bits(comp,
681 					WCD9XXX_A_CDC_CLSH_K1_LSB,
682 					WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
683 					0xC0);
684 			snd_soc_component_update_bits(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, true);
692 		wcd_clsh_set_flyback_current(comp, mode);
693 		wcd_clsh_set_buck_mode(comp, mode);
694 		wcd_clsh_buck_ctrl(ctrl, mode, 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, CLS_H_NORMAL);
699 
700 		if (mode != CLS_AB) {
701 			snd_soc_component_update_bits(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, false);
706 		}
707 		/* set buck and flyback to Default Mode */
708 		wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
709 		wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
710 		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
711 		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
712 		wcd_clsh_set_buck_regulator_mode(comp, 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, true);
725 		wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, 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, true);
729 		wcd_clsh_v3_set_hph_mode(component, mode);
730 	} else {
731 		wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL);
732 
733 		/* set buck and flyback to Default Mode */
734 		wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false);
735 		wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false);
736 		wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false);
737 		wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL);
738 		wcd_clsh_v3_set_buck_mode(component, 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, true);
755 		snd_soc_component_update_bits(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, true);
762 		wcd_clsh_set_flyback_current(comp, mode);
763 		wcd_clsh_buck_ctrl(ctrl, mode, true);
764 	} else {
765 		snd_soc_component_update_bits(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, false);
770 		wcd_clsh_buck_ctrl(ctrl, mode, false);
771 		wcd_clsh_flyback_ctrl(ctrl, mode, false);
772 		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
773 		wcd_clsh_set_buck_mode(comp, 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(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, nstate, CLSH_REQ_ENABLE, mode);
862 		break;
863 	case WCD_CLSH_EVENT_POST_PA:
864 		_wcd_clsh_ctrl_set_state(ctrl, 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(sizeof(*ctrl), GFP_KERNEL);
887 	if (!ctrl)
888 		return ERR_PTR(-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(ctrl);
901 }
902 EXPORT_SYMBOL_GPL(wcd_clsh_ctrl_free);
903 
904 MODULE_DESCRIPTION("WCD93XX Class-H driver");
905 MODULE_LICENSE("GPL");
906