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  
wcd_enable_clsh_block(struct wcd_clsh_ctrl * ctrl,bool enable)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  
wcd_clsh_set_buck_mode(struct snd_soc_component * comp,int mode)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  
wcd_clsh_v3_set_buck_mode(struct snd_soc_component * component,int mode)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  
wcd_clsh_set_flyback_mode(struct snd_soc_component * comp,int mode)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  
wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl * ctrl,int mode,bool enable)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  
wcd_clsh_v3_buck_ctrl(struct snd_soc_component * component,struct wcd_clsh_ctrl * ctrl,int mode,bool enable)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  
wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl * ctrl,int mode,bool enable)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  
wcd_clsh_set_gain_path(struct wcd_clsh_ctrl * ctrl,int mode)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  
wcd_clsh_v2_set_hph_mode(struct snd_soc_component * comp,int mode)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  
wcd_clsh_v3_set_hph_mode(struct snd_soc_component * component,int mode)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  
wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl * ctrl,int mode)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  
wcd_clsh_set_flyback_current(struct snd_soc_component * comp,int mode)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  
wcd_clsh_set_buck_regulator_mode(struct snd_soc_component * comp,int mode)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  
wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component * component,int mode)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  
wcd_clsh_v3_set_flyback_mode(struct snd_soc_component * component,int mode)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  
wcd_clsh_v3_force_iq_ctl(struct snd_soc_component * component,int mode,bool enable)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  
wcd_clsh_v3_flyback_ctrl(struct snd_soc_component * component,struct wcd_clsh_ctrl * ctrl,int mode,bool enable)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  
wcd_clsh_v3_set_flyback_current(struct snd_soc_component * component,int mode)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  
wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_state_lo(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_state_hph_r(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_state_hph_l(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
wcd_clsh_state_ear(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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  
_wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl * ctrl,int req_state,bool is_enable,int mode)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   */
wcd_clsh_is_state_valid(int state)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   */
wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl * ctrl,enum wcd_clsh_event clsh_event,int nstate,enum wcd_clsh_mode mode)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  
wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl * ctrl)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  
wcd_clsh_ctrl_alloc(struct snd_soc_component * comp,int version)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  
wcd_clsh_ctrl_free(struct wcd_clsh_ctrl * ctrl)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