blob: 7b2e68a211b009dbe5ab43d48a4694f6d1e6aac2 [file] [log] [blame]
Banajit Goswamide8271c2017-01-18 00:28:59 -08001/* Copyright (c) 2013-2015, 2017 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 <linux/slab.h>
15#include <sound/soc.h>
16#include <linux/kernel.h>
17#include <linux/delay.h>
18#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
19#include "wcd9xxx-common.h"
20
21#define CLSH_COMPUTE_EAR 0x01
22#define CLSH_COMPUTE_HPH_L 0x02
23#define CLSH_COMPUTE_HPH_R 0x03
24
25#define BUCK_VREF_0P494V 0x3F
26#define BUCK_VREF_2V 0xFF
27#define BUCK_VREF_0P494V 0x3F
28#define BUCK_VREF_1P8V 0xE6
29
30#define BUCK_SETTLE_TIME_US 50
31#define NCP_SETTLE_TIME_US 50
32
33#define MAX_IMPED_PARAMS 13
34
35#define USLEEP_RANGE_MARGIN_US 100
36
37struct wcd9xxx_imped_val {
38 u32 imped_val;
39 u8 index;
40};
41
42static const struct wcd9xxx_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
43 {
44 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x46},
45 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
46 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
47 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
48 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
49 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
50 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
51 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
52 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
53 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
54 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
55 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x04},
56 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
57 },
58 {
59 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x47},
60 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
61 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
62 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
63 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
64 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
65 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
66 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
67 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
68 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
69 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
70 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x05},
71 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
72 },
73 {
74 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
75 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
76 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
77 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
78 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
79 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
80 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
81 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
82 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
83 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
84 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
85 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
86 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0E},
87 },
88 {
89 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
90 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
91 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
92 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
93 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
94 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x17},
95 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
96 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x5F},
97 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
98 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCF},
99 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
100 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
101 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0F},
102 },
103 {
104 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x59},
105 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x15},
106 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
107 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9C},
108 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
109 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
110 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
111 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCE},
112 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
113 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
114 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
115 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
116 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x10},
117 },
118 {
119 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x66},
120 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
121 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
122 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9A},
123 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
124 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
125 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
126 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
127 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
128 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
129 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
130 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
131 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x11},
132 },
133 {
134 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
135 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
136 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
137 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
138 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
139 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
140 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
141 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
142 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
143 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
144 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
145 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x08},
146 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
147 },
148 {
149 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x76},
150 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
151 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
152 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
153 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
154 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
155 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
156 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
157 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
158 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
159 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
160 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x09},
161 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
162 },
163 {
164 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
165 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
166 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
167 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
168 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
169 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
170 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
171 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
172 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
173 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
174 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
175 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0A},
176 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x13},
177 },
178 {
179 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x7A},
180 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
181 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
182 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
183 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
184 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
185 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
186 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
187 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
188 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
189 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
190 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0B},
191 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
192 },
193 {
194 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x60},
195 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x09},
196 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
197 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
198 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
199 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
200 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
201 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
202 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
203 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
204 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
205 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0C},
206 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
207 },
208 {
209 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
210 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
211 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
212 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
213 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
214 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
215 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
216 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
217 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
218 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
219 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
220 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0D},
221 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x15},
222 },
223 {
224 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
225 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
226 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
227 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
228 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
229 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
230 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
231 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
232 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
233 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
234 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
235 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0E},
236 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
237 },
238 {
239 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x89},
240 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
241 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
242 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x40},
243 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
244 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
245 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
246 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
247 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
248 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
249 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
250 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x10},
251 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
252 },
253 {
254 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
255 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
256 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
257 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
258 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
259 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
260 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
261 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
262 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
263 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
264 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
265 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x12},
266 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
267 },
268 {
269 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
270 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
271 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
272 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
273 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
274 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
275 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
276 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
277 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
278 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
279 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
280 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x13},
281 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
282 },
283 {
284 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
285 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
286 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
287 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
288 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
289 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
290 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
291 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
292 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
293 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
294 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
295 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x15},
296 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
297 },
298 {
299 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
300 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x08},
301 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
302 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
303 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
304 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
305 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
306 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
307 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
308 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
309 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
310 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x18},
311 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
312 },
313 {
314 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8B},
315 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x18},
316 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
317 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
318 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
319 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
320 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
321 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x20},
322 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
323 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
324 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
325 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1A},
326 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
327 },
328 {
329 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
330 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
331 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
332 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
333 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
334 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
335 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
336 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
337 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
338 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
339 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
340 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1D},
341 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x1A},
342 },
343 {
344 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
345 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
346 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
347 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
348 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
349 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
350 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
351 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
352 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
353 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
354 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
355 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1F},
356 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
357 },
358 {
359 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xB9},
360 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
361 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
362 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
363 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
364 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
365 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
366 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
367 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
368 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
369 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
370 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x23},
371 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
372 },
373 {
374 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
375 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
376 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
377 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
378 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
379 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
380 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
381 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
382 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
383 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
384 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
385 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x26},
386 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
387 },
388};
389
390static const struct wcd9xxx_imped_val imped_index[] = {
391 {4000, 0},
392 {4500, 1},
393 {5000, 2},
394 {5500, 3},
395 {6000, 4},
396 {6500, 5},
397 {7000, 6},
398 {7700, 7},
399 {8470, 8},
400 {9317, 9},
401 {10248, 10},
402 {11273, 11},
403 {12400, 12},
404 {13641, 13},
405 {15005, 14},
406 {16505, 15},
407 {18156, 16},
408 {19971, 17},
409 {21969, 18},
410 {24165, 19},
411 {26582, 20},
412 {29240, 21},
413 {32164, 22},
414};
415
416static inline void
417wcd9xxx_enable_clsh_block(struct snd_soc_codec *codec,
418 struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
419{
420 if ((enable && ++clsh_d->clsh_users == 1) ||
421 (!enable && --clsh_d->clsh_users == 0))
422 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
423 0x01, enable ? 0x01 : 0x00);
424 dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
425 clsh_d->clsh_users, enable);
426}
427
428static inline void wcd9xxx_enable_anc_delay(
429 struct snd_soc_codec *codec,
430 bool on)
431{
432 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
433 0x02, on ? 0x02 : 0x00);
434}
435
436static inline void
437wcd9xxx_enable_buck(struct snd_soc_codec *codec,
438 struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
439{
440 if ((enable && ++clsh_d->buck_users == 1) ||
441 (!enable && --clsh_d->buck_users == 0))
442 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
443 0x80, enable ? 0x80 : 0x00);
444 dev_dbg(codec->dev, "%s: buck_users %d, enable %d", __func__,
445 clsh_d->buck_users, enable);
446}
447
448static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
449 struct wcd9xxx_clsh_cdc_data *,
450 u8 req_state, bool req_type);
451
452static const char *state_to_str(u8 state, char *buf, size_t buflen)
453{
454 int i;
455 int cnt = 0;
456 /*
457 * This array of strings should match with enum wcd9xxx_clsh_state_bit.
458 */
459 static const char *const states[] = {
460 "STATE_EAR",
461 "STATE_HPH_L",
462 "STATE_HPH_R",
463 "STATE_LO",
464 };
465
466 if (state == WCD9XXX_CLSH_STATE_IDLE) {
467 snprintf(buf, buflen, "[STATE_IDLE]");
468 goto done;
469 }
470
471 buf[0] = '\0';
472 for (i = 0; i < ARRAY_SIZE(states); i++) {
473 if (!(state & (1 << i)))
474 continue;
475 cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
476 buf[0] == '\0' ? "[" : "|",
477 states[i]);
478 }
479 if (cnt > 0)
480 strlcat(buf + cnt, "]", buflen);
481
482done:
483 if (buf[0] == '\0')
484 snprintf(buf, buflen, "[STATE_UNKNOWN]");
485 return buf;
486}
487
488static void wcd9xxx_cfg_clsh_param_common(
489 struct snd_soc_codec *codec)
490{
491 int i;
492 const struct wcd9xxx_reg_mask_val reg_set[] = {
493 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
494 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
495 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
496 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
497 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
498 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
499 {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
500 {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
501 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
502 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
503 };
504
505 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
506 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
507 reg_set[i].val);
508
509 dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
510 __func__);
511}
512
513static void wcd9xxx_chargepump_request(struct snd_soc_codec *codec, bool on)
514{
515 static int cp_count;
516
517 if (on && (++cp_count == 1)) {
518 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
519 0x01, 0x01);
520 dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
521 __func__, cp_count);
522 } else if (!on) {
523 if (--cp_count < 0) {
524 dev_dbg(codec->dev,
525 "%s: Unbalanced disable for charge pump\n",
526 __func__);
527 if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL) &
528 0x01) {
529 dev_dbg(codec->dev,
530 "%s: Actual chargepump is ON\n",
531 __func__);
532 }
533 cp_count = 0;
534 WARN_ON(1);
535 }
536
537 if (cp_count == 0) {
538 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
539 0x01, 0x00);
540 dev_dbg(codec->dev,
541 "%s: Charge pump disabled, count = %d\n",
542 __func__, cp_count);
543 }
544 }
545}
546
547void wcd9xxx_enable_high_perf_mode(struct snd_soc_codec *codec,
548 struct wcd9xxx_clsh_cdc_data *clsh_d,
549 u8 uhqa_mode, u8 req_state, bool req_type)
550{
551 dev_dbg(codec->dev, "%s: users fclk8 %d, fclk5 %d", __func__,
552 clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
553 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
554
555 if (req_type == WCD9XXX_CLSAB_REQ_ENABLE) {
556 clsh_d->ncp_users[NCP_FCLK_LEVEL_8]++;
557 snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_PA,
558 WCD9XXX_A_RX_HPH_BIAS_PA__POR);
559 snd_soc_write(codec, WCD9XXX_A_RX_HPH_L_PA_CTL, 0x48);
560 snd_soc_write(codec, WCD9XXX_A_RX_HPH_R_PA_CTL, 0x48);
561 if (uhqa_mode)
562 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CHOP_CTL,
563 0x20, 0x00);
564 wcd9xxx_chargepump_request(codec, true);
565 wcd9xxx_enable_anc_delay(codec, true);
566 wcd9xxx_enable_buck(codec, clsh_d, false);
567 if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
568 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
569 0x0F, 0x08);
570 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x30, 0x30);
571
572 /* Enable NCP and wait until settles down */
573 if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
574 usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US+10);
575 } else {
576 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CHOP_CTL,
577 0x20, 0x20);
578 snd_soc_write(codec, WCD9XXX_A_RX_HPH_L_PA_CTL,
579 WCD9XXX_A_RX_HPH_L_PA_CTL__POR);
580 snd_soc_write(codec, WCD9XXX_A_RX_HPH_R_PA_CTL,
581 WCD9XXX_A_RX_HPH_R_PA_CTL__POR);
582 snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_PA, 0x57);
583 wcd9xxx_enable_buck(codec, clsh_d, true);
584 wcd9xxx_chargepump_request(codec, false);
585 wcd9xxx_enable_anc_delay(codec, false);
586 clsh_d->ncp_users[NCP_FCLK_LEVEL_8]--;
587 if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
588 clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
589 snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
590 0x01, 0x00);
591 else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
592 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
593 0x0F, 0x05);
594 }
595 dev_dbg(codec->dev, "%s: leave\n", __func__);
596}
597EXPORT_SYMBOL(wcd9xxx_enable_high_perf_mode);
598
599static int get_impedance_index(u32 imped)
600{
601 int i = 0;
602
603 if (imped < imped_index[i].imped_val) {
604 pr_debug("%s, detected impedance is less than 4 Ohm\n",
605 __func__);
606 goto ret;
607 }
608 if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) {
609 pr_debug("%s, detected impedance is greater than 32164 Ohm\n",
610 __func__);
611 i = ARRAY_SIZE(imped_index) - 1;
612 goto ret;
613 }
614 for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) {
615 if (imped >= imped_index[i].imped_val &&
616 imped < imped_index[i + 1].imped_val)
617 break;
618 }
619ret:
620 pr_debug("%s: selected impedance index = %d\n",
621 __func__, imped_index[i].index);
622 return imped_index[i].index;
623}
624
625void wcd9xxx_clsh_imped_config(struct snd_soc_codec *codec,
626 int imped)
627{
628 int i = 0;
629 int index = 0;
630
631 index = get_impedance_index(imped);
632 if (index >= ARRAY_SIZE(imped_index)) {
633 pr_err("%s, invalid imped = %d\n", __func__, imped);
634 return;
635 }
636 for (i = 0; i < MAX_IMPED_PARAMS; i++)
637 snd_soc_write(codec, imped_table[index][i].reg,
638 imped_table[index][i].val);
639}
640
641static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
642 struct wcd9xxx_clsh_cdc_data *clsh_d,
643 int compute_pa, bool on)
644{
645 u8 shift;
646
647 if (compute_pa == CLSH_COMPUTE_EAR) {
648 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10,
649 (on ? 0x10 : 0));
650 } else {
651 if (compute_pa == CLSH_COMPUTE_HPH_L) {
652 shift = 3;
653 } else if (compute_pa == CLSH_COMPUTE_HPH_R) {
654 shift = 2;
655 } else {
656 dev_dbg(codec->dev,
657 "%s: classh computation request is incorrect\n",
658 __func__);
659 return;
660 }
661
662 if (on)
663 wcd9xxx_resmgr_add_cond_update_bits(clsh_d->resmgr,
664 WCD9XXX_COND_HPH,
665 WCD9XXX_A_CDC_CLSH_B1_CTL,
666 shift, false);
667 else
668 wcd9xxx_resmgr_rm_cond_update_bits(clsh_d->resmgr,
669 WCD9XXX_COND_HPH,
670 WCD9XXX_A_CDC_CLSH_B1_CTL,
671 shift, false);
672 }
673}
674
675int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
676 struct list_head *list,
677 uint16_t reg, uint8_t mask,
678 uint8_t value, int delay)
679{
680 int rc;
681 struct wcd9xxx_register_save_node *node;
682
683 node = kmalloc(sizeof(*node), GFP_KERNEL);
684 if (unlikely(!node)) {
685 pr_err("%s: Not enough memory\n", __func__);
686 return -ENOMEM;
687 }
688 node->reg = reg;
689 node->value = snd_soc_read(codec, reg);
690 list_add(&node->lh, list);
691 if (mask == 0xFF)
692 rc = snd_soc_write(codec, reg, value);
693 else
694 rc = snd_soc_update_bits(codec, reg, mask, value);
695 if (delay)
696 usleep_range(delay, delay + USLEEP_RANGE_MARGIN_US);
697 return rc;
698}
699EXPORT_SYMBOL(wcd9xxx_soc_update_bits_push);
700
701void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
702 struct list_head *lh)
703{
704 struct wcd9xxx_register_save_node *node, *nodetmp;
705
706 list_for_each_entry_safe(node, nodetmp, lh, lh) {
707 snd_soc_write(codec, node->reg, node->value);
708 list_del(&node->lh);
709 kfree(node);
710 }
711}
712EXPORT_SYMBOL(wcd9xxx_restore_registers);
713
714static void wcd9xxx_dynamic_bypass_buck_ctrl_lo(struct snd_soc_codec *cdc,
715 bool enable)
716{
717 int i;
718 const struct wcd9xxx_reg_mask_val reg_set[] = {
719 {WCD9XXX_A_BUCK_MODE_3, (0x1 << 3), (enable << 3)},
720 {WCD9XXX_A_BUCK_MODE_5, enable ? 0xFF : 0x02, 0x02},
721 {WCD9XXX_A_BUCK_MODE_5, 0x1, 0x01}
722 };
723
724 if (!enable) {
725 snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_1,
726 (0x1 << 3), 0x00);
727 snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_4,
728 0xFF, BUCK_VREF_2V);
729 }
730 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
731 snd_soc_update_bits(cdc, reg_set[i].reg, reg_set[i].mask,
732 reg_set[i].val);
733
734 /* 50us sleep is reqd. as per the class H HW design sequence */
735 usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
736}
737
738static void wcd9xxx_dynamic_bypass_buck_ctrl(struct snd_soc_codec *cdc,
739 bool enable)
740{
741 int i;
742 const struct wcd9xxx_reg_mask_val reg_set[] = {
743 {WCD9XXX_A_BUCK_MODE_3, (0x1 << 3), (enable << 3)},
744 {WCD9XXX_A_BUCK_MODE_5, (0x1 << 1), ((!enable) << 1)},
745 {WCD9XXX_A_BUCK_MODE_5, 0x1, !enable}
746 };
747 if (!enable) {
748 snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_1,
749 (0x1 << 3), 0x00);
750 snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_4,
751 0xFF, BUCK_VREF_2V);
752 }
753 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
754 snd_soc_update_bits(cdc, reg_set[i].reg, reg_set[i].mask,
755 reg_set[i].val);
756
757 /* 50us sleep is reqd. as per the class H HW design sequence */
758 usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
759}
760
761static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
762{
763 int i;
764 const struct wcd9xxx_reg_mask_val reg_set[] = {
765 {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x02},
766 {WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
767 {WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
768 {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
769 {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
770 };
771
772 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
773 snd_soc_update_bits(codec, reg_set[i].reg,
774 reg_set[i].mask, reg_set[i].val);
775
776 dev_dbg(codec->dev, "%s: Done\n", __func__);
777 usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US + 10);
778}
779
780
781/* This will be called for all states except Lineout */
782static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec,
783 struct wcd9xxx_clsh_cdc_data *cdc_clsh_d)
784{
785 int i;
786 const struct wcd9xxx_reg_mask_val reg_set[] = {
787 {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
788 {WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
789 {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
790 };
791
792 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
793 snd_soc_update_bits(codec, reg_set[i].reg,
794 reg_set[i].mask, reg_set[i].val);
795
796 if (!cdc_clsh_d->is_dynamic_vdd_cp)
797 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_3,
798 0x08, 0x08);
799
800 dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
801 __func__);
802
803}
804
805static void wcd9xxx_set_fclk_get_ncp(struct snd_soc_codec *codec,
806 struct wcd9xxx_clsh_cdc_data *clsh_d,
807 enum ncp_fclk_level fclk_level)
808{
809 clsh_d->ncp_users[fclk_level]++;
810
811 pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
812 fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
813 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
814
815 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x10, 0x00);
816 /* fclk level 8 dominates level 5 */
817 if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
818 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x08);
819 else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_5] > 0)
820 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
821 else
822 WARN_ONCE(1, "Unexpected users %d,%d\n",
823 clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
824 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
825 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x20, 0x20);
826
827 /* enable NCP and wait until settles down */
828 if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
829 usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US + 50);
830 pr_debug("%s: leave\n", __func__);
831}
832
833static void wcd9xxx_set_fclk_put_ncp(struct snd_soc_codec *codec,
834 struct wcd9xxx_clsh_cdc_data *clsh_d,
835 enum ncp_fclk_level fclk_level)
836{
837 clsh_d->ncp_users[fclk_level]--;
838
839 pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
840 fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
841 clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
842
843 if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
844 clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
845 snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x00);
846 else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
847 /* if dominating level 8 has gone, switch to 5 */
848 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
849 pr_debug("%s: leave\n", __func__);
850}
851
852static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
853{
854 int i;
855 const struct wcd9xxx_reg_mask_val reg_set[] = {
856 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
857 {WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
858 {WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
859
860 /* Under assumption that EAR load is 10.7ohm */
861 {WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
862 {WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
863 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
864 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
865 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
866 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
867 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
868 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
869 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
870 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
871 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
872 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
873 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
874 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
875 };
876
877 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
878 snd_soc_update_bits(codec, reg_set[i].reg,
879 reg_set[i].mask, reg_set[i].val);
880
881 dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
882 __func__);
883}
884
885static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
886{
887 int i;
888 const struct wcd9xxx_reg_mask_val reg_set[] = {
889 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
890 {WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
891 {WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
892
893 /* Under assumption that HPH load is 16ohm per channel */
894 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
895 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
896 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
897 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
898 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
899 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
900 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
901 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
902 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
903 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
904 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
905 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
906 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
907 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
908 };
909
910 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
911 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
912 reg_set[i].val);
913 dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
914 __func__);
915}
916
917static void wcd9xxx_ncp_bypass_enable(struct snd_soc_codec *cdc, bool enable)
918{
919 snd_soc_update_bits(cdc, WCD9XXX_A_NCP_STATIC, 0x10, (enable << 4));
920 /* 50us sleep is reqd. as per the class H HW design sequence */
921 usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
922}
923
924static void wcd9xxx_clsh_set_Iest(struct snd_soc_codec *codec,
925 u8 value)
926{
927 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
928 0x01, (0x01 & 0x03));
929 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
930 0xFC, (value << 2));
931}
932
933static void wcd9xxx_clsh_state_hph_ear(struct snd_soc_codec *codec,
934 struct wcd9xxx_clsh_cdc_data *clsh_d,
935 u8 req_state, bool is_enable)
936{
937 int compute_pa = 0;
938
939 dev_dbg(codec->dev, "%s: enter %s\n", __func__,
940 is_enable ? "enable" : "disable");
941
942 if (is_enable) {
943 /*
944 * The below check condition is required to make sure
945 * functions inside if condition will execute only once.
946 */
947 if ((clsh_d->state == WCD9XXX_CLSH_STATE_EAR) ||
948 (req_state == WCD9XXX_CLSH_STATE_EAR)) {
949 wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
950 wcd9xxx_ncp_bypass_enable(codec, true);
951 }
952 switch (req_state) {
953 case WCD9XXX_CLSH_STATE_HPHL:
954 compute_pa = CLSH_COMPUTE_HPH_L;
955 break;
956 case WCD9XXX_CLSH_STATE_HPHR:
957 compute_pa = CLSH_COMPUTE_HPH_R;
958 break;
959 case WCD9XXX_CLSH_STATE_EAR:
960 compute_pa = CLSH_COMPUTE_EAR;
961 break;
962 default:
963 dev_dbg(codec->dev,
964 "%s:Invalid state:0x%x,enable:0x%x\n",
965 __func__, req_state, is_enable);
966 break;
967 }
968 wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, true);
969
970 dev_dbg(codec->dev, "%s: Enabled hph+ear mode clsh\n",
971 __func__);
972 } else {
973 switch (req_state) {
974 case WCD9XXX_CLSH_STATE_HPHL:
975 compute_pa = CLSH_COMPUTE_HPH_L;
976 break;
977 case WCD9XXX_CLSH_STATE_HPHR:
978 compute_pa = CLSH_COMPUTE_HPH_R;
979 break;
980 case WCD9XXX_CLSH_STATE_EAR:
981 compute_pa = CLSH_COMPUTE_EAR;
982 break;
983 default:
984 dev_dbg(codec->dev,
985 "%s:Invalid state:0x%x,enable:0x%x\n",
986 __func__, req_state, is_enable);
987 break;
988 }
989 wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, false);
990
991 if (((clsh_d->state & (~req_state)) ==
992 WCD9XXX_CLSH_STATE_EAR) ||
993 (req_state == WCD9XXX_CLSH_STATE_EAR)) {
994 wcd9xxx_ncp_bypass_enable(codec, false);
995 wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
996 }
997 }
998}
999
1000static void wcd9xxx_clsh_state_hph_lo(struct snd_soc_codec *codec,
1001 struct wcd9xxx_clsh_cdc_data *clsh_d,
1002 u8 req_state, bool is_enable)
1003{
1004
1005 dev_dbg(codec->dev, "%s: enter %s\n", __func__,
1006 is_enable ? "enable" : "disable");
1007 if (is_enable) {
1008 if ((clsh_d->state == WCD9XXX_CLSH_STATE_LO) ||
1009 (req_state == WCD9XXX_CLSH_STATE_LO)) {
1010 wcd9xxx_dynamic_bypass_buck_ctrl_lo(codec, false);
1011 wcd9xxx_enable_buck(codec, clsh_d, true);
1012 wcd9xxx_ncp_bypass_enable(codec, true);
1013 if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
1014 wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
1015 NCP_FCLK_LEVEL_8);
1016 wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
1017 NCP_FCLK_LEVEL_5);
1018 wcd9xxx_enable_clsh_block(codec, clsh_d, true);
1019 wcd9xxx_chargepump_request(codec, true);
1020 wcd9xxx_enable_anc_delay(codec, true);
1021 }
1022 }
1023 if (req_state == WCD9XXX_CLSH_STATE_HPHL)
1024 wcd9xxx_clsh_comp_req(codec, clsh_d,
1025 CLSH_COMPUTE_HPH_L, true);
1026 if (req_state == WCD9XXX_CLSH_STATE_HPHR)
1027 wcd9xxx_clsh_comp_req(codec, clsh_d,
1028 CLSH_COMPUTE_HPH_R, true);
1029 } else {
1030 switch (req_state) {
1031 case WCD9XXX_CLSH_STATE_LO:
1032 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
1033 0x20, 0x00);
1034 wcd9xxx_dynamic_bypass_buck_ctrl_lo(codec, true);
1035 break;
1036 case WCD9XXX_CLSH_STATE_HPHL:
1037 wcd9xxx_clsh_comp_req(codec, clsh_d,
1038 CLSH_COMPUTE_HPH_L, false);
1039 break;
1040 case WCD9XXX_CLSH_STATE_HPHR:
1041 wcd9xxx_clsh_comp_req(codec, clsh_d,
1042 CLSH_COMPUTE_HPH_R, false);
1043 break;
1044 default:
1045 dev_dbg(codec->dev,
1046 "%s:Invalid state:0x%x,enable:0x%x\n",
1047 __func__, req_state, is_enable);
1048 break;
1049 }
1050 if ((req_state == WCD9XXX_CLSH_STATE_LO) ||
1051 ((clsh_d->state & (~req_state)) == WCD9XXX_CLSH_STATE_LO)) {
1052 wcd9xxx_ncp_bypass_enable(codec, false);
1053
1054 if ((clsh_d->state & (~req_state)) ==
1055 WCD9XXX_CLSH_STATE_LO) {
1056 wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
1057 NCP_FCLK_LEVEL_5);
1058 wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
1059 NCP_FCLK_LEVEL_8);
1060 }
1061
1062 if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
1063 usleep_range(BUCK_SETTLE_TIME_US,
1064 BUCK_SETTLE_TIME_US + 10);
1065 if (clsh_d->buck_mv ==
1066 WCD9XXX_CDC_BUCK_MV_1P8) {
1067 wcd9xxx_enable_buck(codec, clsh_d,
1068 false);
1069 wcd9xxx_ncp_bypass_enable(codec, true);
1070 } else {
1071 /*
1072 *NCP settle time recommended by codec
1073 *specification
1074 */
1075 usleep_range(NCP_SETTLE_TIME_US,
1076 NCP_SETTLE_TIME_US + 10);
1077 wcd9xxx_clsh_set_Iest(codec, 0x02);
1078 }
1079 snd_soc_update_bits(codec,
1080 WCD9XXX_A_BUCK_MODE_1,
1081 0x04, 0x00);
1082 snd_soc_update_bits(codec,
1083 WCD9XXX_A_BUCK_MODE_4,
1084 0xFF, BUCK_VREF_1P8V);
1085 }
1086 }
1087 }
1088}
1089
1090static void wcd9xxx_clsh_state_ear_lo(struct snd_soc_codec *codec,
1091 struct wcd9xxx_clsh_cdc_data *clsh_d,
1092 u8 req_state, bool is_enable)
1093{
1094
1095 dev_dbg(codec->dev, "%s: enter %s\n", __func__,
1096 is_enable ? "enable" : "disable");
1097 if (is_enable) {
1098 wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
1099 wcd9xxx_enable_buck(codec, clsh_d, true);
1100 wcd9xxx_ncp_bypass_enable(codec, true);
1101 if (req_state & WCD9XXX_CLSH_STATE_EAR) {
1102 wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
1103 NCP_FCLK_LEVEL_8);
1104 wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
1105 NCP_FCLK_LEVEL_5);
1106 wcd9xxx_enable_clsh_block(codec, clsh_d, true);
1107 wcd9xxx_chargepump_request(codec, true);
1108 wcd9xxx_enable_anc_delay(codec, true);
1109 wcd9xxx_clsh_comp_req(codec, clsh_d,
1110 CLSH_COMPUTE_EAR, true);
1111 }
1112 } else {
1113 wcd9xxx_ncp_bypass_enable(codec, false);
1114
1115 if ((clsh_d->state & (~req_state)) == WCD9XXX_CLSH_STATE_LO) {
1116 wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
1117 NCP_FCLK_LEVEL_5);
1118 wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
1119 NCP_FCLK_LEVEL_8);
1120 }
1121
1122 if (req_state & WCD9XXX_CLSH_STATE_LO) {
1123 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
1124 0x20, 0x00);
1125 wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
1126 } else if (req_state & WCD9XXX_CLSH_STATE_EAR) {
1127 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
1128 false);
1129 /*sleep 5ms*/
1130 if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
1131 wcd9xxx_enable_buck(codec, clsh_d, false);
1132 wcd9xxx_ncp_bypass_enable(codec, true);
1133 } else {
1134 /* NCP settle time recommended by codec spec */
1135 usleep_range(NCP_SETTLE_TIME_US,
1136 NCP_SETTLE_TIME_US + 10);
1137 wcd9xxx_clsh_set_Iest(codec, 0x02);
1138 }
1139 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
1140 0x04, 0x00);
1141 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_4,
1142 0xFF, BUCK_VREF_1P8V);
1143 }
1144 }
1145}
1146
1147static void wcd9xxx_clsh_state_hph_ear_lo(struct snd_soc_codec *codec,
1148 struct wcd9xxx_clsh_cdc_data *clsh_d,
1149 u8 req_state, bool is_enable)
1150{
1151 dev_dbg(codec->dev, "%s: enter %s\n", __func__,
1152 is_enable ? "enable" : "disable");
1153
1154 if (req_state & WCD9XXX_CLSH_STATE_HPHL)
1155 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
1156 is_enable);
1157
1158 if (req_state & WCD9XXX_CLSH_STATE_HPHR)
1159 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
1160 is_enable);
1161
1162 if (req_state & WCD9XXX_CLSH_STATE_EAR)
1163 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
1164 is_enable);
1165}
1166
1167static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
1168 struct wcd9xxx_clsh_cdc_data *clsh_d,
1169 u8 req_state, bool is_enable)
1170{
1171 pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
1172 if (is_enable) {
1173 wcd9xxx_cfg_clsh_param_common(codec);
1174 wcd9xxx_cfg_clsh_param_ear(codec);
1175 wcd9xxx_enable_clsh_block(codec, clsh_d, true);
1176 wcd9xxx_chargepump_request(codec, true);
1177 wcd9xxx_enable_anc_delay(codec, true);
1178 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
1179 wcd9xxx_set_buck_mode(codec, BUCK_VREF_2V);
1180 wcd9xxx_enable_buck(codec, clsh_d, true);
1181 wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
1182
1183 dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
1184 } else {
1185 dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
1186 wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
1187 wcd9xxx_enable_buck(codec, clsh_d, false);
1188 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, false);
1189 wcd9xxx_chargepump_request(codec, false);
1190 wcd9xxx_enable_clsh_block(codec, clsh_d, false);
1191 }
1192}
1193
1194static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
1195 struct wcd9xxx_clsh_cdc_data *clsh_d,
1196 u8 req_state, bool is_enable)
1197{
1198 pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
1199
1200 if (is_enable) {
1201 wcd9xxx_cfg_clsh_param_common(codec);
1202 wcd9xxx_cfg_clsh_param_hph(codec);
1203 wcd9xxx_enable_clsh_block(codec, clsh_d, true);
1204 wcd9xxx_chargepump_request(codec, true);
1205 wcd9xxx_enable_anc_delay(codec, true);
1206 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
1207 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
1208 wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
1209 wcd9xxx_enable_buck(codec, clsh_d, true);
1210 wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
1211
1212 dev_dbg(codec->dev, "%s: Done\n", __func__);
1213 } else {
1214 wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
1215 wcd9xxx_enable_buck(codec, clsh_d, false);
1216 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
1217 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
1218 wcd9xxx_enable_clsh_block(codec, clsh_d, false);
1219 wcd9xxx_chargepump_request(codec, false);
1220 }
1221}
1222
1223static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
1224 struct wcd9xxx_clsh_cdc_data *clsh_d,
1225 u8 req_state, bool is_enable)
1226{
1227 pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
1228
1229 if (is_enable) {
1230 wcd9xxx_cfg_clsh_param_common(codec);
1231 wcd9xxx_cfg_clsh_param_hph(codec);
1232 wcd9xxx_enable_clsh_block(codec, clsh_d, true);
1233 wcd9xxx_chargepump_request(codec, true);
1234 wcd9xxx_enable_anc_delay(codec, true);
1235 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
1236 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
1237 wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
1238 wcd9xxx_enable_buck(codec, clsh_d, true);
1239 wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
1240
1241 dev_dbg(codec->dev, "%s: Done\n", __func__);
1242 } else {
1243 wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
1244 wcd9xxx_enable_buck(codec, clsh_d, false);
1245 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
1246 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
1247 wcd9xxx_enable_clsh_block(codec, clsh_d, false);
1248 wcd9xxx_chargepump_request(codec, false);
1249 }
1250}
1251
1252static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
1253 struct wcd9xxx_clsh_cdc_data *clsh_d,
1254 u8 req_state, bool is_enable)
1255{
1256 pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
1257
1258 if (is_enable)
1259 dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
1260 else
1261 dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
1262}
1263
1264static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
1265 struct wcd9xxx_clsh_cdc_data *clsh_d,
1266 u8 req_state, bool is_enable)
1267{
1268 pr_debug("%s: enter %s, buck_mv %d\n", __func__,
1269 is_enable ? "enable" : "disable", clsh_d->buck_mv);
1270
1271 if (is_enable) {
1272 wcd9xxx_set_buck_mode(codec, BUCK_VREF_1P8V);
1273 wcd9xxx_enable_buck(codec, clsh_d, true);
1274 wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
1275
1276 if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
1277 wcd9xxx_enable_buck(codec, clsh_d, false);
1278 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
1279 1 << 4, 1 << 4);
1280 /* NCP settle time recommended by codec specification */
1281 usleep_range(NCP_SETTLE_TIME_US,
1282 NCP_SETTLE_TIME_US + 10);
1283 } else {
1284 /* NCP settle time recommended by codec specification */
1285 usleep_range(NCP_SETTLE_TIME_US,
1286 NCP_SETTLE_TIME_US + 10);
1287 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
1288 0x01, (0x01 & 0x03));
1289 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
1290 0xFC, (0xFC & 0xB));
1291 }
1292 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1, 0x04, 0x00);
1293 } else {
1294 dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
1295 wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
1296 if (clsh_d->buck_mv != WCD9XXX_CDC_BUCK_MV_1P8)
1297 wcd9xxx_enable_buck(codec, clsh_d, false);
1298 }
1299}
1300
1301static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
1302 struct wcd9xxx_clsh_cdc_data *clsh_d,
1303 u8 req_state, bool is_enable)
1304{
1305 char msg[128];
1306
1307 dev_dbg(codec->dev,
1308 "%s Wrong request for class H state machine requested to %s %s",
1309 __func__, is_enable ? "enable" : "disable",
1310 state_to_str(req_state, msg, sizeof(msg)));
1311 WARN_ON(1);
1312}
1313
1314/*
1315 * Function: wcd9xxx_clsh_is_state_valid
1316 * Params: state
1317 * Description:
1318 * Provides information on valid states of Class H configuration
1319 */
1320static int wcd9xxx_clsh_is_state_valid(u8 state)
1321{
1322 switch (state) {
1323 case WCD9XXX_CLSH_STATE_IDLE:
1324 case WCD9XXX_CLSH_STATE_EAR:
1325 case WCD9XXX_CLSH_STATE_HPHL:
1326 case WCD9XXX_CLSH_STATE_HPHR:
1327 case WCD9XXX_CLSH_STATE_HPH_ST:
1328 case WCD9XXX_CLSH_STATE_LO:
1329 case WCD9XXX_CLSH_STATE_HPHL_EAR:
1330 case WCD9XXX_CLSH_STATE_HPHR_EAR:
1331 case WCD9XXX_CLSH_STATE_HPH_ST_EAR:
1332 case WCD9XXX_CLSH_STATE_HPHL_LO:
1333 case WCD9XXX_CLSH_STATE_HPHR_LO:
1334 case WCD9XXX_CLSH_STATE_HPH_ST_LO:
1335 case WCD9XXX_CLSH_STATE_EAR_LO:
1336 case WCD9XXX_CLSH_STATE_HPHL_EAR_LO:
1337 case WCD9XXX_CLSH_STATE_HPHR_EAR_LO:
1338 case WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO:
1339 return 1;
1340 default:
1341 break;
1342 }
1343 return 0;
1344}
1345
1346/*
1347 * Function: wcd9xxx_clsh_fsm
1348 * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
1349 * Description:
1350 * This function handles PRE DAC and POST DAC conditions of different devices
1351 * and updates class H configuration of different combination of devices
1352 * based on validity of their states. cdc_clsh_d will contain current
1353 * class h state information
1354 */
1355void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
1356 struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
1357 u8 req_state, bool req_type, u8 clsh_event)
1358{
1359 u8 old_state, new_state;
1360 char msg0[128], msg1[128];
1361
1362 switch (clsh_event) {
1363 case WCD9XXX_CLSH_EVENT_PRE_DAC:
1364 /* PRE_DAC event should be used only for Enable */
1365 BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
1366
1367 old_state = cdc_clsh_d->state;
1368 new_state = old_state | req_state;
1369
1370 if (!wcd9xxx_clsh_is_state_valid(new_state)) {
1371 dev_dbg(codec->dev,
1372 "%s: classH not a valid new state: %s\n",
1373 __func__,
1374 state_to_str(new_state, msg0, sizeof(msg0)));
1375 return;
1376 }
1377 if (new_state == old_state) {
1378 dev_dbg(codec->dev,
1379 "%s: classH already in requested state: %s\n",
1380 __func__,
1381 state_to_str(new_state, msg0, sizeof(msg0)));
1382 return;
1383 }
1384 (*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
1385 req_type);
1386 cdc_clsh_d->state = new_state;
1387 dev_dbg(codec->dev,
1388 "%s: ClassH state transition from %s to %s\n",
1389 __func__, state_to_str(old_state, msg0, sizeof(msg0)),
1390 state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
1391
1392 break;
1393 case WCD9XXX_CLSH_EVENT_POST_PA:
1394 if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
1395 old_state = cdc_clsh_d->state;
1396 new_state = old_state & (~req_state);
1397
1398 if (new_state < NUM_CLSH_STATES) {
1399 if (!wcd9xxx_clsh_is_state_valid(old_state)) {
1400 dev_dbg(codec->dev,
1401 "%s:Invalid old state:%s\n",
1402 __func__,
1403 state_to_str(old_state, msg0,
1404 sizeof(msg0)));
1405 return;
1406 }
1407 if (new_state == old_state) {
1408 dev_dbg(codec->dev,
1409 "%s: clsH already in old state: %s\n",
1410 __func__,
1411 state_to_str(new_state, msg0,
1412 sizeof(msg0)));
1413 return;
1414 }
1415 (*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
1416 req_state,
1417 req_type);
1418 cdc_clsh_d->state = new_state;
1419 dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
1420 __func__, state_to_str(old_state, msg0,
1421 sizeof(msg0)),
1422 state_to_str(cdc_clsh_d->state, msg1,
1423 sizeof(msg1)));
1424
1425 } else {
1426 dev_dbg(codec->dev, "%s:wrong new state=0x%x\n",
1427 __func__, new_state);
1428 }
1429 } else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
1430 wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
1431 }
1432
1433 break;
1434 }
1435
1436}
1437EXPORT_SYMBOL(wcd9xxx_clsh_fsm);
1438
1439void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
1440 struct wcd9xxx_resmgr *resmgr)
1441{
1442 int i;
1443
1444 clsh->state = WCD9XXX_CLSH_STATE_IDLE;
1445 clsh->resmgr = resmgr;
1446
1447 for (i = 0; i < NUM_CLSH_STATES; i++)
1448 clsh_state_fp[i] = wcd9xxx_clsh_state_err;
1449
1450 clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
1451 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
1452 wcd9xxx_clsh_state_hph_l;
1453 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
1454 wcd9xxx_clsh_state_hph_r;
1455 clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
1456 wcd9xxx_clsh_state_hph_st;
1457 clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
1458 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR] =
1459 wcd9xxx_clsh_state_hph_ear;
1460 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR] =
1461 wcd9xxx_clsh_state_hph_ear;
1462 clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR] =
1463 wcd9xxx_clsh_state_hph_ear;
1464 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_LO] = wcd9xxx_clsh_state_hph_lo;
1465 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_LO] = wcd9xxx_clsh_state_hph_lo;
1466 clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_LO] =
1467 wcd9xxx_clsh_state_hph_lo;
1468 clsh_state_fp[WCD9XXX_CLSH_STATE_EAR_LO] = wcd9xxx_clsh_state_ear_lo;
1469 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR_LO] =
1470 wcd9xxx_clsh_state_hph_ear_lo;
1471 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR_LO] =
1472 wcd9xxx_clsh_state_hph_ear_lo;
1473 clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO] =
1474 wcd9xxx_clsh_state_hph_ear_lo;
1475
1476}
1477EXPORT_SYMBOL(wcd9xxx_clsh_init);
1478
1479MODULE_DESCRIPTION("WCD9XXX Common");
1480MODULE_LICENSE("GPL v2");