blob: 73dc1f8ef087f9c07c8719495c0a720eaad449ec [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Laxminath Kasam7adc34e2018-11-09 11:24:38 +05302/*
Laxminath Kasamea2b0582018-12-03 20:30:02 +05303 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
Laxminath Kasam7adc34e2018-11-09 11:24:38 +05304 */
5
6#include <linux/module.h>
7#include <linux/slab.h>
8#include <sound/soc.h>
9#include <linux/kernel.h>
10#include <linux/delay.h>
11#include <asoc/wcd9xxx_registers.h>
Meng Wang11a25cf2018-10-31 14:11:26 +080012#include <asoc/wcd-clsh.h>
Laxminath Kasam7adc34e2018-11-09 11:24:38 +053013
14#define WCD_USLEEP_RANGE 50
15
Meng Wang15c825d2018-09-06 10:49:18 +080016static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_component *,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +053017 struct wcd_clsh_cdc_info *,
18 u8 req_state, bool en, int mode);
19
20static const char *mode_to_str(int mode)
21{
22 switch (mode) {
23 case CLS_H_NORMAL:
24 return WCD_CLSH_STRINGIFY(CLS_H_NORMAL);
25 case CLS_H_HIFI:
26 return WCD_CLSH_STRINGIFY(CLS_H_HIFI);
27 case CLS_H_LOHIFI:
28 return WCD_CLSH_STRINGIFY(CLS_H_LOHIFI);
29 case CLS_H_LP:
30 return WCD_CLSH_STRINGIFY(CLS_H_LP);
31 case CLS_H_ULP:
32 return WCD_CLSH_STRINGIFY(CLS_H_ULP);
33 case CLS_AB:
34 return WCD_CLSH_STRINGIFY(CLS_AB);
35 case CLS_AB_HIFI:
36 return WCD_CLSH_STRINGIFY(CLS_AB_HIFI);
Karthikeyan Mani7f609a32019-05-17 16:59:53 -070037 case CLS_AB_LP:
38 return WCD_CLSH_STRINGIFY(CLS_AB_LP);
39 case CLS_AB_LOHIFI:
40 return WCD_CLSH_STRINGIFY(CLS_AB_LOHIFI);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +053041 default:
42 return WCD_CLSH_STRINGIFY(CLS_H_INVALID);
43 };
44}
45
46static const char *state_to_str(u8 state, char *buf, size_t buflen)
47{
48 int i;
49 int cnt = 0;
50 /*
51 * This array of strings should match with enum wcd_clsh_state_bit.
52 */
53 static const char *const states[] = {
54 "STATE_EAR",
55 "STATE_HPH_L",
56 "STATE_HPH_R",
57 "STATE_AUX",
58 };
59
60 if (state == WCD_CLSH_STATE_IDLE) {
61 snprintf(buf, buflen, "[STATE_IDLE]");
62 goto done;
63 }
64
65 buf[0] = '\0';
66 for (i = 0; i < ARRAY_SIZE(states); i++) {
67 if (!(state & (1 << i)))
68 continue;
69 cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
70 buf[0] == '\0' ? "[" : "|",
71 states[i]);
72 }
73 if (cnt > 0)
74 strlcat(buf + cnt, "]", buflen);
75
76done:
77 if (buf[0] == '\0')
78 snprintf(buf, buflen, "[STATE_UNKNOWN]");
79 return buf;
80}
81
82static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_info *clsh_d,
83 int clsh_state)
84{
85 int mode;
86
87 if ((clsh_state != WCD_CLSH_STATE_EAR) &&
88 (clsh_state != WCD_CLSH_STATE_HPHL) &&
89 (clsh_state != WCD_CLSH_STATE_HPHR) &&
90 (clsh_state != WCD_CLSH_STATE_AUX))
91 mode = CLS_NONE;
92 else
93 mode = clsh_d->interpolator_modes[ffs(clsh_state)];
94
95 return mode;
96}
97
98static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_info *clsh_d,
99 int clsh_state, int mode)
100{
101 if ((clsh_state != WCD_CLSH_STATE_EAR) &&
102 (clsh_state != WCD_CLSH_STATE_HPHL) &&
103 (clsh_state != WCD_CLSH_STATE_HPHR) &&
104 (clsh_state != WCD_CLSH_STATE_AUX))
105 return;
106
107 clsh_d->interpolator_modes[ffs(clsh_state)] = mode;
108}
109
Meng Wang15c825d2018-09-06 10:49:18 +0800110static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530111 int mode)
112{
113 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
Karthikeyan Mani7f609a32019-05-17 16:59:53 -0700114 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI)
Meng Wang15c825d2018-09-06 10:49:18 +0800115 snd_soc_component_update_bits(component,
116 WCD9XXX_ANA_RX_SUPPLIES,
117 0x08, 0x08); /* set to HIFI */
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530118 else
Meng Wang15c825d2018-09-06 10:49:18 +0800119 snd_soc_component_update_bits(component,
120 WCD9XXX_ANA_RX_SUPPLIES,
121 0x08, 0x00); /* set to default */
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530122}
123
Meng Wang15c825d2018-09-06 10:49:18 +0800124static inline void wcd_clsh_set_flyback_mode(
125 struct snd_soc_component *component,
126 int mode)
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530127{
128 if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
Karthikeyan Mani7f609a32019-05-17 16:59:53 -0700129 mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) {
Meng Wang15c825d2018-09-06 10:49:18 +0800130 snd_soc_component_update_bits(component,
131 WCD9XXX_ANA_RX_SUPPLIES,
132 0x04, 0x04);
133 snd_soc_component_update_bits(component,
134 WCD9XXX_FLYBACK_VNEG_CTRL_4,
135 0xF0, 0x80);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530136 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800137 snd_soc_component_update_bits(component,
138 WCD9XXX_ANA_RX_SUPPLIES,
139 0x04, 0x00); /* set to Default */
140 snd_soc_component_update_bits(component,
141 WCD9XXX_FLYBACK_VNEG_CTRL_4,
142 0xF0, 0x70);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530143 }
144}
145
Meng Wang15c825d2018-09-06 10:49:18 +0800146static inline void wcd_clsh_force_iq_ctl(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530147 int mode, bool enable)
148{
149 if (enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800150 snd_soc_component_update_bits(component,
151 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
152 0xE0, 0xA0);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530153 /* 100usec delay is needed as per HW requirement */
154 usleep_range(100, 110);
Meng Wang15c825d2018-09-06 10:49:18 +0800155 snd_soc_component_update_bits(component,
156 WCD9XXX_CLASSH_MODE_3,
157 0x02, 0x02);
158 snd_soc_component_update_bits(component,
159 WCD9XXX_CLASSH_MODE_2,
160 0xFF, 0x1C);
Karthikeyan Mani7f609a32019-05-17 16:59:53 -0700161 if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) {
Meng Wang15c825d2018-09-06 10:49:18 +0800162 snd_soc_component_update_bits(component,
163 WCD9XXX_HPH_NEW_INT_PA_MISC2,
164 0x20, 0x20);
165 snd_soc_component_update_bits(component,
166 WCD9XXX_RX_BIAS_HPH_LOWPOWER,
167 0xF0, 0xC0);
168 snd_soc_component_update_bits(component,
169 WCD9XXX_HPH_PA_CTL1,
170 0x0E, 0x02);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530171 }
172 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800173 snd_soc_component_update_bits(component,
174 WCD9XXX_HPH_NEW_INT_PA_MISC2,
175 0x20, 0x00);
176 snd_soc_component_update_bits(component,
177 WCD9XXX_RX_BIAS_HPH_LOWPOWER,
178 0xF0, 0x80);
179 snd_soc_component_update_bits(component,
180 WCD9XXX_HPH_PA_CTL1,
181 0x0E, 0x06);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530182 }
183}
184
Meng Wang15c825d2018-09-06 10:49:18 +0800185static void wcd_clsh_buck_ctrl(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530186 struct wcd_clsh_cdc_info *clsh_d,
187 int mode,
188 bool enable)
189{
190 /* enable/disable buck */
191 if ((enable && (++clsh_d->buck_users == 1)) ||
192 (!enable && (--clsh_d->buck_users == 0))) {
Meng Wang15c825d2018-09-06 10:49:18 +0800193 snd_soc_component_update_bits(component,
194 WCD9XXX_ANA_RX_SUPPLIES,
195 (1 << 7), (enable << 7));
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530196 /*
197 * 500us sleep is required after buck enable/disable
198 * as per HW requirement
199 */
200 usleep_range(500, 510);
201 if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP ||
202 mode == CLS_H_HIFI || mode == CLS_H_LP)
Meng Wang15c825d2018-09-06 10:49:18 +0800203 snd_soc_component_update_bits(component,
204 WCD9XXX_CLASSH_MODE_3,
205 0x02, 0x00);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530206
Meng Wang15c825d2018-09-06 10:49:18 +0800207 snd_soc_component_update_bits(component,
208 WCD9XXX_CLASSH_MODE_2,
209 0xFF, 0x3A);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530210 /* 500usec delay is needed as per HW requirement */
211 usleep_range(500, 500 + WCD_USLEEP_RANGE);
212 }
Meng Wang15c825d2018-09-06 10:49:18 +0800213 dev_dbg(component->dev, "%s: buck_users %d, enable %d, mode: %s\n",
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530214 __func__, clsh_d->buck_users, enable, mode_to_str(mode));
215}
216
Meng Wang15c825d2018-09-06 10:49:18 +0800217static void wcd_clsh_flyback_ctrl(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530218 struct wcd_clsh_cdc_info *clsh_d,
219 int mode,
220 bool enable)
221{
222 /* enable/disable flyback */
223 if ((enable && (++clsh_d->flyback_users == 1)) ||
224 (!enable && (--clsh_d->flyback_users == 0))) {
Meng Wang15c825d2018-09-06 10:49:18 +0800225 snd_soc_component_update_bits(component,
Laxminath Kasamf16ed2f2019-03-13 12:21:26 +0530226 WCD9XXX_FLYBACK_VNEG_CTRL_1,
227 0xE0, 0xE0);
228 snd_soc_component_update_bits(component,
Meng Wang15c825d2018-09-06 10:49:18 +0800229 WCD9XXX_ANA_RX_SUPPLIES,
230 (1 << 6), (enable << 6));
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530231 /*
232 * 100us sleep is required after flyback enable/disable
233 * as per HW requirement
234 */
235 usleep_range(100, 110);
Meng Wang15c825d2018-09-06 10:49:18 +0800236 snd_soc_component_update_bits(component,
237 WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
238 0xE0, 0xE0);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530239 /* 500usec delay is needed as per HW requirement */
240 usleep_range(500, 500 + WCD_USLEEP_RANGE);
241 }
Meng Wang15c825d2018-09-06 10:49:18 +0800242 dev_dbg(component->dev, "%s: flyback_users %d, enable %d, mode: %s\n",
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530243 __func__, clsh_d->flyback_users, enable, mode_to_str(mode));
244}
245
Karthikeyan Manib9d78072019-06-21 14:15:23 -0700246/*
247 * Function: wcd_clsh_set_hph_mode
248 * Params: soc component, hph mode class
249 * Description:
250 * This function updates class H mode configuration based on
251 * the input mode.
252 */
253void wcd_clsh_set_hph_mode(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530254 int mode)
255{
256 u8 val = 0;
257
258 switch (mode) {
259 case CLS_H_NORMAL:
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530260 val = 0x00;
261 break;
262 case CLS_AB:
263 case CLS_H_ULP:
264 val = 0x0C;
265 break;
266 case CLS_AB_HIFI:
267 case CLS_H_HIFI:
268 val = 0x08;
269 break;
270 case CLS_H_LP:
Laxminath Kasamea2b0582018-12-03 20:30:02 +0530271 case CLS_H_LOHIFI:
Karthikeyan Mani7f609a32019-05-17 16:59:53 -0700272 case CLS_AB_LP:
273 case CLS_AB_LOHIFI:
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530274 val = 0x04;
275 break;
276 default:
Meng Wang15c825d2018-09-06 10:49:18 +0800277 dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530278 return;
279 };
280
Meng Wang15c825d2018-09-06 10:49:18 +0800281 snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530282}
Karthikeyan Manib9d78072019-06-21 14:15:23 -0700283EXPORT_SYMBOL(wcd_clsh_set_hph_mode);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530284
Meng Wang15c825d2018-09-06 10:49:18 +0800285static void wcd_clsh_set_flyback_current(struct snd_soc_component *component,
286 int mode)
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530287{
Meng Wang15c825d2018-09-06 10:49:18 +0800288 snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF,
289 0x0F, 0x0A);
290 snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF,
291 0xF0, 0xA0);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530292 /* Sleep needed to avoid click and pop as per HW requirement */
293 usleep_range(100, 110);
294}
295
Meng Wang15c825d2018-09-06 10:49:18 +0800296static void wcd_clsh_set_buck_regulator_mode(
297 struct snd_soc_component *component,
298 int mode)
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530299{
Meng Wang15c825d2018-09-06 10:49:18 +0800300 snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530301 0x02, 0x00);
302}
303
Meng Wang15c825d2018-09-06 10:49:18 +0800304static void wcd_clsh_state_ear_aux(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530305 struct wcd_clsh_cdc_info *clsh_d,
306 u8 req_state, bool is_enable, int mode)
307{
Meng Wang15c825d2018-09-06 10:49:18 +0800308 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
309 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530310}
311
Meng Wang15c825d2018-09-06 10:49:18 +0800312static void wcd_clsh_state_hph_aux(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530313 struct wcd_clsh_cdc_info *clsh_d,
314 u8 req_state, bool is_enable, int mode)
315{
Meng Wang15c825d2018-09-06 10:49:18 +0800316 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
317 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530318}
319
Meng Wang15c825d2018-09-06 10:49:18 +0800320static void wcd_clsh_state_hph_ear(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530321 struct wcd_clsh_cdc_info *clsh_d,
322 u8 req_state, bool is_enable, int mode)
323{
Meng Wang15c825d2018-09-06 10:49:18 +0800324 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
325 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530326}
327
Meng Wang15c825d2018-09-06 10:49:18 +0800328static void wcd_clsh_state_hph_st(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530329 struct wcd_clsh_cdc_info *clsh_d,
330 u8 req_state, bool is_enable, int mode)
331{
Meng Wang15c825d2018-09-06 10:49:18 +0800332 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
333 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530334}
335
Meng Wang15c825d2018-09-06 10:49:18 +0800336static void wcd_clsh_state_hph_r(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530337 struct wcd_clsh_cdc_info *clsh_d,
338 u8 req_state, bool is_enable, int mode)
339{
Meng Wang15c825d2018-09-06 10:49:18 +0800340 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
341 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530342
343 if (mode == CLS_H_NORMAL) {
Meng Wang15c825d2018-09-06 10:49:18 +0800344 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n",
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530345 __func__);
346 return;
347 }
348
349 if (is_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800350 wcd_clsh_set_buck_regulator_mode(component, mode);
351 wcd_clsh_set_flyback_mode(component, mode);
352 wcd_clsh_force_iq_ctl(component, mode, true);
353 wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
354 wcd_clsh_set_flyback_current(component, mode);
355 wcd_clsh_set_buck_mode(component, mode);
356 wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
357 wcd_clsh_set_hph_mode(component, mode);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530358 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800359 wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530360
361 /* buck and flyback set to default mode and disable */
Meng Wang15c825d2018-09-06 10:49:18 +0800362 wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
363 wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
364 wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false);
365 wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
366 wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530367 }
368}
369
Meng Wang15c825d2018-09-06 10:49:18 +0800370static void wcd_clsh_state_hph_l(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530371 struct wcd_clsh_cdc_info *clsh_d,
372 u8 req_state, bool is_enable, int mode)
373{
Meng Wang15c825d2018-09-06 10:49:18 +0800374 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
375 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530376
377 if (mode == CLS_H_NORMAL) {
Meng Wang15c825d2018-09-06 10:49:18 +0800378 dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n",
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530379 __func__);
380 return;
381 }
382
383 if (is_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800384 wcd_clsh_set_buck_regulator_mode(component, mode);
385 wcd_clsh_set_flyback_mode(component, mode);
386 wcd_clsh_force_iq_ctl(component, mode, true);
387 wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
388 wcd_clsh_set_flyback_current(component, mode);
389 wcd_clsh_set_buck_mode(component, mode);
390 wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
391 wcd_clsh_set_hph_mode(component, mode);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530392 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800393 wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530394
395 /* set buck and flyback to Default Mode */
Meng Wang15c825d2018-09-06 10:49:18 +0800396 wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
397 wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
398 wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false);
399 wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
400 wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530401 }
402}
403
Meng Wang15c825d2018-09-06 10:49:18 +0800404static void wcd_clsh_state_aux(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530405 struct wcd_clsh_cdc_info *clsh_d,
406 u8 req_state, bool is_enable, int mode)
407{
Meng Wang15c825d2018-09-06 10:49:18 +0800408 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
409 mode_to_str(mode), is_enable ? "enable" : "disable");
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530410
411 if (is_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800412 wcd_clsh_set_buck_mode(component, mode);
413 wcd_clsh_set_flyback_mode(component, mode);
414 wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
415 wcd_clsh_set_flyback_current(component, mode);
416 wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530417 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800418 wcd_clsh_buck_ctrl(component, clsh_d, mode, false);
419 wcd_clsh_flyback_ctrl(component, clsh_d, mode, false);
420 wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
421 wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530422 }
423}
424
Meng Wang15c825d2018-09-06 10:49:18 +0800425static void wcd_clsh_state_ear(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530426 struct wcd_clsh_cdc_info *clsh_d,
427 u8 req_state, bool is_enable, int mode)
428{
Meng Wang15c825d2018-09-06 10:49:18 +0800429 dev_dbg(component->dev, "%s: mode: %s, %s\n", __func__,
430 mode_to_str(mode),
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530431 is_enable ? "enable" : "disable");
432
433 if (is_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800434 wcd_clsh_set_buck_regulator_mode(component, mode);
435 wcd_clsh_set_flyback_mode(component, mode);
436 wcd_clsh_force_iq_ctl(component, mode, true);
437 wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
438 wcd_clsh_set_flyback_current(component, mode);
439 wcd_clsh_set_buck_mode(component, mode);
440 wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
441 wcd_clsh_set_hph_mode(component, mode);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530442 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800443 wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530444
445 /* set buck and flyback to Default Mode */
Meng Wang15c825d2018-09-06 10:49:18 +0800446 wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
447 wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
448 wcd_clsh_force_iq_ctl(component, CLS_H_NORMAL, false);
449 wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
450 wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530451 }
452}
453
Meng Wang15c825d2018-09-06 10:49:18 +0800454static void wcd_clsh_state_err(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530455 struct wcd_clsh_cdc_info *clsh_d,
456 u8 req_state, bool is_enable, int mode)
457{
458 char msg[128];
459
Meng Wang15c825d2018-09-06 10:49:18 +0800460 dev_err(component->dev,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530461 "%s Wrong request for class H state machine requested to %s %s\n",
462 __func__, is_enable ? "enable" : "disable",
463 state_to_str(req_state, msg, sizeof(msg)));
464}
465
466/*
467 * Function: wcd_clsh_is_state_valid
468 * Params: state
469 * Description:
470 * Provides information on valid states of Class H configuration
471 */
472static bool wcd_clsh_is_state_valid(u8 state)
473{
474 switch (state) {
475 case WCD_CLSH_STATE_IDLE:
476 case WCD_CLSH_STATE_EAR:
477 case WCD_CLSH_STATE_HPHL:
478 case WCD_CLSH_STATE_HPHR:
479 case WCD_CLSH_STATE_HPH_ST:
480 case WCD_CLSH_STATE_AUX:
481 case WCD_CLSH_STATE_HPHL_AUX:
482 case WCD_CLSH_STATE_HPHR_AUX:
483 case WCD_CLSH_STATE_HPH_ST_AUX:
484 case WCD_CLSH_STATE_EAR_AUX:
Laxminath Kasamade14442019-09-19 18:39:21 +0530485 case WCD_CLSH_STATE_HPHL_EAR:
486 case WCD_CLSH_STATE_HPHR_EAR:
487 case WCD_CLSH_STATE_HPH_ST_EAR:
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530488 return true;
489 default:
490 return false;
491 };
492}
493
494/*
495 * Function: wcd_cls_h_fsm
Meng Wang15c825d2018-09-06 10:49:18 +0800496 * Params: component, cdc_clsh_d, req_state, req_type, clsh_event
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530497 * Description:
498 * This function handles PRE DAC and POST DAC conditions of different devices
499 * and updates class H configuration of different combination of devices
500 * based on validity of their states. cdc_clsh_d will contain current
501 * class h state information
502 */
Meng Wang15c825d2018-09-06 10:49:18 +0800503void wcd_cls_h_fsm(struct snd_soc_component *component,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530504 struct wcd_clsh_cdc_info *cdc_clsh_d,
505 u8 clsh_event, u8 req_state,
506 int int_mode)
507{
508 u8 old_state, new_state;
509 char msg0[128], msg1[128];
510
511 switch (clsh_event) {
512 case WCD_CLSH_EVENT_PRE_DAC:
513 old_state = cdc_clsh_d->state;
514 new_state = old_state | req_state;
515
516 if (!wcd_clsh_is_state_valid(new_state)) {
Meng Wang15c825d2018-09-06 10:49:18 +0800517 dev_err(component->dev,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530518 "%s: Class-H not a valid new state: %s\n",
519 __func__,
520 state_to_str(new_state, msg0, sizeof(msg0)));
521 return;
522 }
523 if (new_state == old_state) {
Meng Wang15c825d2018-09-06 10:49:18 +0800524 dev_err(component->dev,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530525 "%s: Class-H already in requested state: %s\n",
526 __func__,
527 state_to_str(new_state, msg0, sizeof(msg0)));
528 return;
529 }
530 cdc_clsh_d->state = new_state;
531 wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode);
Meng Wang15c825d2018-09-06 10:49:18 +0800532 (*clsh_state_fp[new_state]) (component, cdc_clsh_d, req_state,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530533 CLSH_REQ_ENABLE, int_mode);
Meng Wang15c825d2018-09-06 10:49:18 +0800534 dev_dbg(component->dev,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530535 "%s: ClassH state transition from %s to %s\n",
536 __func__, state_to_str(old_state, msg0, sizeof(msg0)),
537 state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
538 break;
539 case WCD_CLSH_EVENT_POST_PA:
540 old_state = cdc_clsh_d->state;
541 new_state = old_state & (~req_state);
542 if (new_state < NUM_CLSH_STATES) {
543 if (!wcd_clsh_is_state_valid(old_state)) {
Meng Wang15c825d2018-09-06 10:49:18 +0800544 dev_err(component->dev,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530545 "%s:Invalid old state:%s\n",
546 __func__,
547 state_to_str(old_state, msg0,
548 sizeof(msg0)));
549 return;
550 }
551 if (new_state == old_state) {
Meng Wang15c825d2018-09-06 10:49:18 +0800552 dev_err(component->dev,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530553 "%s: Class-H already in requested state: %s\n",
554 __func__,
555 state_to_str(new_state, msg0,
556 sizeof(msg0)));
557 return;
558 }
Meng Wang15c825d2018-09-06 10:49:18 +0800559 (*clsh_state_fp[old_state]) (component, cdc_clsh_d,
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530560 req_state, CLSH_REQ_DISABLE,
561 int_mode);
562 cdc_clsh_d->state = new_state;
563 wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE);
Meng Wang15c825d2018-09-06 10:49:18 +0800564 dev_dbg(component->dev, "%s: ClassH state transition from %s to %s\n",
Laxminath Kasam7adc34e2018-11-09 11:24:38 +0530565 __func__, state_to_str(old_state, msg0,
566 sizeof(msg0)),
567 state_to_str(cdc_clsh_d->state, msg1,
568 sizeof(msg1)));
569 }
570 break;
571 };
572}
573EXPORT_SYMBOL(wcd_cls_h_fsm);
574
575/*
576 * wcd_cls_h_init: Called to init clsh info
577 *
578 * @clsh: pointer for clsh state information.
579 */
580void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh)
581{
582 int i;
583
584 clsh->state = WCD_CLSH_STATE_IDLE;
585
586 for (i = 0; i < NUM_CLSH_STATES; i++)
587 clsh_state_fp[i] = wcd_clsh_state_err;
588
589 clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
590 clsh_state_fp[WCD_CLSH_STATE_HPHL] = wcd_clsh_state_hph_l;
591 clsh_state_fp[WCD_CLSH_STATE_HPHR] = wcd_clsh_state_hph_r;
592 clsh_state_fp[WCD_CLSH_STATE_HPH_ST] = wcd_clsh_state_hph_st;
593 clsh_state_fp[WCD_CLSH_STATE_AUX] = wcd_clsh_state_aux;
594 clsh_state_fp[WCD_CLSH_STATE_HPHL_AUX] = wcd_clsh_state_hph_aux;
595 clsh_state_fp[WCD_CLSH_STATE_HPHR_AUX] = wcd_clsh_state_hph_aux;
596 clsh_state_fp[WCD_CLSH_STATE_HPH_ST_AUX] =
597 wcd_clsh_state_hph_aux;
598 clsh_state_fp[WCD_CLSH_STATE_EAR_AUX] = wcd_clsh_state_ear_aux;
599 clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] = wcd_clsh_state_hph_ear;
600 clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] = wcd_clsh_state_hph_ear;
601 clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] = wcd_clsh_state_hph_ear;
602 /* Set interpolaotr modes to NONE */
603 wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE);
604 wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE);
605 wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE);
606 wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_AUX, CLS_NONE);
607 clsh->flyback_users = 0;
608 clsh->buck_users = 0;
609}
610EXPORT_SYMBOL(wcd_cls_h_init);
611
612MODULE_DESCRIPTION("WCD Class-H Driver");
613MODULE_LICENSE("GPL v2");