blob: 831fa35e957c84587d3a2154dfc269b47d031b76 [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>
Phani Kumar Uppalapati01a77e12013-08-08 15:31:35 -070014#include <linux/slab.h>
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -080015#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
Joonwoo Parkd535b8a2013-08-01 18:44:56 -070025#define BUCK_VREF_0P494V 0x3F
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -080026#define BUCK_VREF_2V 0xFF
27#define BUCK_VREF_1P8V 0xE6
28
29#define NCP_FCLK_LEVEL_8 0x08
30#define NCP_FCLK_LEVEL_5 0x05
31
32#define BUCK_SETTLE_TIME_US 50
33#define NCP_SETTLE_TIME_US 50
34
Santosh Mardi93a69192013-07-03 23:37:29 +053035#define MAX_IMPED_PARAMS 13
36
Phani Kumar Uppalapati01a77e12013-08-08 15:31:35 -070037#define USLEEP_RANGE_MARGIN_US 100
38
Santosh Mardi93a69192013-07-03 23:37:29 +053039struct wcd9xxx_imped_val {
40 u32 imped_val;
41 u8 index;
42};
43
44static const struct wcd9xxx_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
45 {
46 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x46},
47 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
48 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
49 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
50 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
51 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
52 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
53 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
54 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
55 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
56 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
57 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x04},
58 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
59 },
60 {
61 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x47},
62 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
63 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
64 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
65 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
66 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9B},
67 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
68 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x15},
69 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
70 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
71 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
72 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x05},
73 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0C},
74 },
75 {
76 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
77 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
78 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
79 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
80 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
81 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
82 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
83 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
84 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
85 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
86 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
87 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
88 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0E},
89 },
90 {
91 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x49},
92 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
93 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
94 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
95 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
96 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x17},
97 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
98 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x5F},
99 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
100 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCF},
101 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
102 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x06},
103 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x0F},
104 },
105 {
106 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x59},
107 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x15},
108 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
109 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9C},
110 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
111 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
112 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
113 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xCE},
114 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
115 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
116 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
117 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
118 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x10},
119 },
120 {
121 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x66},
122 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
123 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
124 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x9A},
125 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x02},
126 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
127 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
128 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xBD},
129 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
130 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
131 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
132 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x07},
133 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x11},
134 },
135 {
136 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
137 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
138 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
139 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
140 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
141 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
142 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
143 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA6},
144 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
145 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
146 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
147 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x08},
148 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
149 },
150 {
151 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x76},
152 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x04},
153 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
154 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x11},
155 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
156 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x4E},
157 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
158 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAD},
159 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
160 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
161 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
162 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x09},
163 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x12},
164 },
165 {
166 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
167 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
168 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
169 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x12},
170 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
171 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
172 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
173 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
174 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
175 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
176 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
177 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0A},
178 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x13},
179 },
180 {
181 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x7A},
182 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
183 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
184 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
185 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
186 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
187 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
188 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
189 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
190 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
191 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
192 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0B},
193 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
194 },
195 {
196 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x60},
197 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x09},
198 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
199 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
200 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
201 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
202 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
203 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
204 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
205 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
206 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
207 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0C},
208 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x14},
209 },
210 {
211 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x79},
212 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
213 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
214 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
215 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
216 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
217 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
218 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1F},
219 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
220 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
221 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
222 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0D},
223 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x15},
224 },
225 {
226 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x78},
227 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x16},
228 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
229 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
230 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
231 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
232 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
233 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
234 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
235 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
236 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
237 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x0E},
238 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
239 },
240 {
241 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x89},
242 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
243 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
244 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x40},
245 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
246 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
247 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
248 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
249 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
250 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
251 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
252 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x10},
253 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
254 },
255 {
256 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
257 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
258 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
259 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xD0},
260 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
261 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
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_K_DATA, 0xff, 0x1B},
266 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
267 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x12},
268 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
269 },
270 {
271 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
272 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
273 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
274 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xB7},
275 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
276 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
277 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
278 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
279 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
280 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
281 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
282 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x13},
283 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x17},
284 },
285 {
286 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8A},
287 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
288 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
289 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xA4},
290 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
291 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
292 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
293 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
294 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
295 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
296 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
297 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x15},
298 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
299 },
300 {
301 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
302 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x08},
303 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
304 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
305 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
306 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
307 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
308 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
309 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
310 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
311 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
312 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x18},
313 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
314 },
315 {
316 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x8B},
317 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x18},
318 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
319 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAC},
320 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
321 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
322 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
323 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x20},
324 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
325 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
326 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
327 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1A},
328 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
329 },
330 {
331 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x9A},
332 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x17},
333 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
334 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x13},
335 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
336 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1B},
337 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
338 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2E},
339 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
340 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
341 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
342 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1D},
343 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x1A},
344 },
345 {
346 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
347 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
348 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
349 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x14},
350 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
351 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
352 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
353 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2D},
354 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
355 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
356 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
357 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x1F},
358 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x19},
359 },
360 {
361 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xB9},
362 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x06},
363 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
364 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x10},
365 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
366 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
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_K_DATA, 0xff, 0x2C},
371 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
372 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x23},
373 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x18},
374 },
375 {
376 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0xA9},
377 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x07},
378 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0xff, 0x00},
379 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1D},
380 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
381 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x27},
382 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
383 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2C},
384 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
385 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x35},
386 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
387 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0xff, 0x26},
388 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0xff, 0x16},
389 },
390};
391
392static const struct wcd9xxx_imped_val imped_index[] = {
393 {4000, 0},
394 {4500, 1},
395 {5000, 2},
396 {5500, 3},
397 {6000, 4},
398 {6500, 5},
399 {7000, 6},
400 {7700, 7},
401 {8470, 8},
402 {9317, 9},
403 {10248, 10},
404 {11273, 11},
405 {12400, 12},
406 {13641, 13},
407 {15005, 14},
408 {16505, 15},
409 {18156, 16},
410 {19971, 17},
411 {21969, 18},
412 {24165, 19},
413 {26582, 20},
414 {29240, 21},
415 {32164, 22},
416};
417
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800418static inline void wcd9xxx_enable_clsh_block(
419 struct snd_soc_codec *codec,
420 bool on)
421{
422 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
423 0x01, on ? 0x01 : 0x00);
424}
425
426static inline void wcd9xxx_enable_anc_delay(
427 struct snd_soc_codec *codec,
428 bool on)
429{
430 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
431 0x02, on ? 0x02 : 0x00);
432}
433
434static inline void wcd9xxx_enable_ncp(
435 struct snd_soc_codec *codec,
436 bool on)
437{
438 snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
439 0x01, on ? 0x01 : 0x00);
440}
441
442static inline void wcd9xxx_enable_buck(
443 struct snd_soc_codec *codec,
444 bool on)
445{
446 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
447 0x80, on ? 0x80 : 0x00);
448}
449
450static int cdc_lo_count;
451
452static void (*clsh_state_fp[NUM_CLSH_STATES])
453 (struct snd_soc_codec *,
454 struct wcd9xxx_clsh_cdc_data *,
455 u8 req_state, bool req_type);
456
457static const char *state_to_str(u8 state)
458{
459 if (state == WCD9XXX_CLSH_STATE_IDLE)
460 return "STATE_IDLE";
461 else if (state == WCD9XXX_CLSH_STATE_EAR)
462 return "STATE_EAR";
463 else if (state == WCD9XXX_CLSH_STATE_HPHL)
464 return "STATE_HPH_L";
465 else if (state == WCD9XXX_CLSH_STATE_HPHR)
466 return "STATE_HPH_R";
467 else if (state == (WCD9XXX_CLSH_STATE_HPHL
468 | WCD9XXX_CLSH_STATE_HPHR))
469 return "STATE_HPH_L_R";
470 else if (state == WCD9XXX_CLSH_STATE_LO)
471 return "STATE_LO";
472
473 return "UNKNOWN_STATE";
474}
475
476static void wcd9xxx_cfg_clsh_buck(
477 struct snd_soc_codec *codec)
478{
479 int i;
480 const struct wcd9xxx_reg_mask_val reg_set[] = {
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800481 {WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800482 };
483
484 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
485 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
486 reg_set[i].val);
487
488 dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
489}
490
491static void wcd9xxx_cfg_clsh_param_common(
492 struct snd_soc_codec *codec)
493{
494 int i;
495 const struct wcd9xxx_reg_mask_val reg_set[] = {
496 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
497 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
498 {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
499 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
500 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
501 {WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
502 {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
503 {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
504 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
505 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
506 };
507
508 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
509 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
510 reg_set[i].val);
511
512 dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
513 __func__);
514}
515
516static void wcd9xxx_chargepump_request(
517 struct snd_soc_codec *codec, bool on)
518{
519 static int cp_count;
520
521 if (on && (++cp_count == 1)) {
522 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
523 0x01, 0x01);
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800524 dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800525 __func__, cp_count);
526 }
527
528 else if (!on) {
529 if (--cp_count < 0) {
530 dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
531 __func__);
532 if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
533 & 0x01) {
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800534 dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800535 __func__);
536 }
537 cp_count = 0;
538 WARN_ON(1);
539 }
540
541 if (cp_count == 0) {
542 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
543 0x01, 0x00);
544 dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
545 __func__, cp_count);
546 }
547 }
548}
549
Santosh Mardi93a69192013-07-03 23:37:29 +0530550static int get_impedance_index(u32 imped)
551{
552 int i = 0;
553 if (imped < imped_index[i].imped_val) {
554 pr_debug("%s, detected impedance is less than 4 Ohm\n",
555 __func__);
556 goto ret;
557 }
558 for (i = 0; i < ARRAY_SIZE(imped_index); i++) {
559 if (imped >= imped_index[i].imped_val &&
560 imped < imped_index[i + 1].imped_val)
561 break;
562 }
563ret:
564 pr_debug("%s: selected impedance index = %d\n",
565 __func__, imped_index[i].index);
566 return imped_index[i].index;
567}
568
569void wcd9xxx_clsh_imped_config(struct snd_soc_codec *codec,
570 int imped)
571{
572 int i = 0;
573 int index = 0;
574 index = get_impedance_index(imped);
575 if (index > ARRAY_SIZE(imped_index)) {
576 pr_err("%s, invalid imped = %d\n", __func__, imped);
577 return;
578 }
579 for (i = 0; i < MAX_IMPED_PARAMS; i++)
580 snd_soc_write(codec, imped_table[index][i].reg,
581 imped_table[index][i].val);
582}
583
Joonwoo Parka08e0552013-03-05 18:28:23 -0800584static void wcd9xxx_clsh_comp_req(struct snd_soc_codec *codec,
585 struct wcd9xxx_clsh_cdc_data *clsh_d,
586 int compute_pa, bool on)
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800587{
Joonwoo Parka08e0552013-03-05 18:28:23 -0800588 u8 shift;
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800589
Joonwoo Parka08e0552013-03-05 18:28:23 -0800590 if (compute_pa == CLSH_COMPUTE_EAR) {
591 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10,
592 (on ? 0x10 : 0));
593 } else {
594 if (compute_pa == CLSH_COMPUTE_HPH_L) {
595 shift = 3;
596 } else if (compute_pa == CLSH_COMPUTE_HPH_R) {
597 shift = 2;
598 } else {
599 dev_dbg(codec->dev,
600 "%s: classh computation request is incorrect\n",
601 __func__);
602 return;
603 }
604
605 if (on)
606 wcd9xxx_resmgr_add_cond_update_bits(clsh_d->resmgr,
607 WCD9XXX_COND_HPH,
608 WCD9XXX_A_CDC_CLSH_B1_CTL,
609 shift, false);
610 else
611 wcd9xxx_resmgr_rm_cond_update_bits(clsh_d->resmgr,
612 WCD9XXX_COND_HPH,
613 WCD9XXX_A_CDC_CLSH_B1_CTL,
614 shift, false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800615 }
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800616}
617
Phani Kumar Uppalapati01a77e12013-08-08 15:31:35 -0700618
619int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
620 struct list_head *list,
621 uint16_t reg, uint8_t mask,
622 uint8_t value, int delay)
623{
624 int rc;
625 struct wcd9xxx_register_save_node *node;
626
627 node = kmalloc(sizeof(*node), GFP_KERNEL);
628 if (unlikely(!node)) {
629 pr_err("%s: Not enough memory\n", __func__);
630 return -ENOMEM;
631 }
632 node->reg = reg;
633 node->value = snd_soc_read(codec, reg);
634 list_add(&node->lh, list);
635 if (mask == 0xFF)
636 rc = snd_soc_write(codec, reg, value);
637 else
638 rc = snd_soc_update_bits(codec, reg, mask, value);
639 if (delay)
640 usleep_range(delay, delay + USLEEP_RANGE_MARGIN_US);
641 return rc;
642}
643EXPORT_SYMBOL(wcd9xxx_soc_update_bits_push);
644
645void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
646 struct list_head *lh)
647{
648 struct wcd9xxx_register_save_node *node, *nodetmp;
649
650 list_for_each_entry_safe(node, nodetmp, lh, lh) {
651 snd_soc_write(codec, node->reg, node->value);
652 list_del(&node->lh);
653 kfree(node);
654 }
655}
656EXPORT_SYMBOL(wcd9xxx_restore_registers);
657
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800658static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
659 u8 buck_vref)
660{
661 int i;
662 const struct wcd9xxx_reg_mask_val reg_set[] = {
663 {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
664 {WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
665 {WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
666 {WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
667 {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
668 {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
669 {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
670 };
671
672 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
673 snd_soc_update_bits(codec, reg_set[i].reg,
674 reg_set[i].mask, reg_set[i].val);
675
676 dev_dbg(codec->dev, "%s: Done\n", __func__);
677 usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
678}
679
Bhalchandra Gajare7c739522013-06-20 15:31:02 -0700680
681/* This will be called for all states except Lineout */
682static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec,
683 struct wcd9xxx_clsh_cdc_data *cdc_clsh_d)
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800684{
685 int i;
686 const struct wcd9xxx_reg_mask_val reg_set[] = {
687 {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
688 {WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
689 {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800690 };
691
692 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
693 snd_soc_update_bits(codec, reg_set[i].reg,
694 reg_set[i].mask, reg_set[i].val);
695
Bhalchandra Gajare7c739522013-06-20 15:31:02 -0700696 if (!cdc_clsh_d->is_dynamic_vdd_cp)
697 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_3,
698 0x08, 0x08);
699
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800700 dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
701 __func__);
702
703}
704
705static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
706 u8 fclk_level)
707{
708 int i;
709 const struct wcd9xxx_reg_mask_val reg_set[] = {
710 {WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
711 {WCD9XXX_A_NCP_EN, 0x01, 0x01},
712 };
713 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
714 0x010, 0x00);
715 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
716 0x0F, fclk_level);
717 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
718 snd_soc_update_bits(codec, reg_set[i].reg,
719 reg_set[i].mask, reg_set[i].val);
720
721 usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
722
723 dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
724}
725
726static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
727{
728 int i;
729 const struct wcd9xxx_reg_mask_val reg_set[] = {
730 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
731 {WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
732 {WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
733
734 /* Under assumption that EAR load is 10.7ohm */
735 {WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
736 {WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
737 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
738 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
739 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
740 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
741 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
742 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
743 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
744 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
745 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
746 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
747 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
748 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
749 };
750
751 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
752 snd_soc_update_bits(codec, reg_set[i].reg,
753 reg_set[i].mask, reg_set[i].val);
754
755 dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
756 __func__);
757}
758
759static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
760{
761 int i;
762 const struct wcd9xxx_reg_mask_val reg_set[] = {
763 {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
764 {WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
765 {WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
766
767 /* Under assumption that HPH load is 16ohm per channel */
768 {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
769 {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
770 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
771 {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
772 {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
773 {WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
774 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
775 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
776 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
777 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
778 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
779 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
780 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
781 {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
782 };
783
784 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
785 snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
786 reg_set[i].val);
787 dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
788 __func__);
789}
790
791static void wcd9xxx_clsh_turnoff_postpa
792 (struct snd_soc_codec *codec)
793{
794
795 int i;
796
797 const struct wcd9xxx_reg_mask_val reg_set[] = {
798 {WCD9XXX_A_NCP_EN, 0x01, 0x00},
799 {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
800 {WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
801 };
802
803 wcd9xxx_chargepump_request(codec, false);
804
805 for (i = 0; i < ARRAY_SIZE(reg_set); i++)
806 snd_soc_update_bits(codec, reg_set[i].reg,
807 reg_set[i].mask, reg_set[i].val);
808
809 wcd9xxx_enable_clsh_block(codec, false);
810
811 dev_dbg(codec->dev, "%s: Done\n", __func__);
812}
813
814static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
815 struct wcd9xxx_clsh_cdc_data *clsh_d,
816 u8 req_state, bool is_enable)
817{
818 if (is_enable) {
819 dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
820 __func__);
821 } else {
822 if (req_state == WCD9XXX_CLSH_STATE_EAR) {
823 wcd9xxx_clsh_turnoff_postpa(codec);
824 } else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800825 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
826 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800827 wcd9xxx_clsh_turnoff_postpa(codec);
828 } else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800829 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
830 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800831 wcd9xxx_clsh_turnoff_postpa(codec);
832 } else if (req_state == WCD9XXX_CLSH_STATE_LO) {
833 wcd9xxx_enable_ncp(codec, false);
834 wcd9xxx_enable_buck(codec, false);
835 }
836 }
837}
838
839static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
840 struct wcd9xxx_clsh_cdc_data *clsh_d,
841 u8 req_state, bool is_enable)
842{
843 if (is_enable) {
844 wcd9xxx_cfg_clsh_buck(codec);
845 wcd9xxx_cfg_clsh_param_common(codec);
846 wcd9xxx_cfg_clsh_param_ear(codec);
847 wcd9xxx_enable_clsh_block(codec, true);
848 wcd9xxx_chargepump_request(codec, true);
849 wcd9xxx_enable_anc_delay(codec, true);
Joonwoo Parka08e0552013-03-05 18:28:23 -0800850 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800851 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
852 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
853
854 dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
855 } else {
856 dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
857 }
858}
859
860static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
861 struct wcd9xxx_clsh_cdc_data *clsh_d,
862 u8 req_state, bool is_enable)
863{
864 if (is_enable) {
865 wcd9xxx_cfg_clsh_buck(codec);
866 wcd9xxx_cfg_clsh_param_common(codec);
867 wcd9xxx_cfg_clsh_param_hph(codec);
868 wcd9xxx_enable_clsh_block(codec, true);
869 wcd9xxx_chargepump_request(codec, true);
870 wcd9xxx_enable_anc_delay(codec, true);
Joonwoo Parka08e0552013-03-05 18:28:23 -0800871 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
Joonwoo Parkd535b8a2013-08-01 18:44:56 -0700872 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_0P494V);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800873 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
874
875 dev_dbg(codec->dev, "%s: Done\n", __func__);
876 } else {
877 if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800878 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
879 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800880 } else {
881 dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
882 __func__);
883 }
884 }
885}
886
887static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
888 struct wcd9xxx_clsh_cdc_data *clsh_d,
889 u8 req_state, bool is_enable)
890{
891 if (is_enable) {
892
893 wcd9xxx_cfg_clsh_buck(codec);
894 wcd9xxx_cfg_clsh_param_common(codec);
895 wcd9xxx_cfg_clsh_param_hph(codec);
896 wcd9xxx_enable_clsh_block(codec, true);
897 wcd9xxx_chargepump_request(codec, true);
898 wcd9xxx_enable_anc_delay(codec, true);
Joonwoo Parka08e0552013-03-05 18:28:23 -0800899 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
Joonwoo Parkd535b8a2013-08-01 18:44:56 -0700900 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_0P494V);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800901 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
902
903 dev_dbg(codec->dev, "%s: Done\n", __func__);
904 } else {
905 if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800906 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
907 false);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800908 } else {
909 dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
910 __func__);
911 }
912 }
913}
914
915static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
916 struct wcd9xxx_clsh_cdc_data *clsh_d,
917 u8 req_state, bool is_enable)
918{
919 if (is_enable) {
Joonwoo Parka08e0552013-03-05 18:28:23 -0800920 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
921 wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800922 } else {
923 dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
924 }
925}
926
927static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
928 struct wcd9xxx_clsh_cdc_data *clsh_d,
929 u8 req_state, bool is_enable)
930{
931 if (is_enable) {
932 if (++cdc_lo_count > 1)
933 return;
934
935 wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
936 wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
937
938 if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
939 wcd9xxx_enable_buck(codec, false);
940 snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
941 0x20, 0x01);
942 wcd9xxx_enable_ncp(codec, true);
Bhalchandra Gajare8b90bc22013-06-19 00:38:24 -0700943 /* NCP settle time recommended by codec specification */
944 usleep_range(NCP_SETTLE_TIME_US,
945 NCP_SETTLE_TIME_US + 10);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800946
947 } else {
948 snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
949 0x40, 0x00);
950 wcd9xxx_enable_ncp(codec, true);
Bhalchandra Gajare8b90bc22013-06-19 00:38:24 -0700951 /* NCP settle time recommended by codec specification */
952 usleep_range(NCP_SETTLE_TIME_US,
953 NCP_SETTLE_TIME_US + 10);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800954 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
955 0x01, 0x01);
956 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
957 0xFB, (0x02 << 2));
958 }
959 snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
960 0x04, 0x00);
961 } else {
962 dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
963 }
964}
965
966static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
967 struct wcd9xxx_clsh_cdc_data *clsh_d,
968 u8 req_state, bool is_enable)
969{
970 dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
971 , __func__, is_enable ? "enable" : "disable",
972 state_to_str(req_state));
973 WARN_ON(1);
974}
975
976void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
977 struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
978 u8 req_state, bool req_type, u8 clsh_event)
979{
980 u8 old_state, new_state;
981
982 switch (clsh_event) {
983
984 case WCD9XXX_CLSH_EVENT_PRE_DAC:
985
986 /* PRE_DAC event should be used only for Enable */
987 BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
988
989 old_state = cdc_clsh_d->state;
990 new_state = old_state | req_state;
991
992 (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
993 req_state, req_type);
994 cdc_clsh_d->state = new_state;
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -0800995 dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -0800996 __func__, state_to_str(old_state),
997 state_to_str(cdc_clsh_d->state));
998
999 break;
1000
1001 case WCD9XXX_CLSH_EVENT_POST_PA:
1002
1003 if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
1004 if (req_state == WCD9XXX_CLSH_STATE_LO
1005 && --cdc_lo_count > 0)
1006 break;
1007
1008 old_state = cdc_clsh_d->state;
1009 new_state = old_state & (~req_state);
1010
1011 if (new_state < NUM_CLSH_STATES) {
1012 (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
1013 req_state, req_type);
1014 cdc_clsh_d->state = new_state;
Bhalchandra Gajaredb8ffcb2013-02-27 13:58:17 -08001015 dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -08001016 __func__, state_to_str(old_state),
1017 state_to_str(cdc_clsh_d->state));
1018
1019 } else {
1020 dev_dbg(codec->dev, "%s: wrong new state = %x\n",
1021 __func__, new_state);
1022 }
1023
1024
1025 } else if (req_state != WCD9XXX_CLSH_STATE_LO) {
Bhalchandra Gajare7c739522013-06-20 15:31:02 -07001026 wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -08001027 }
1028
1029 break;
1030 }
1031
1032}
1033EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
1034
Joonwoo Parka08e0552013-03-05 18:28:23 -08001035void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
1036 struct wcd9xxx_resmgr *resmgr)
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -08001037{
1038 int i;
1039 clsh->state = WCD9XXX_CLSH_STATE_IDLE;
Joonwoo Parka08e0552013-03-05 18:28:23 -08001040 clsh->resmgr = resmgr;
Bhalchandra Gajare87fef4c2013-02-19 14:57:03 -08001041
1042 for (i = 0; i < NUM_CLSH_STATES; i++)
1043 clsh_state_fp[i] = wcd9xxx_clsh_state_err;
1044
1045 clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
1046 clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
1047 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
1048 wcd9xxx_clsh_state_hph_l;
1049 clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
1050 wcd9xxx_clsh_state_hph_r;
1051 clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
1052 wcd9xxx_clsh_state_hph_st;
1053 clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
1054
1055}
1056EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
1057
1058MODULE_DESCRIPTION("WCD9XXX Common");
1059MODULE_LICENSE("GPL v2");