blob: 80b1efb1178de38ee3df62ba0d4c929df791810a [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. 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#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/slab.h>
15#include <linux/platform_device.h>
16#include <linux/printk.h>
17#include <linux/ratelimit.h>
18#include <linux/mfd/wcd9310/core.h>
19#include <linux/mfd/wcd9310/registers.h>
20#include <sound/jack.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <sound/tlv.h>
24#include <linux/bitops.h>
25#include <linux/delay.h>
26#include "wcd9310.h"
27
28static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
29static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
30static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
31
32enum tabla_bandgap_type {
33 TABLA_BANDGAP_OFF = 0,
34 TABLA_BANDGAP_AUDIO_MODE,
35 TABLA_BANDGAP_MBHC_MODE,
36};
37
38struct tabla_priv { /* member undecided */
39 struct snd_soc_codec *codec;
40 u32 ref_cnt;
41 u32 adc_count;
42 u32 dec_count;
43 enum tabla_bandgap_type bandgap_type;
44 bool clock_active;
45 bool config_mode_active;
46 bool mbhc_polling_active;
Bradley Rubincb1e2732011-06-23 16:49:20 -070047 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
49 struct tabla_mbhc_calibration *calibration;
50
Bradley Rubincb1e2732011-06-23 16:49:20 -070051 struct snd_soc_jack *headset_jack;
52 struct snd_soc_jack *button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053};
54
55static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
56 struct snd_kcontrol *kcontrol, int event)
57{
58 struct snd_soc_codec *codec = w->codec;
59 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
60
61 pr_debug("%s %d\n", __func__, event);
62 switch (event) {
63 case SND_SOC_DAPM_POST_PMU:
64 if ((tabla->bandgap_type != TABLA_BANDGAP_AUDIO_MODE) ||
65 (!tabla->clock_active)) {
66 pr_err("%s: Error, Tabla must have clocks enabled for "
67 "charge pump\n", __func__);
68 return -EINVAL;
69 }
70
71 snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x01);
72 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
73 0x01);
74 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
75 usleep_range(200, 200);
76 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
77 break;
78 case SND_SOC_DAPM_PRE_PMD:
79 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
80 0x10);
81 usleep_range(20, 20);
82 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
83 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
84 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
85 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
86 0x00);
87 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
88 snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x00);
89 break;
90 }
91 return 0;
92}
93
94static const struct snd_kcontrol_new tabla_snd_controls[] = {
95 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
96 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -070097 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
98 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
100 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700101 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
102 line_gain),
103
104 SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
105 SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
106 SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
107 SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
108 SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
109 SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
112 line_gain),
113 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
114 line_gain),
115
116 SOC_SINGLE_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL, 0,
117 100, 0, digital_gain),
118 SOC_SINGLE_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL, 0,
119 100, 0, digital_gain),
120
121 SOC_SINGLE_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, 100, 0,
122 digital_gain),
123 SOC_SINGLE_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, 100, 0,
124 digital_gain),
125
126 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
127 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
128
129 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
130};
131
132static const char *rx_mix1_text[] = {
133 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
134 "RX5", "RX6", "RX7"
135};
136
137static const char *sb_tx1_mux_text[] = {
138 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
139 "DEC1"
140};
141
142static const char *sb_tx5_mux_text[] = {
143 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
144 "DEC5"
145};
146
147static const char *sb_tx6_mux_text[] = {
148 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
149 "DEC6"
150};
151
152static const char const *sb_tx7_to_tx10_mux_text[] = {
153 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
154 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
155 "DEC9", "DEC10"
156};
157
158static const char *dec1_mux_text[] = {
159 "ZERO", "DMIC1", "ADC6",
160};
161
162static const char *dec5_mux_text[] = {
163 "ZERO", "DMIC5", "ADC2",
164};
165
166static const char *dec6_mux_text[] = {
167 "ZERO", "DMIC6", "ADC1",
168};
169
170static const char const *dec7_mux_text[] = {
171 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
172};
173
174static const char *iir1_inp1_text[] = {
175 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
176 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
177};
178
179static const struct soc_enum rx_mix1_inp1_chain_enum =
180 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
181
182static const struct soc_enum rx2_mix1_inp1_chain_enum =
183 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
184
185static const struct soc_enum rx3_mix1_inp1_chain_enum =
186 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
187
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700188static const struct soc_enum rx3_mix1_inp2_chain_enum =
189 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191static const struct soc_enum rx4_mix1_inp1_chain_enum =
192 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
193
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700194static const struct soc_enum rx4_mix1_inp2_chain_enum =
195 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197static const struct soc_enum rx5_mix1_inp1_chain_enum =
198 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
199
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700200static const struct soc_enum rx5_mix1_inp2_chain_enum =
201 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
202
203static const struct soc_enum rx6_mix1_inp1_chain_enum =
204 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
205
206static const struct soc_enum rx6_mix1_inp2_chain_enum =
207 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209static const struct soc_enum sb_tx5_mux_enum =
210 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
211
212static const struct soc_enum sb_tx6_mux_enum =
213 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
214
215static const struct soc_enum sb_tx7_mux_enum =
216 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
217 sb_tx7_to_tx10_mux_text);
218
219static const struct soc_enum sb_tx8_mux_enum =
220 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
221 sb_tx7_to_tx10_mux_text);
222
223static const struct soc_enum sb_tx1_mux_enum =
224 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
225
226static const struct soc_enum dec1_mux_enum =
227 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
228
229static const struct soc_enum dec5_mux_enum =
230 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
231
232static const struct soc_enum dec6_mux_enum =
233 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
234
235static const struct soc_enum dec7_mux_enum =
236 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
237
238static const struct soc_enum iir1_inp1_mux_enum =
239 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
240
241static const struct snd_kcontrol_new rx_mix1_inp1_mux =
242 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
243
244static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
245 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
246
247static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
248 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
249
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700250static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
251 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
254 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
255
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700256static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
257 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
260 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
261
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700262static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
263 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
264
265static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
266 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
267
268static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
269 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271static const struct snd_kcontrol_new sb_tx5_mux =
272 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
273
274static const struct snd_kcontrol_new sb_tx6_mux =
275 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
276
277static const struct snd_kcontrol_new sb_tx7_mux =
278 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
279
280static const struct snd_kcontrol_new sb_tx8_mux =
281 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
282
283static const struct snd_kcontrol_new sb_tx1_mux =
284 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
285
286static const struct snd_kcontrol_new dec1_mux =
287 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
288
289static const struct snd_kcontrol_new dec5_mux =
290 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
291
292static const struct snd_kcontrol_new dec6_mux =
293 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
294
295static const struct snd_kcontrol_new dec7_mux =
296 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
297
298static const struct snd_kcontrol_new iir1_inp1_mux =
299 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
300
301static const struct snd_kcontrol_new dac1_control =
302 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0);
303
304static const struct snd_kcontrol_new hphl_switch =
305 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0);
306
307static const struct snd_kcontrol_new hphr_switch =
308 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0);
309
310static const struct snd_kcontrol_new lineout1_switch =
311 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0);
312
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700313static const struct snd_kcontrol_new lineout2_switch =
314 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0);
315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316static const struct snd_kcontrol_new lineout3_switch =
317 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
318
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700319static const struct snd_kcontrol_new lineout4_switch =
320 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
321
322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
324 int enable)
325{
326 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
327
328 pr_debug("%s %d\n", __func__, enable);
329
330 if (enable) {
331 tabla->adc_count++;
332 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
333 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
334 } else {
335 tabla->adc_count--;
336 if (!tabla->adc_count) {
337 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
338 0x2, 0x0);
339 if (!tabla->mbhc_polling_active)
340 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
341 0xE0, 0x0);
342 }
343 }
344}
345
346static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
347 struct snd_kcontrol *kcontrol, int event)
348{
349 struct snd_soc_codec *codec = w->codec;
350 u16 adc_reg;
351
352 pr_debug("%s %d\n", __func__, event);
353
354 if (w->reg == TABLA_A_TX_1_2_EN)
355 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
356 else if (w->reg == TABLA_A_TX_3_4_EN)
357 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
358 else if (w->reg == TABLA_A_TX_5_6_EN)
359 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
360 else {
361 pr_err("%s: Error, invalid adc register\n", __func__);
362 return -EINVAL;
363 }
364
365 switch (event) {
366 case SND_SOC_DAPM_PRE_PMU:
367 tabla_codec_enable_adc_block(codec, 1);
368 break;
369 case SND_SOC_DAPM_POST_PMU:
370 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
371 1 << w->shift);
372 usleep_range(1000, 1000);
373 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
374 usleep_range(1000, 1000);
375 break;
376 case SND_SOC_DAPM_POST_PMD:
377 tabla_codec_enable_adc_block(codec, 0);
378 break;
379 }
380 return 0;
381}
382
383static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
384 struct snd_kcontrol *kcontrol, int event)
385{
386 struct snd_soc_codec *codec = w->codec;
387
388 pr_debug("%s %d\n", __func__, event);
389 switch (event) {
390 case SND_SOC_DAPM_PRE_PMU:
391 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
392 break;
393 case SND_SOC_DAPM_POST_PMD:
394 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
395 break;
396 }
397 return 0;
398}
399
400static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
401 struct snd_kcontrol *kcontrol, int event)
402{
403 struct snd_soc_codec *codec = w->codec;
404 u16 lineout_gain_reg;
405
406 pr_debug("%s %d\n", __func__, event);
407
408 switch (w->shift) {
409 case 0:
410 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
411 break;
412 case 1:
413 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
414 break;
415 case 2:
416 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
417 break;
418 case 3:
419 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
420 break;
421 case 4:
422 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
423 break;
424 default:
425 pr_err("%s: Error, incorrect lineout register value\n",
426 __func__);
427 return -EINVAL;
428 }
429
430 switch (event) {
431 case SND_SOC_DAPM_PRE_PMU:
432 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
433 break;
434 case SND_SOC_DAPM_POST_PMU:
435 usleep_range(40000, 40000);
436 break;
437 case SND_SOC_DAPM_POST_PMD:
438 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
439 break;
440 }
441 return 0;
442}
443
444static int tabla_codec_enable_dmic1(struct snd_soc_dapm_widget *w,
445 struct snd_kcontrol *kcontrol, int event)
446{
447 struct snd_soc_codec *codec = w->codec;
448
449 pr_debug("%s %d\n", __func__, event);
450 switch (event) {
451 case SND_SOC_DAPM_PRE_PMU:
452 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_MUX_CTL, 0x1, 0x1);
453 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x2, 0x2);
454 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1);
455 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x1, 0x1);
456 break;
457 case SND_SOC_DAPM_POST_PMD:
458 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0);
459 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x3, 0);
460 break;
461 }
462 return 0;
463}
464
465static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
466 struct snd_kcontrol *kcontrol, int event)
467{
468 struct snd_soc_codec *codec = w->codec;
469 u16 micb_cfilt_reg, micb_int_reg;
470 char *internal_text = "Internal";
471
472 pr_debug("%s %d\n", __func__, event);
473 switch (w->reg) {
474 case TABLA_A_MICB_1_CTL:
475 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
476 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
477 break;
478 case TABLA_A_MICB_2_CTL:
479 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
480 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
481 break;
482 case TABLA_A_MICB_3_CTL:
483 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
484 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
485 break;
486 default:
487 pr_err("%s: Error, invalid micbias register\n", __func__);
488 return -EINVAL;
489 }
490
491 switch (event) {
492 case SND_SOC_DAPM_PRE_PMU:
493 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
494 if (strnstr(w->name, internal_text, 20))
495 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
496 break;
497 case SND_SOC_DAPM_POST_PMD:
498 if (strnstr(w->name, internal_text, 20))
499 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
500 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
501 break;
502 }
503
504 return 0;
505}
506
507static void tabla_codec_enable_dec_clock(struct snd_soc_codec *codec,
508 int enable)
509{
510 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
511
512 if (enable) {
513 tabla->dec_count++;
514 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x4, 0x4);
515 } else {
516 tabla->dec_count--;
517 if (!tabla->dec_count)
518 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
519 0x4, 0x0);
520 }
521}
522
523static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
524 struct snd_kcontrol *kcontrol, int event)
525{
526 struct snd_soc_codec *codec = w->codec;
527 u16 dec_reset_reg;
528
529 pr_debug("%s %d\n", __func__, event);
530
531 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
532 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
533 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
534 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
535 else {
536 pr_err("%s: Error, incorrect dec\n", __func__);
537 return -EINVAL;
538 }
539
540 switch (event) {
541 case SND_SOC_DAPM_PRE_PMU:
542 tabla_codec_enable_dec_clock(codec, 1);
543 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
544 1 << w->shift);
545 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
546 break;
547 case SND_SOC_DAPM_POST_PMD:
548 tabla_codec_enable_dec_clock(codec, 0);
549 break;
550 }
551 return 0;
552}
553
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700554static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 struct snd_kcontrol *kcontrol, int event)
556{
557 struct snd_soc_codec *codec = w->codec;
558
559 switch (event) {
560 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700561 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
562 1 << w->shift, 1 << w->shift);
563 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
564 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565 break;
566 }
567 return 0;
568}
569
570static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
571 /*RX stuff */
572 SND_SOC_DAPM_OUTPUT("EAR"),
573
574 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
575 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
576 SND_SOC_DAPM_PRE_PMD),
577
578 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
579
580 SND_SOC_DAPM_SWITCH("DAC1", TABLA_A_RX_EAR_EN, 6, 0, &dac1_control),
581 SND_SOC_DAPM_PGA_E("RX1 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
582 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
583 SND_SOC_DAPM_PRE_PMD),
584 SND_SOC_DAPM_PGA("RX BIAS", TABLA_A_RX_COM_BIAS, 7, 0, NULL, 0),
585 SND_SOC_DAPM_MUX_E("RX1 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0,
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700586 &rx_mix1_inp1_mux, tabla_codec_reset_interpolator,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 SND_SOC_DAPM_PRE_PMU),
588 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0,
589 TABLA_A_CDC_RX1_B6_CTL, 5, 0),
590
591 /* RX 2 path */
592 SND_SOC_DAPM_PGA_E("RX2 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
593 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
594 SND_SOC_DAPM_PRE_PMD),
595 SND_SOC_DAPM_MUX_E("RX2 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0,
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700596 &rx2_mix1_inp1_mux, tabla_codec_reset_interpolator,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 SND_SOC_DAPM_PRE_PMU),
598 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0,
599 TABLA_A_CDC_RX2_B6_CTL, 5, 0),
600
601 /* Headphone */
602 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
603 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
604 SND_SOC_DAPM_SWITCH("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
605 &hphl_switch),
606
607 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
608 SND_SOC_DAPM_SWITCH("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
609 &hphr_switch),
610
611 /* Speaker */
612 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
615 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
616 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700617 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
618 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
619 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
621 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
622 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700623 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
624 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
625 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
626
627 SND_SOC_DAPM_SWITCH("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
628 &lineout1_switch),
629 SND_SOC_DAPM_SWITCH("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
630 &lineout2_switch),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
632 &lineout3_switch),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700633 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
634 &lineout4_switch),
635
636 SND_SOC_DAPM_PGA_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL, 0,
637 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
638 SND_SOC_DAPM_PGA_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL, 0,
639 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
640 SND_SOC_DAPM_PGA_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL, 0,
641 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
642 SND_SOC_DAPM_PGA_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL, 0,
643 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
644
645 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
646 &rx3_mix1_inp1_mux),
647 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
648 &rx3_mix1_inp2_mux),
649 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
650 &rx4_mix1_inp1_mux),
651 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
652 &rx4_mix1_inp2_mux),
653 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
654 &rx5_mix1_inp1_mux),
655 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
656 &rx5_mix1_inp2_mux),
657 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
658 &rx6_mix1_inp1_mux),
659 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
660 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661
662 /* TX */
663 SND_SOC_DAPM_INPUT("AMIC1"),
664 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
665 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
666 SND_SOC_DAPM_POST_PMD),
667 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal", TABLA_A_MICB_1_CTL, 7, 0,
668 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
669 SND_SOC_DAPM_POST_PMD),
670 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
671 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
672 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
673
674 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
675 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
676 SND_SOC_DAPM_POST_PMD),
677
678 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
679 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
680 SND_SOC_DAPM_POST_PMD),
681
682 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
683 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
684 SND_SOC_DAPM_POST_PMD),
685
686 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
687 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
688 SND_SOC_DAPM_POST_PMD),
689
690 SND_SOC_DAPM_INPUT("AMIC2"),
691 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
692 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
693 SND_SOC_DAPM_POST_PMD),
694 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal", TABLA_A_MICB_2_CTL, 7, 0,
695 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
696 SND_SOC_DAPM_POST_PMD),
697 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
698 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
699 SND_SOC_DAPM_POST_PMD),
700 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal", TABLA_A_MICB_3_CTL, 7, 0,
701 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
702 SND_SOC_DAPM_POST_PMD),
703 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
704 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
705 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
706
707 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
708 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
709 0, 0),
710
711 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
712 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
713 4, 0),
714
715 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
716 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
717 5, 0),
718
719 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
720 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
721 0, 0),
722
723 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
724 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
725 0, 0),
726
727 /* Digital Mic */
728 SND_SOC_DAPM_INPUT("DMIC1 IN"),
729 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic1),
730
731 /* Sidetone */
732 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
733 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
734};
735
736static const struct snd_soc_dapm_route audio_map[] = {
737 /* SLIMBUS Connections */
738 {"RX BIAS", NULL, "SLIM RX1"},
739 {"RX BIAS", NULL, "SLIM RX2"},
740
741 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
742 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
743
744 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
745 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
746
747 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
748 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
749
750 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
751 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
752 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
753 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
754 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
755
756 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
757 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
758 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
759
760 /* Earpiece (RX MIX1) */
761 {"EAR", NULL, "EAR PA"},
762 {"EAR PA", NULL, "EAR PA Input"},
763 {"EAR PA Input", NULL, "DAC1"},
764 {"DAC1", "Switch", "RX1 CP"},
765 {"RX1 CP", NULL, "RX1 MIX1 INP1"},
766 {"RX1 MIX1 INP1", "RX1", "RX BIAS"},
767
768 /* Headset (RX MIX1 and RX MIX2) */
769 {"HEADPHONE", NULL, "HPHL"},
770 {"HPHL", NULL, "HPHL DAC"},
771 {"HPHL DAC", "Switch", "RX1 MIX1 INP1"},
772
773 {"HEADPHONE", NULL, "HPHR"},
774 {"HPHR", NULL, "HPHR DAC"},
775 {"HPHR DAC", "Switch", "RX2 CP"},
776 {"RX2 CP", NULL, "RX2 MIX1 INP1"},
777 {"RX2 MIX1 INP1", "RX2", "RX BIAS"},
778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700780 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700782 {"LINEOUT", NULL, "LINEOUT4"},
783
784 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
785 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700787 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
788
789 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
790 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
791 {"LINEOUT3 DAC", "Switch", "RX5 MIX1"},
792 {"LINEOUT4 DAC", "Switch", "RX6 MIX1"},
793
794 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
795 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
796 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
797 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
798 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
799 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
800 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
801 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
802
803 {"RX3 MIX1 INP1", "RX1", "RX BIAS"},
804 {"RX3 MIX1 INP1", "RX2", "RX BIAS"},
805 {"RX3 MIX1 INP2", "RX1", "RX BIAS"},
806 {"RX3 MIX1 INP2", "RX2", "RX BIAS"},
807 {"RX4 MIX1 INP1", "RX1", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 {"RX4 MIX1 INP1", "RX2", "RX BIAS"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700809 {"RX4 MIX1 INP2", "RX1", "RX BIAS"},
810 {"RX4 MIX1 INP2", "RX2", "RX BIAS"},
811 {"RX5 MIX1 INP1", "RX1", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812 {"RX5 MIX1 INP1", "RX2", "RX BIAS"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700813 {"RX5 MIX1 INP2", "RX1", "RX BIAS"},
814 {"RX5 MIX1 INP2", "RX2", "RX BIAS"},
815 {"RX6 MIX1 INP1", "RX1", "RX BIAS"},
816 {"RX6 MIX1 INP1", "RX2", "RX BIAS"},
817 {"RX6 MIX1 INP2", "RX1", "RX BIAS"},
818 {"RX6 MIX1 INP2", "RX2", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819
820 /* Handset TX */
821 {"DEC5 MUX", "ADC2", "ADC2"},
822 {"DEC6 MUX", "ADC1", "ADC1"},
823 {"ADC1", NULL, "AMIC1"},
824 {"ADC2", NULL, "AMIC2"},
825
826 /* Digital Mic */
827 {"DEC1 MUX", "DMIC1", "DMIC1"},
828 {"DEC7 MUX", "DMIC1", "DMIC1"},
829 {"DMIC1", NULL, "DMIC1 IN"},
830
831 /* Sidetone (IIR1) */
832 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
833 {"IIR1", NULL, "IIR1 INP1 MUX"},
834 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
835
836};
837
838static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
839{
840 return tabla_reg_readable[reg];
841}
842
843static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
844{
845 /* Registers lower than 0x100 are top level registers which can be
846 * written by the Tabla core driver.
847 */
848
849 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
850 return 1;
851
852 return 0;
853}
854
855#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
856static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
857 unsigned int value)
858{
859 int ret;
860 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
861
862 BUG_ON(reg > TABLA_MAX_REGISTER);
863
864 if (!tabla_volatile(codec, reg)) {
865 pr_debug("writing to cache\n");
866 ret = snd_soc_cache_write(codec, reg, value);
867 if (ret != 0)
868 dev_err(codec->dev, "Cache write to %x failed: %d\n",
869 reg, ret);
870 }
871
872 return tabla_reg_write(codec->control_data, reg, value);
873}
874static unsigned int tabla_read(struct snd_soc_codec *codec,
875 unsigned int reg)
876{
877 unsigned int val;
878 int ret;
879
880 BUG_ON(reg > TABLA_MAX_REGISTER);
881
882 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
883 reg < codec->driver->reg_cache_size) {
884 pr_debug("reading from cache\n");
885 ret = snd_soc_cache_read(codec, reg, &val);
886 if (ret >= 0) {
887 pr_debug("register %d, value %d\n", reg, val);
888 return val;
889 } else
890 dev_err(codec->dev, "Cache read from %x failed: %d\n",
891 reg, ret);
892 }
893
894 val = tabla_reg_read(codec->control_data, reg);
895 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
896 return val;
897}
898
899static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
900{
901 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
902 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
903 0x80);
904 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
905 0x04);
906 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
907 0x01);
908 usleep_range(1000, 1000);
909 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
910 0x00);
911}
912
913static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
914 enum tabla_bandgap_type choice)
915{
916 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
917
918 /* TODO lock resources accessed by audio streams and threaded
919 * interrupt handlers
920 */
921
922 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
923 tabla->bandgap_type);
924
925 if (tabla->bandgap_type == choice)
926 return;
927
928 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
929 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
930 tabla_codec_enable_audio_mode_bandgap(codec);
931 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
932 (choice == TABLA_BANDGAP_MBHC_MODE)) {
933 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
934 0x2);
935 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
936 0x80);
937 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
938 0x4);
939 usleep_range(1000, 1000);
940 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
941 0x00);
942 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
943 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
944 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
945 usleep_range(100, 100);
946 tabla_codec_enable_audio_mode_bandgap(codec);
947 } else if (choice == TABLA_BANDGAP_OFF) {
948 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
949 } else {
950 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
951 }
952 tabla->bandgap_type = choice;
953}
954
955static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
956 int enable)
957{
958 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
959
960 if (enable) {
961 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
962 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
963 usleep_range(5, 5);
964 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
965 0x80);
966 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
967 0x80);
968 usleep_range(10, 10);
969 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
970 usleep_range(20, 20);
971 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
972 } else {
973 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
974 0);
975 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
976 }
977 tabla->config_mode_active = enable ? true : false;
978
979 return 0;
980}
981
982static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
983 int config_mode)
984{
985 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
986
987 pr_debug("%s\n", __func__);
988
989 if (config_mode) {
990 tabla_codec_enable_config_mode(codec, 1);
991 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
992 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
993 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
994 usleep_range(1000, 1000);
995 } else
996 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
997
998 if (!config_mode && tabla->mbhc_polling_active) {
999 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1000 tabla_codec_enable_config_mode(codec, 0);
1001
1002 }
1003
1004 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1005 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1006 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1007 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1008 usleep_range(50, 50);
1009 tabla->clock_active = true;
1010 return 0;
1011}
1012static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1013{
1014 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1015 pr_debug("%s\n", __func__);
1016 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1017 ndelay(160);
1018 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1019 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1020 tabla->clock_active = false;
1021}
1022
Bradley Rubincb1e2732011-06-23 16:49:20 -07001023static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1024{
1025 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
1026 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1027 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1028 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1029 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1030 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1031}
1032
1033static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1034{
1035 /* TODO store register values in calibration */
1036
1037 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1038 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1039
1040 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1041 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1042 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1043 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1044
1045 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1046 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1047 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1048 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1049 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1050 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1051}
1052
1053static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1054{
1055 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1056 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1057 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1058}
1059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060static int tabla_startup(struct snd_pcm_substream *substream,
1061 struct snd_soc_dai *dai)
1062{
1063 struct snd_soc_codec *codec = dai->codec;
1064 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1065 int ret = 0;
1066
1067 pr_debug("%s()\n", __func__);
1068
1069 if (!codec) {
1070 pr_err("Error, no codec found\n");
1071 return -EINVAL;
1072 }
1073 tabla->ref_cnt++;
1074
1075 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1076 /* Enable LDO */
1077 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
1078 0xA0);
1079 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
1080 usleep_range(1000, 1000);
1081 }
1082
1083 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001084 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1086 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001087 tabla_codec_calibrate_hs_polling(codec);
1088 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 }
1090
1091 return ret;
1092}
1093
1094static void tabla_shutdown(struct snd_pcm_substream *substream,
1095 struct snd_soc_dai *dai)
1096{
1097 struct snd_soc_codec *codec = dai->codec;
1098 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1099
1100 pr_debug("%s()\n", __func__);
1101
1102 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1103 /* Disable LDO */
1104 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x00);
1105 usleep_range(1000, 1000);
1106 }
1107
1108 if (!tabla->ref_cnt) {
1109 pr_err("Error, trying to shutdown codec when already down\n");
1110 return;
1111 }
1112 tabla->ref_cnt--;
1113
1114 if (tabla->mbhc_polling_active) {
1115 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001116 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 tabla_codec_enable_bandgap(codec,
1118 TABLA_BANDGAP_MBHC_MODE);
1119 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1120 0x80);
1121 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001122 tabla_codec_calibrate_hs_polling(codec);
1123 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 }
1125 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1126 }
1127}
1128
1129static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1130{
1131 struct snd_soc_codec *codec = codec_dai->codec;
1132
1133 pr_debug("%s %d\n", __func__, mute);
1134
1135 /* TODO mute TX */
1136 if (mute)
1137 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1138 else
1139 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1140
1141 return 0;
1142}
1143
1144static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1145 int clk_id, unsigned int freq, int dir)
1146{
1147 pr_debug("%s\n", __func__);
1148 return 0;
1149}
1150
1151static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1152{
1153 pr_debug("%s\n", __func__);
1154 return 0;
1155}
1156
1157static int tabla_hw_params(struct snd_pcm_substream *substream,
1158 struct snd_pcm_hw_params *params,
1159 struct snd_soc_dai *dai)
1160{
1161 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1162 return 0;
1163}
1164
1165static struct snd_soc_dai_ops tabla_dai_ops = {
1166 .startup = tabla_startup,
1167 .shutdown = tabla_shutdown,
1168 .hw_params = tabla_hw_params,
1169 .set_sysclk = tabla_set_dai_sysclk,
1170 .set_fmt = tabla_set_dai_fmt,
1171 .digital_mute = tabla_digital_mute,
1172};
1173
1174static struct snd_soc_dai_driver tabla_dai[] = {
1175 {
1176 .name = "tabla_rx1",
1177 .id = 1,
1178 .playback = {
1179 .stream_name = "AIF1 Playback",
1180 .rates = SNDRV_PCM_RATE_8000_48000,
1181 .formats = TABLA_FORMATS,
1182 .rate_max = 48000,
1183 .rate_min = 8000,
1184 .channels_min = 1,
1185 .channels_max = 2,
1186 },
1187 .ops = &tabla_dai_ops,
1188 },
1189 {
1190 .name = "tabla_tx1",
1191 .id = 2,
1192 .capture = {
1193 .stream_name = "AIF1 Capture",
1194 .rates = SNDRV_PCM_RATE_8000_48000,
1195 .formats = TABLA_FORMATS,
1196 .rate_max = 48000,
1197 .rate_min = 8000,
1198 .channels_min = 1,
1199 .channels_max = 2,
1200 },
1201 .ops = &tabla_dai_ops,
1202 },
1203};
1204
Bradley Rubincb1e2732011-06-23 16:49:20 -07001205static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1206 int dce)
1207{
1208 u8 bias_msb, bias_lsb;
1209 short bias_value;
1210
1211 if (dce) {
1212 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1213 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1214 } else {
1215 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1216 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1217 msleep(100);
1218 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1219 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1220 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1221 }
1222
1223 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1224 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
1225
1226 bias_value = (bias_msb << 8) | bias_lsb;
1227 pr_debug("read microphone bias value %x\n", bias_value);
1228 return bias_value;
1229}
1230
1231static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232{
1233 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1234 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001235 int micbias_ctl_reg, micbias_cfilt_val_reg, micbias_cfilt_ctl_reg,
1236 micbias_mbhc_reg;
1237 short bias_value, threshold_no_mic;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238
1239 if (!calibration) {
1240 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001241 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242 }
1243
1244 tabla->mbhc_polling_active = true;
1245
1246 if (!tabla->ref_cnt) {
1247 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1248 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1249 tabla_codec_enable_clock_block(codec, 1);
1250 }
1251
1252 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0F, 0x0D);
1255 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1256
1257 /* TODO select cfilt separately from the micbias line inside the machine
1258 * driver
1259 */
1260 switch (calibration->bias) {
1261 case TABLA_MICBIAS1:
1262 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1263 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1264 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_1_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001265 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 break;
1267 case TABLA_MICBIAS2:
1268 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1269 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1270 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_2_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001271 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 break;
1273 case TABLA_MICBIAS3:
1274 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1275 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1276 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_3_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001277 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 break;
1279 case TABLA_MICBIAS4:
1280 pr_err("%s: Error, microphone bias 4 not supported\n",
1281 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001282 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 default:
1284 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001285 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 }
1287 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1288
Bradley Rubincb1e2732011-06-23 16:49:20 -07001289 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
1290 snd_soc_update_bits(codec, micbias_ctl_reg, 0x60,
1291 calibration->bias << 5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292
1293 snd_soc_write(codec, micbias_cfilt_val_reg, 0x68);
1294
1295 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001296 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297
1298 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1299 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1300 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1301
1302 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001303 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1304 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305
Bradley Rubincb1e2732011-06-23 16:49:20 -07001306 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1308
Bradley Rubincb1e2732011-06-23 16:49:20 -07001309 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1310 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1311
1312 tabla_codec_calibrate_hs_polling(codec);
1313
1314 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
1315
1316 threshold_no_mic = 0xF7F6;
1317
1318 if (bias_value < threshold_no_mic) {
1319 pr_debug("headphone detected, micbias %x\n", bias_value);
1320 return 0;
1321 } else {
1322 pr_debug("headset detected, micbias %x\n", bias_value);
1323 return 1;
1324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325}
1326
1327static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1328 int insertion)
1329{
1330 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1331 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1332 int central_bias_enabled = 0;
1333 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1334
1335 if (!calibration) {
1336 pr_err("Error, no tabla calibration\n");
1337 return -EINVAL;
1338 }
1339
1340 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1341
1342 if (insertion)
1343 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1344 else
1345 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1346
1347 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1348 if (!(tabla->clock_active)) {
1349 tabla_codec_enable_config_mode(codec, 1);
1350 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001351 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 usleep_range(calibration->shutdown_plug_removal,
1353 calibration->shutdown_plug_removal);
1354 tabla_codec_enable_config_mode(codec, 0);
1355 } else
1356 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001357 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 }
1359
1360 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1361 calibration->hph_current << 2);
1362
1363 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1364
1365 switch (calibration->bias) {
1366 case TABLA_MICBIAS1:
1367 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1368 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1369 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1370 break;
1371 case TABLA_MICBIAS2:
1372 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1373 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1374 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1375 break;
1376 case TABLA_MICBIAS3:
1377 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1378 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1379 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1380 break;
1381 case TABLA_MICBIAS4:
1382 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1383 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1384 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1385 break;
1386 default:
1387 pr_err("Error, invalid mic bias line\n");
1388 return -EINVAL;
1389 }
1390 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1391 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1392
1393 /* If central bandgap disabled */
1394 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1395 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1396 usleep_range(calibration->bg_fast_settle,
1397 calibration->bg_fast_settle);
1398 central_bias_enabled = 1;
1399 }
1400
1401 /* If LDO_H disabled */
1402 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1403 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1404 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1405 usleep_range(calibration->tldoh, calibration->tldoh);
1406 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1407
1408 if (central_bias_enabled)
1409 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1410 }
1411 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1412 calibration->mic_current << 5);
1413 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1414 usleep_range(calibration->mic_pid, calibration->mic_pid);
1415 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1416
1417 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1418
1419 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1420 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1421 return 0;
1422}
1423
Bradley Rubincb1e2732011-06-23 16:49:20 -07001424int tabla_hs_detect(struct snd_soc_codec *codec,
1425 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 struct tabla_mbhc_calibration *calibration)
1427{
1428 struct tabla_priv *tabla;
1429 if (!codec || !calibration) {
1430 pr_err("Error: no codec or calibration\n");
1431 return -EINVAL;
1432 }
1433 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001434 tabla->headset_jack = headset_jack;
1435 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 tabla->calibration = calibration;
1437
1438 return tabla_codec_enable_hs_detect(codec, 1);
1439}
1440EXPORT_SYMBOL_GPL(tabla_hs_detect);
1441
Bradley Rubincb1e2732011-06-23 16:49:20 -07001442static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443{
1444 struct tabla_priv *priv = data;
1445 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001446
1447 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1448 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1449
1450 pr_debug("%s: Button pressed\n", __func__);
1451 if (priv->button_jack)
1452 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1453 SND_JACK_BTN_0);
1454
1455 priv->buttons_pressed |= SND_JACK_BTN_0;
1456 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1457 0x09);
1458 usleep_range(100000, 100000);
1459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 return IRQ_HANDLED;
1461}
1462
Bradley Rubincb1e2732011-06-23 16:49:20 -07001463static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464{
1465 struct tabla_priv *priv = data;
1466 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001467 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1468 pr_debug("%s: Button released\n", __func__);
1469 if (priv->button_jack)
1470 snd_soc_jack_report(priv->button_jack, 0,
1471 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472
Bradley Rubincb1e2732011-06-23 16:49:20 -07001473 priv->buttons_pressed &= ~SND_JACK_BTN_0;
1474 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1475 0x08);
1476 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478
1479 return IRQ_HANDLED;
1480}
1481
Bradley Rubincb1e2732011-06-23 16:49:20 -07001482static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1483{
1484 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1485 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1486 int micbias_mbhc_reg;
1487
1488 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1489 tabla_codec_enable_config_mode(codec, 1);
1490
1491 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1492 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
1493 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x0);
1494
1495 switch (calibration->bias) {
1496 case TABLA_MICBIAS1:
1497 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1498 break;
1499 case TABLA_MICBIAS2:
1500 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1501 break;
1502 case TABLA_MICBIAS3:
1503 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1504 break;
1505 case TABLA_MICBIAS4:
1506 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1507 break;
1508 default:
1509 pr_err("Error, invalid mic bias line\n");
1510 return;
1511 }
1512 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
1513 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1514 usleep_range(calibration->shutdown_plug_removal,
1515 calibration->shutdown_plug_removal);
1516
1517 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1518 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1519 tabla_codec_enable_config_mode(codec, 0);
1520
1521 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
1522}
1523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
1525{
1526 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001527
1528 tabla_codec_shutdown_hs_removal_detect(codec);
1529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 if (!tabla->ref_cnt) {
1531 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
1532 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1533 tabla_codec_enable_clock_block(codec, 0);
1534 }
1535
1536 tabla->mbhc_polling_active = false;
1537}
1538
Bradley Rubincb1e2732011-06-23 16:49:20 -07001539static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
1540{
1541 struct tabla_priv *priv = data;
1542 struct snd_soc_codec *codec = priv->codec;
1543 int microphone_present;
1544
1545 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1546
1547 usleep_range(priv->calibration->setup_plug_removal_delay,
1548 priv->calibration->setup_plug_removal_delay);
1549
1550 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
1551 if (priv->headset_jack) {
1552 pr_debug("%s: Reporting removal\n", __func__);
1553 snd_soc_jack_report(priv->headset_jack, 0,
1554 SND_JACK_HEADSET);
1555 }
1556 tabla_codec_shutdown_hs_removal_detect(codec);
1557 tabla_codec_enable_hs_detect(codec, 1);
1558 return IRQ_HANDLED;
1559 }
1560
1561 microphone_present = tabla_codec_setup_hs_polling(codec);
1562
1563 if (microphone_present == 0) {
1564 if (priv->headset_jack) {
1565 pr_debug("%s: Reporting insertion %d\n", __func__,
1566 SND_JACK_HEADPHONE);
1567 snd_soc_jack_report(priv->headset_jack,
1568 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
1569 }
1570 tabla_codec_shutdown_hs_polling(codec);
1571 tabla_codec_enable_hs_detect(codec, 0);
1572 } else if (microphone_present == 1) {
1573 if (priv->headset_jack) {
1574 pr_debug("%s: Reporting insertion %d\n", __func__,
1575 SND_JACK_HEADSET);
1576 snd_soc_jack_report(priv->headset_jack,
1577 SND_JACK_HEADSET, SND_JACK_HEADSET);
1578 }
1579 tabla_codec_start_hs_polling(codec);
1580 }
1581
1582 return IRQ_HANDLED;
1583}
1584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
1586{
1587 struct tabla_priv *priv = data;
1588 struct snd_soc_codec *codec = priv->codec;
1589
1590 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1591 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1592
1593 usleep_range(priv->calibration->shutdown_plug_removal,
1594 priv->calibration->shutdown_plug_removal);
1595
Bradley Rubincb1e2732011-06-23 16:49:20 -07001596 if (priv->headset_jack) {
1597 pr_debug("%s: Reporting removal\n", __func__);
1598 snd_soc_jack_report(priv->headset_jack, 0, SND_JACK_HEADSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 }
1600 tabla_codec_shutdown_hs_polling(codec);
1601
1602 tabla_codec_enable_hs_detect(codec, 1);
1603
1604 return IRQ_HANDLED;
1605}
1606
1607static unsigned long slimbus_value;
1608
1609static irqreturn_t tabla_slimbus_irq(int irq, void *data)
1610{
1611 struct tabla_priv *priv = data;
1612 struct snd_soc_codec *codec = priv->codec;
1613 int i, j;
1614 u8 val;
1615
1616 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
1617 slimbus_value = tabla_interface_reg_read(codec->control_data,
1618 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
1619 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
1620 val = tabla_interface_reg_read(codec->control_data,
1621 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
1622 if (val & 0x1)
1623 pr_err_ratelimited("overflow error on port %x,"
1624 " value %x\n", i*8 + j, val);
1625 if (val & 0x2)
1626 pr_err_ratelimited("underflow error on port %x,"
1627 " value %x\n", i*8 + j, val);
1628 }
1629 tabla_interface_reg_write(codec->control_data,
1630 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
1631 }
1632
1633 return IRQ_HANDLED;
1634}
1635
1636static int tabla_codec_probe(struct snd_soc_codec *codec)
1637{
1638 struct tabla *control;
1639 struct tabla_priv *tabla;
1640 struct snd_soc_dapm_context *dapm = &codec->dapm;
1641 int ret = 0;
1642 int i;
1643 int tx_channel;
1644
1645 codec->control_data = dev_get_drvdata(codec->dev->parent);
1646 control = codec->control_data;
1647
1648 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
1649 if (!tabla) {
1650 dev_err(codec->dev, "Failed to allocate private data\n");
1651 return -ENOMEM;
1652 }
1653
1654 snd_soc_codec_set_drvdata(codec, tabla);
1655
1656 tabla->ref_cnt = 0;
1657 tabla->bandgap_type = TABLA_BANDGAP_OFF;
1658 tabla->clock_active = false;
1659 tabla->config_mode_active = false;
1660 tabla->mbhc_polling_active = false;
1661 tabla->codec = codec;
1662
1663 /* TODO only enable bandgap when necessary in order to save power */
1664 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1665 tabla_codec_enable_clock_block(codec, 0);
1666
1667 /* Initialize gain registers to use register gain */
1668 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
1669 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
1670 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
1671 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
1672
1673 /* Initialize mic biases to differential mode */
1674 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
1675 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
1676 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
1677 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
1678
1679 /* Set headset CFILT to fast mode */
1680 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_CTL, 0x00, 0x00);
1681 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_CTL, 0x00, 0x00);
1682 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_CTL, 0x00, 0x00);
1683
1684 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
1685
1686 /* Use 16 bit sample size for now */
1687 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
1688 snd_soc_update_bits(codec,
1689 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
1690 snd_soc_update_bits(codec,
1691 TABLA_A_CDC_TX1_MUX_CTL + tx_channel, 0x8, 0x0);
1692
1693 }
1694 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
1695 snd_soc_update_bits(codec,
1696 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
1697 snd_soc_update_bits(codec,
1698 TABLA_A_CDC_TX1_MUX_CTL + tx_channel, 0x8, 0x0);
1699 }
1700 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
1701 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
1702
1703 snd_soc_add_controls(codec, tabla_snd_controls,
1704 ARRAY_SIZE(tabla_snd_controls));
1705 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
1706 ARRAY_SIZE(tabla_dapm_widgets));
1707 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
1708 snd_soc_dapm_sync(dapm);
1709
1710 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
1711 tabla_hs_insert_irq, "Headset insert detect", tabla);
1712 if (ret) {
1713 pr_err("%s: Failed to request irq %d\n", __func__,
1714 TABLA_IRQ_MBHC_INSERTION);
1715 goto err_insert_irq;
1716 }
1717 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1718
1719 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
1720 tabla_hs_remove_irq, "Headset remove detect", tabla);
1721 if (ret) {
1722 pr_err("%s: Failed to request irq %d\n", __func__,
1723 TABLA_IRQ_MBHC_REMOVAL);
1724 goto err_remove_irq;
1725 }
1726 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1727
1728 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001729 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 if (ret) {
1731 pr_err("%s: Failed to request irq %d\n", __func__,
1732 TABLA_IRQ_MBHC_POTENTIAL);
1733 goto err_potential_irq;
1734 }
1735 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1736
Bradley Rubincb1e2732011-06-23 16:49:20 -07001737 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
1738 tabla_release_handler, "Button Release detect", tabla);
1739 if (ret) {
1740 pr_err("%s: Failed to request irq %d\n", __func__,
1741 TABLA_IRQ_MBHC_RELEASE);
1742 goto err_release_irq;
1743 }
1744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
1746 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
1747 if (ret) {
1748 pr_err("%s: Failed to request irq %d\n", __func__,
1749 TABLA_IRQ_SLIMBUS);
1750 goto err_slimbus_irq;
1751 }
1752
1753 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
1754 tabla_interface_reg_write(codec->control_data,
1755 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
1756
1757 return ret;
1758
1759err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07001760 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
1761err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
1763err_potential_irq:
1764 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
1765err_remove_irq:
1766 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
1767err_insert_irq:
1768 kfree(tabla);
1769 return ret;
1770}
1771static int tabla_codec_remove(struct snd_soc_codec *codec)
1772{
1773 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1774 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001775 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
1777 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
1778 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
1779 tabla_codec_disable_clock_block(codec);
1780 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
1781 kfree(tabla);
1782 return 0;
1783}
1784static struct snd_soc_codec_driver soc_codec_dev_tabla = {
1785 .probe = tabla_codec_probe,
1786 .remove = tabla_codec_remove,
1787 .read = tabla_read,
1788 .write = tabla_write,
1789
1790 .readable_register = tabla_readable,
1791 .volatile_register = tabla_volatile,
1792
1793 .reg_cache_size = TABLA_CACHE_SIZE,
1794 .reg_cache_default = tabla_reg_defaults,
1795 .reg_word_size = 1,
1796};
1797static int __devinit tabla_probe(struct platform_device *pdev)
1798{
1799 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
1800 tabla_dai, ARRAY_SIZE(tabla_dai));
1801}
1802static int __devexit tabla_remove(struct platform_device *pdev)
1803{
1804 snd_soc_unregister_codec(&pdev->dev);
1805 return 0;
1806}
1807static struct platform_driver tabla_codec_driver = {
1808 .probe = tabla_probe,
1809 .remove = tabla_remove,
1810 .driver = {
1811 .name = "tabla_codec",
1812 .owner = THIS_MODULE,
1813 },
1814};
1815
1816static int __init tabla_codec_init(void)
1817{
1818 return platform_driver_register(&tabla_codec_driver);
1819}
1820
1821static void __exit tabla_codec_exit(void)
1822{
1823 platform_driver_unregister(&tabla_codec_driver);
1824}
1825
1826module_init(tabla_codec_init);
1827module_exit(tabla_codec_exit);
1828
1829MODULE_DESCRIPTION("Tabla codec driver");
1830MODULE_VERSION("1.0");
1831MODULE_LICENSE("GPL v2");