blob: 3df95d537fe8c462c1f06276a554b7e8de8d2eb4 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/* Copyright (c) 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
14#include <linux/kernel.h>
15#include <linux/device.h>
16#include <linux/regmap.h>
17#include <linux/delay.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053018#include "core.h"
19#include "pdata.h"
20#include "wcd9xxx-utils.h"
21#include "wcd9335_registers.h"
22#include "wcd9335_irq.h"
23#include <asoc/wcd934x_registers.h>
24#include "wcd934x/wcd934x_irq.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053025
26/* wcd9335 interrupt table */
27static const struct intr_data wcd9335_intr_table[] = {
28 {WCD9XXX_IRQ_SLIMBUS, false},
29 {WCD9335_IRQ_MBHC_SW_DET, true},
30 {WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
31 {WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
32 {WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
33 {WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
34 {WCD9335_IRQ_FLL_LOCK_LOSS, false},
35 {WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
36 {WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
37 {WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
38 {WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
39 {WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
40 {WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
41 {WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
42 {WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
43 {WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
44 {WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
45 {WCD9335_IRQ_SOUNDWIRE, false},
46 {WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
47 {WCD9335_IRQ_RCO_ERROR, false},
48 {WCD9335_IRQ_SVA_ERROR, false},
49 {WCD9335_IRQ_MAD_AUDIO, false},
50 {WCD9335_IRQ_MAD_BEACON, false},
51 {WCD9335_IRQ_SVA_OUTBOX1, true},
52 {WCD9335_IRQ_SVA_OUTBOX2, true},
53 {WCD9335_IRQ_MAD_ULTRASOUND, false},
54 {WCD9335_IRQ_VBAT_ATTACK, false},
55 {WCD9335_IRQ_VBAT_RESTORE, false},
56};
57
58static const struct intr_data wcd934x_intr_table[] = {
59 {WCD9XXX_IRQ_SLIMBUS, false},
60 {WCD934X_IRQ_MBHC_SW_DET, true},
61 {WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true},
62 {WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true},
63 {WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true},
64 {WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
65 {WCD934X_IRQ_MISC, false},
66 {WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false},
67 {WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false},
68 {WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false},
69 {WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false},
70 {WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false},
71 {WCD934X_IRQ_SLNQ_ANALOG_ERROR, false},
72 {WCD934X_IRQ_RESERVED_3, false},
73 {WCD934X_IRQ_HPH_PA_OCPL_FAULT, false},
74 {WCD934X_IRQ_HPH_PA_OCPR_FAULT, false},
75 {WCD934X_IRQ_EAR_PA_OCP_FAULT, false},
76 {WCD934X_IRQ_SOUNDWIRE, false},
77 {WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false},
78 {WCD934X_IRQ_RCO_ERROR, false},
79 {WCD934X_IRQ_CPE_ERROR, false},
80 {WCD934X_IRQ_MAD_AUDIO, false},
81 {WCD934X_IRQ_MAD_BEACON, false},
82 {WCD934X_IRQ_CPE1_INTR, true},
83 {WCD934X_IRQ_RESERVED_4, false},
84 {WCD934X_IRQ_MAD_ULTRASOUND, false},
85 {WCD934X_IRQ_VBAT_ATTACK, false},
86 {WCD934X_IRQ_VBAT_RESTORE, false},
87};
88
89/*
90 * wcd9335_bring_down: Bringdown WCD Codec
91 *
92 * @wcd9xxx: Pointer to wcd9xxx structure
93 *
94 * Returns 0 for success or negative error code for failure
95 */
96static int wcd9335_bring_down(struct wcd9xxx *wcd9xxx)
97{
98 if (!wcd9xxx || !wcd9xxx->regmap)
99 return -EINVAL;
100
101 regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
102 0x04);
103
104 return 0;
105}
106
107/*
108 * wcd9335_bring_up: Bringup WCD Codec
109 *
110 * @wcd9xxx: Pointer to the wcd9xxx structure
111 *
112 * Returns 0 for success or negative error code for failure
113 */
114static int wcd9335_bring_up(struct wcd9xxx *wcd9xxx)
115{
116 int ret = 0;
117 int val, byte0;
118 struct regmap *wcd_regmap;
119
120 if (!wcd9xxx)
121 return -EINVAL;
122
123 if (!wcd9xxx->regmap) {
124 dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
125 __func__);
126 return -EINVAL;
127 }
128 wcd_regmap = wcd9xxx->regmap;
129
130 regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
131 regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
132
133 if ((val < 0) || (byte0 < 0)) {
134 dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
135 __func__);
136 return -EINVAL;
137 }
138 if ((val & 0x80) && (byte0 == 0x0)) {
139 dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
140 __func__);
141 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
142 regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
143 regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
144 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
145 0x5);
146 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
147 0x7);
148 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
149 0x3);
150 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
151 } else if (byte0 == 0x1) {
152 dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
153 __func__);
154 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
155 regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
156 regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
157 regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
158 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
159 0x5);
160 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
161 0x7);
162 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
163 0x3);
164 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
165 } else if ((byte0 == 0) && (!(val & 0x80))) {
166 dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
167 __func__);
168 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
169 regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
170 regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
171 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
172 0x3);
173 regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
174 } else {
175 dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
176 __func__);
177 ret = -EINVAL;
178 }
179
180 return ret;
181}
182
183/*
184 * wcd9335_get_cdc_info: Get codec specific information
185 *
186 * @wcd9xxx: pointer to wcd9xxx structure
187 * @wcd_type: pointer to wcd9xxx_codec_type structure
188 *
189 * Returns 0 for success or negative error code for failure
190 */
191static int wcd9335_get_cdc_info(struct wcd9xxx *wcd9xxx,
192 struct wcd9xxx_codec_type *wcd_type)
193{
194 u16 id_minor, id_major;
195 struct regmap *wcd_regmap;
196 int rc, val, version = 0;
197
198 if (!wcd9xxx || !wcd_type)
199 return -EINVAL;
200
201 if (!wcd9xxx->regmap) {
202 dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
203 __func__);
204 return -EINVAL;
205 }
206 wcd_regmap = wcd9xxx->regmap;
207
208 rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
209 (u8 *)&id_minor, sizeof(u16));
210 if (rc)
211 return -EINVAL;
212
213 rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
214 (u8 *)&id_major, sizeof(u16));
215 if (rc)
216 return -EINVAL;
217
218 dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
219 __func__, id_major, id_minor);
220
221 /* Version detection */
222 if (id_major == TASHA_MAJOR) {
223 regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,
224 &val);
225 version = ((u8)val & 0x80) >> 7;
226 } else if (id_major == TASHA2P0_MAJOR)
227 version = 2;
228 else
229 dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n",
230 __func__, id_major, id_minor);
231
232 /* Fill codec type info */
233 wcd_type->id_major = id_major;
234 wcd_type->id_minor = id_minor;
235 wcd_type->num_irqs = WCD9335_NUM_IRQS;
236 wcd_type->version = version;
237 wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
238 wcd_type->i2c_chip_status = 0x01;
239 wcd_type->intr_tbl = wcd9335_intr_table;
240 wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table);
241
242 wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
243 WCD9335_INTR_PIN1_STATUS0;
244 wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
245 WCD9335_INTR_PIN1_CLEAR0;
246 wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
247 WCD9335_INTR_PIN1_MASK0;
248 wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
249 WCD9335_INTR_LEVEL0;
250 wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
251 WCD9335_INTR_CLR_COMMIT;
252
253 return rc;
254}
255
256/*
257 * wcd934x_bring_down: Bringdown WCD Codec
258 *
259 * @wcd9xxx: Pointer to wcd9xxx structure
260 *
261 * Returns 0 for success or negative error code for failure
262 */
263static int wcd934x_bring_down(struct wcd9xxx *wcd9xxx)
264{
265 if (!wcd9xxx || !wcd9xxx->regmap)
266 return -EINVAL;
267
268 regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
269 0x04);
270
271 return 0;
272}
273
274/*
275 * wcd934x_bring_up: Bringup WCD Codec
276 *
277 * @wcd9xxx: Pointer to the wcd9xxx structure
278 *
279 * Returns 0 for success or negative error code for failure
280 */
281static int wcd934x_bring_up(struct wcd9xxx *wcd9xxx)
282{
283 struct regmap *wcd_regmap;
284
285 if (!wcd9xxx)
286 return -EINVAL;
287
288 if (!wcd9xxx->regmap) {
289 dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
290 __func__);
291 return -EINVAL;
292 }
293 wcd_regmap = wcd9xxx->regmap;
294
295 regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
296 regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
297 regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
298 /* Add 1msec delay for VOUT to settle */
299 usleep_range(1000, 1100);
300 regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
301 regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
302 regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
303 regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
304 regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
305
306 return 0;
307}
308
309/*
310 * wcd934x_get_cdc_info: Get codec specific information
311 *
312 * @wcd9xxx: pointer to wcd9xxx structure
313 * @wcd_type: pointer to wcd9xxx_codec_type structure
314 *
315 * Returns 0 for success or negative error code for failure
316 */
317static int wcd934x_get_cdc_info(struct wcd9xxx *wcd9xxx,
318 struct wcd9xxx_codec_type *wcd_type)
319{
320 u16 id_minor, id_major;
321 struct regmap *wcd_regmap;
322 int rc, version = -1;
323
324 if (!wcd9xxx || !wcd_type)
325 return -EINVAL;
326
327 if (!wcd9xxx->regmap) {
328 dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__);
329 return -EINVAL;
330 }
331 wcd_regmap = wcd9xxx->regmap;
332
333 rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
334 (u8 *)&id_minor, sizeof(u16));
335 if (rc)
336 return -EINVAL;
337
338 rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
339 (u8 *)&id_major, sizeof(u16));
340 if (rc)
341 return -EINVAL;
342
343 dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
344 __func__, id_major, id_minor);
345
346 if (id_major != TAVIL_MAJOR)
347 goto version_unknown;
348
349 /*
350 * As fine version info cannot be retrieved before tavil probe.
351 * Assign coarse versions for possible future use before tavil probe.
352 */
353 if (id_minor == cpu_to_le16(0))
354 version = TAVIL_VERSION_1_0;
355 else if (id_minor == cpu_to_le16(0x01))
356 version = TAVIL_VERSION_1_1;
357
358version_unknown:
359 if (version < 0)
360 dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n",
361 __func__);
362
363 /* Fill codec type info */
364 wcd_type->id_major = id_major;
365 wcd_type->id_minor = id_minor;
366 wcd_type->num_irqs = WCD934X_NUM_IRQS;
367 wcd_type->version = version;
368 wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
369 wcd_type->i2c_chip_status = 0x01;
370 wcd_type->intr_tbl = wcd934x_intr_table;
371 wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table);
372
373 wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
374 WCD934X_INTR_PIN1_STATUS0;
375 wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
376 WCD934X_INTR_PIN1_CLEAR0;
377 wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
378 WCD934X_INTR_PIN1_MASK0;
379 wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
380 WCD934X_INTR_LEVEL0;
381 wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
382 WCD934X_INTR_CLR_COMMIT;
383
384 return rc;
385}
386
387codec_bringdown_fn wcd9xxx_bringdown_fn(int type)
388{
389 codec_bringdown_fn cdc_bdown_fn;
390
391 switch (type) {
392 case WCD934X:
393 cdc_bdown_fn = wcd934x_bring_down;
394 break;
395 case WCD9335:
396 cdc_bdown_fn = wcd9335_bring_down;
397 break;
398 default:
399 cdc_bdown_fn = NULL;
400 break;
401 }
402
403 return cdc_bdown_fn;
404}
405
406codec_bringup_fn wcd9xxx_bringup_fn(int type)
407{
408 codec_bringup_fn cdc_bup_fn;
409
410 switch (type) {
411 case WCD934X:
412 cdc_bup_fn = wcd934x_bring_up;
413 break;
414 case WCD9335:
415 cdc_bup_fn = wcd9335_bring_up;
416 break;
417 default:
418 cdc_bup_fn = NULL;
419 break;
420 }
421
422 return cdc_bup_fn;
423}
424
425codec_type_fn wcd9xxx_get_codec_info_fn(int type)
426{
427 codec_type_fn cdc_type_fn;
428
429 switch (type) {
430 case WCD934X:
431 cdc_type_fn = wcd934x_get_cdc_info;
432 break;
433 case WCD9335:
434 cdc_type_fn = wcd9335_get_cdc_info;
435 break;
436 default:
437 cdc_type_fn = NULL;
438 break;
439 }
440
441 return cdc_type_fn;
442}
443