blob: b89afa960668997537cd582cdf0bd44cec2c7109 [file] [log] [blame]
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -08001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <sound/soc.h>
15#include <linux/kernel.h>
16#include <linux/delay.h>
17#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
18#include "wcd9xxx-common.h"
19
20#define CLSH_COMPUTE_EAR 0x01
21#define CLSH_COMPUTE_HPH_L 0x02
22#define CLSH_COMPUTE_HPH_R 0x03
23
24#define BUCK_VREF_2V 0xFF
25#define BUCK_VREF_1P8V 0xE6
26
27#define NCP_FCLK_LEVEL_8 0x08
28#define NCP_FCLK_LEVEL_5 0x05
29
30#define BUCK_SETTLE_TIME_US 50
31#define NCP_SETTLE_TIME_US 50
32
33static inline void wcd9xxx_enable_clsh_block(
34 struct snd_soc_codec *codec,
35 bool on)
36{
37 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
38 0x01, on ? 0x01 : 0x00);
39}
40
41static inline void wcd9xxx_enable_anc_delay(
42 struct snd_soc_codec *codec,
43 bool on)
44{
45 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
46 0x02, on ? 0x02 : 0x00);
47}
48
49static inline void wcd9xxx_enable_ncp(
50 struct snd_soc_codec *codec,
51 bool on)
52{
53 snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
54 0x01, on ? 0x01 : 0x00);
55}
56
57static inline void wcd9xxx_enable_buck(
58 struct snd_soc_codec *codec,
59 bool on)
60{
61 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
62 0x80, on ? 0x80 : 0x00);
63}
64
65static int cdc_lo_count;
66
67static void (*clsh_state_fp[NUM_CLSH_STATES])
68 (struct snd_soc_codec *,
69 struct wcd9xxx_clsh_cdc_data *,
70 u8 req_state, bool req_type);
71
72static const char *state_to_str(u8 state)
73{
74 if (state == WCD9XXX_CLSH_STATE_IDLE)
75 return "STATE_IDLE";
76 else if (state == WCD9XXX_CLSH_STATE_EAR)
77 return "STATE_EAR";
78 else if (state == WCD9XXX_CLSH_STATE_HPHL)
79 return "STATE_HPH_L";
80 else if (state == WCD9XXX_CLSH_STATE_HPHR)
81 return "STATE_HPH_R";
82 else if (state == (WCD9XXX_CLSH_STATE_HPHL
83 | WCD9XXX_CLSH_STATE_HPHR))
84 return "STATE_HPH_L_R";
85 else if (state == WCD9XXX_CLSH_STATE_LO)
86 return "STATE_LO";
87
88 return "UNKNOWN_STATE";
89}
90
91static void wcd9xxx_cfg_clsh_buck(
92 struct snd_soc_codec *codec)
93{
94 int i;
95 const struct wcd9xxx_reg_mask_val reg_set[] = {
96 {WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
97 {WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
98 {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
99 {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
100 };
101
102 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
103 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
104 reg_set[i].val);
105
106 dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
107}
108
109static void wcd9xxx_cfg_clsh_param_common(
110 struct snd_soc_codec *codec)
111{
112 int i;
113 const struct wcd9xxx_reg_mask_val reg_set[] = {
114 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
115 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
116 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
117 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
118 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
119 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
120 {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
121 {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
122 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
123 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
124 };
125
126 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
127 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
128 reg_set[i].val);
129
130 dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
131 __func__);
132}
133
134static void wcd9xxx_chargepump_request(
135 struct snd_soc_codec *codec, bool on)
136{
137 static int cp_count;
138
139 if (on && (++cp_count == 1)) {
140 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
141 0x01, 0x01);
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800142 dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800143 __func__, cp_count);
144 }
145
146 else if (!on) {
147 if (--cp_count < 0) {
148 dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
149 __func__);
150 if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
151 & 0x01) {
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800152 dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800153 __func__);
154 }
155 cp_count = 0;
156 WARN_ON(1);
157 }
158
159 if (cp_count == 0) {
160 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
161 0x01, 0x00);
162 dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
163 __func__, cp_count);
164 }
165 }
166}
167
Joonwoo Parka08e0552013-03-05 18:28:23 -0800168static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
169 struct wcd9xxx_clsh_cdc_data *clsh_d,
170 int compute_pa, bool on)
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800171{
Joonwoo Parka08e0552013-03-05 18:28:23 -0800172 u8 shift;
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800173
Joonwoo Parka08e0552013-03-05 18:28:23 -0800174 if (compute_pa == CLSH_COMPUTE_EAR) {
175 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10,
176 (on ? 0x10 : 0));
177 } else {
178 if (compute_pa == CLSH_COMPUTE_HPH_L) {
179 shift = 3;
180 } else if (compute_pa == CLSH_COMPUTE_HPH_R) {
181 shift = 2;
182 } else {
183 dev_dbg(codec->dev,
184 "%s: classh computation request is incorrect\n",
185 __func__);
186 return;
187 }
188
189 if (on)
190 wcd9xxx_resmgr_add_cond_update_bits(clsh_d->resmgr,
191 WCD9XXX_COND_HPH,
192 WCD9XXX_A_CDC_CLSH_B1_CTL,
193 shift, false);
194 else
195 wcd9xxx_resmgr_rm_cond_update_bits(clsh_d->resmgr,
196 WCD9XXX_COND_HPH,
197 WCD9XXX_A_CDC_CLSH_B1_CTL,
198 shift, false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800199 }
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800200}
201
202static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
203 u8 buck_vref)
204{
205 int i;
206 const struct wcd9xxx_reg_mask_val reg_set[] = {
207 {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
208 {WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
209 {WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
210 {WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
211 {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
212 {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
213 {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
214 };
215
216 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
217 snd_soc_update_bits(codec, reg_set[i].reg,
218 reg_set[i].mask, reg_set[i].val);
219
220 dev_dbg(codec->dev, "%s: Done\n", __func__);
221 usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
222}
223
Bhalchandra Gajare7c739522013-06-20 15:31:02 -0700224
225/* This will be called for all states except Lineout */
226static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec,
227 struct wcd9xxx_clsh_cdc_data *cdc_clsh_d)
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800228{
229 int i;
230 const struct wcd9xxx_reg_mask_val reg_set[] = {
231 {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
232 {WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
233 {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800234 };
235
236 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
237 snd_soc_update_bits(codec, reg_set[i].reg,
238 reg_set[i].mask, reg_set[i].val);
239
Bhalchandra Gajare7c739522013-06-20 15:31:02 -0700240 if (!cdc_clsh_d->is_dynamic_vdd_cp)
241 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_3,
242 0x08, 0x08);
243
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800244 dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
245 __func__);
246
247}
248
249static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
250 u8 fclk_level)
251{
252 int i;
253 const struct wcd9xxx_reg_mask_val reg_set[] = {
254 {WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
255 {WCD9XXX_A_NCP_EN, 0x01, 0x01},
256 };
257 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
258 0x010, 0x00);
259 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
260 0x0F, fclk_level);
261 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
262 snd_soc_update_bits(codec, reg_set[i].reg,
263 reg_set[i].mask, reg_set[i].val);
264
265 usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
266
267 dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
268}
269
270static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
271{
272 int i;
273 const struct wcd9xxx_reg_mask_val reg_set[] = {
274 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
275 {WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
276 {WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
277
278 /* Under assumption that EAR load is 10.7ohm */
279 {WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
280 {WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
281 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
282 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
283 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
284 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
285 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
286 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
287 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
288 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
289 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
290 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
291 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
292 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
293 };
294
295 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
296 snd_soc_update_bits(codec, reg_set[i].reg,
297 reg_set[i].mask, reg_set[i].val);
298
299 dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
300 __func__);
301}
302
303static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
304{
305 int i;
306 const struct wcd9xxx_reg_mask_val reg_set[] = {
307 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
308 {WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
309 {WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
310
311 /* Under assumption that HPH load is 16ohm per channel */
312 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
313 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
314 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
315 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
316 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
317 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
318 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
319 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
320 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
321 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
322 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
323 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
324 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
325 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
326 };
327
328 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
329 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
330 reg_set[i].val);
331 dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
332 __func__);
333}
334
335static void wcd9xxx_clsh_turnoff_postpa
336 (struct snd_soc_codec *codec)
337{
338
339 int i;
340
341 const struct wcd9xxx_reg_mask_val reg_set[] = {
342 {WCD9XXX_A_NCP_EN, 0x01, 0x00},
343 {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
344 {WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
345 };
346
347 wcd9xxx_chargepump_request(codec, false);
348
349 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
350 snd_soc_update_bits(codec, reg_set[i].reg,
351 reg_set[i].mask, reg_set[i].val);
352
353 wcd9xxx_enable_clsh_block(codec, false);
354
355 dev_dbg(codec->dev, "%s: Done\n", __func__);
356}
357
358static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
359 struct wcd9xxx_clsh_cdc_data *clsh_d,
360 u8 req_state, bool is_enable)
361{
362 if (is_enable) {
363 dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
364 __func__);
365 } else {
366 if (req_state == WCD9XXX_CLSH_STATE_EAR) {
367 wcd9xxx_clsh_turnoff_postpa(codec);
368 } else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800369 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
370 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800371 wcd9xxx_clsh_turnoff_postpa(codec);
372 } else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800373 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
374 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800375 wcd9xxx_clsh_turnoff_postpa(codec);
376 } else if (req_state == WCD9XXX_CLSH_STATE_LO) {
377 wcd9xxx_enable_ncp(codec, false);
378 wcd9xxx_enable_buck(codec, false);
379 }
380 }
381}
382
383static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
384 struct wcd9xxx_clsh_cdc_data *clsh_d,
385 u8 req_state, bool is_enable)
386{
387 if (is_enable) {
388 wcd9xxx_cfg_clsh_buck(codec);
389 wcd9xxx_cfg_clsh_param_common(codec);
390 wcd9xxx_cfg_clsh_param_ear(codec);
391 wcd9xxx_enable_clsh_block(codec, true);
392 wcd9xxx_chargepump_request(codec, true);
393 wcd9xxx_enable_anc_delay(codec, true);
Joonwoo Parka08e0552013-03-05 18:28:23 -0800394 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800395 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
396 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
397
398 dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
399 } else {
400 dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
401 }
402}
403
404static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
405 struct wcd9xxx_clsh_cdc_data *clsh_d,
406 u8 req_state, bool is_enable)
407{
408 if (is_enable) {
409 wcd9xxx_cfg_clsh_buck(codec);
410 wcd9xxx_cfg_clsh_param_common(codec);
411 wcd9xxx_cfg_clsh_param_hph(codec);
412 wcd9xxx_enable_clsh_block(codec, true);
413 wcd9xxx_chargepump_request(codec, true);
414 wcd9xxx_enable_anc_delay(codec, true);
Joonwoo Parka08e0552013-03-05 18:28:23 -0800415 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800416 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
417 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
418
419 dev_dbg(codec->dev, "%s: Done\n", __func__);
420 } else {
421 if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800422 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
423 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800424 } else {
425 dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
426 __func__);
427 }
428 }
429}
430
431static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
432 struct wcd9xxx_clsh_cdc_data *clsh_d,
433 u8 req_state, bool is_enable)
434{
435 if (is_enable) {
436
437 wcd9xxx_cfg_clsh_buck(codec);
438 wcd9xxx_cfg_clsh_param_common(codec);
439 wcd9xxx_cfg_clsh_param_hph(codec);
440 wcd9xxx_enable_clsh_block(codec, true);
441 wcd9xxx_chargepump_request(codec, true);
442 wcd9xxx_enable_anc_delay(codec, true);
Joonwoo Parka08e0552013-03-05 18:28:23 -0800443 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800444 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
445 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
446
447 dev_dbg(codec->dev, "%s: Done\n", __func__);
448 } else {
449 if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800450 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
451 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800452 } else {
453 dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
454 __func__);
455 }
456 }
457}
458
459static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
460 struct wcd9xxx_clsh_cdc_data *clsh_d,
461 u8 req_state, bool is_enable)
462{
463 if (is_enable) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800464 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
465 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800466 } else {
467 dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
468 }
469}
470
471static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
472 struct wcd9xxx_clsh_cdc_data *clsh_d,
473 u8 req_state, bool is_enable)
474{
475 if (is_enable) {
476 if (++cdc_lo_count > 1)
477 return;
478
479 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
480 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
481
482 if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
483 wcd9xxx_enable_buck(codec, false);
484 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
485 0x20, 0x01);
486 wcd9xxx_enable_ncp(codec, true);
487 msleep(NCP_SETTLE_TIME_US);
488
489 } else {
490 snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
491 0x40, 0x00);
492 wcd9xxx_enable_ncp(codec, true);
493 msleep(NCP_SETTLE_TIME_US);
494 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
495 0x01, 0x01);
496 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
497 0xFB, (0x02 << 2));
498 }
499 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
500 0x04, 0x00);
501 } else {
502 dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
503 }
504}
505
506static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
507 struct wcd9xxx_clsh_cdc_data *clsh_d,
508 u8 req_state, bool is_enable)
509{
510 dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
511 , __func__, is_enable ? "enable" : "disable",
512 state_to_str(req_state));
513 WARN_ON(1);
514}
515
516void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
517 struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
518 u8 req_state, bool req_type, u8 clsh_event)
519{
520 u8 old_state, new_state;
521
522 switch (clsh_event) {
523
524 case WCD9XXX_CLSH_EVENT_PRE_DAC:
525
526 /* PRE_DAC event should be used only for Enable */
527 BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
528
529 old_state = cdc_clsh_d->state;
530 new_state = old_state | req_state;
531
532 (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
533 req_state, req_type);
534 cdc_clsh_d->state = new_state;
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800535 dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800536 __func__, state_to_str(old_state),
537 state_to_str(cdc_clsh_d->state));
538
539 break;
540
541 case WCD9XXX_CLSH_EVENT_POST_PA:
542
543 if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
544 if (req_state == WCD9XXX_CLSH_STATE_LO
545 && --cdc_lo_count > 0)
546 break;
547
548 old_state = cdc_clsh_d->state;
549 new_state = old_state & (~req_state);
550
551 if (new_state < NUM_CLSH_STATES) {
552 (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
553 req_state, req_type);
554 cdc_clsh_d->state = new_state;
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800555 dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800556 __func__, state_to_str(old_state),
557 state_to_str(cdc_clsh_d->state));
558
559 } else {
560 dev_dbg(codec->dev, "%s: wrong new state = %x\n",
561 __func__, new_state);
562 }
563
564
565 } else if (req_state != WCD9XXX_CLSH_STATE_LO) {
Bhalchandra Gajare7c739522013-06-20 15:31:02 -0700566 wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800567 }
568
569 break;
570 }
571
572}
573EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
574
Joonwoo Parka08e0552013-03-05 18:28:23 -0800575void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
576 struct wcd9xxx_resmgr *resmgr)
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800577{
578 int i;
579 clsh->state = WCD9XXX_CLSH_STATE_IDLE;
Joonwoo Parka08e0552013-03-05 18:28:23 -0800580 clsh->resmgr = resmgr;
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800581
582 for (i = 0; i < NUM_CLSH_STATES; i++)
583 clsh_state_fp[i] = wcd9xxx_clsh_state_err;
584
585 clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
586 clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
587 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
588 wcd9xxx_clsh_state_hph_l;
589 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
590 wcd9xxx_clsh_state_hph_r;
591 clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
592 wcd9xxx_clsh_state_hph_st;
593 clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
594
595}
596EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
597
598MODULE_DESCRIPTION("WCD9XXX Common");
599MODULE_LICENSE("GPL v2");