Merge tag 'block-5.14-2021-08-20' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / sound / soc / codecs / wcd-clsh-v2.c
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 }