blob: a5dcb19826e2ead3ee9c928e6980523e85282e54 [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>
Bradley Rubin229c6a52011-07-12 16:18:48 -070014#include <linux/firmware.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/printk.h>
18#include <linux/ratelimit.h>
19#include <linux/mfd/wcd9310/core.h>
20#include <linux/mfd/wcd9310/registers.h>
21#include <sound/jack.h>
22#include <sound/soc.h>
23#include <sound/soc-dapm.h>
24#include <sound/tlv.h>
25#include <linux/bitops.h>
26#include <linux/delay.h>
27#include "wcd9310.h"
28
29static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
30static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
31static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
32
33enum tabla_bandgap_type {
34 TABLA_BANDGAP_OFF = 0,
35 TABLA_BANDGAP_AUDIO_MODE,
36 TABLA_BANDGAP_MBHC_MODE,
37};
38
Bradley Rubin229c6a52011-07-12 16:18:48 -070039struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 struct snd_soc_codec *codec;
41 u32 ref_cnt;
42 u32 adc_count;
43 u32 dec_count;
Bradley Rubin229c6a52011-07-12 16:18:48 -070044 u32 rx_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045 enum tabla_bandgap_type bandgap_type;
46 bool clock_active;
47 bool config_mode_active;
48 bool mbhc_polling_active;
Bradley Rubincb1e2732011-06-23 16:49:20 -070049 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050
51 struct tabla_mbhc_calibration *calibration;
52
Bradley Rubincb1e2732011-06-23 16:49:20 -070053 struct snd_soc_jack *headset_jack;
54 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -070055
56 u32 anc_writes_size;
57 u32 *anc_writes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058};
59
60static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
61 struct snd_kcontrol *kcontrol, int event)
62{
63 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
65 pr_debug("%s %d\n", __func__, event);
66 switch (event) {
67 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
69 0x01);
70 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
71 usleep_range(200, 200);
72 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
73 break;
74 case SND_SOC_DAPM_PRE_PMD:
75 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
76 0x10);
77 usleep_range(20, 20);
78 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
79 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
80 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
81 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
82 0x00);
83 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084 break;
85 }
86 return 0;
87}
88
89static const struct snd_kcontrol_new tabla_snd_controls[] = {
90 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
91 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -070092 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
93 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
95 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -070096 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
97 line_gain),
98
99 SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
100 SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
101 SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
102 SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
103 SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
104 SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
107 line_gain),
108 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
109 line_gain),
110
111 SOC_SINGLE_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL, 0,
112 100, 0, digital_gain),
113 SOC_SINGLE_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL, 0,
114 100, 0, digital_gain),
115
116 SOC_SINGLE_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, 100, 0,
117 digital_gain),
118 SOC_SINGLE_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, 100, 0,
119 digital_gain),
120
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700121 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
122 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700123 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
124 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700125 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
126 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127
128 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700129 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
130 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131};
132
133static const char *rx_mix1_text[] = {
134 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
135 "RX5", "RX6", "RX7"
136};
137
138static const char *sb_tx1_mux_text[] = {
139 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
140 "DEC1"
141};
142
143static const char *sb_tx5_mux_text[] = {
144 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
145 "DEC5"
146};
147
148static const char *sb_tx6_mux_text[] = {
149 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
150 "DEC6"
151};
152
153static const char const *sb_tx7_to_tx10_mux_text[] = {
154 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
155 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
156 "DEC9", "DEC10"
157};
158
159static const char *dec1_mux_text[] = {
160 "ZERO", "DMIC1", "ADC6",
161};
162
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700163static const char *dec2_mux_text[] = {
164 "ZERO", "DMIC2", "ADC5",
165};
166
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700167static const char *dec3_mux_text[] = {
168 "ZERO", "DMIC3", "ADC4",
169};
170
171static const char *dec4_mux_text[] = {
172 "ZERO", "DMIC4", "ADC3",
173};
174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175static const char *dec5_mux_text[] = {
176 "ZERO", "DMIC5", "ADC2",
177};
178
179static const char *dec6_mux_text[] = {
180 "ZERO", "DMIC6", "ADC1",
181};
182
183static const char const *dec7_mux_text[] = {
184 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
185};
186
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700187static const char *dec8_mux_text[] = {
188 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
189};
190
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700191static const char *dec9_mux_text[] = {
192 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
193};
194
195static const char *dec10_mux_text[] = {
196 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
197};
198
Bradley Rubin229c6a52011-07-12 16:18:48 -0700199static const char const *anc_mux_text[] = {
200 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
201 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
202};
203
204static const char const *anc1_fb_mux_text[] = {
205 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
206};
207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208static const char *iir1_inp1_text[] = {
209 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
210 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
211};
212
213static const struct soc_enum rx_mix1_inp1_chain_enum =
214 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
215
Bradley Rubin229c6a52011-07-12 16:18:48 -0700216static const struct soc_enum rx_mix1_inp2_chain_enum =
217 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219static const struct soc_enum rx2_mix1_inp1_chain_enum =
220 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
221
Bradley Rubin229c6a52011-07-12 16:18:48 -0700222static const struct soc_enum rx2_mix1_inp2_chain_enum =
223 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225static const struct soc_enum rx3_mix1_inp1_chain_enum =
226 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
227
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700228static const struct soc_enum rx3_mix1_inp2_chain_enum =
229 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231static const struct soc_enum rx4_mix1_inp1_chain_enum =
232 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
233
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700234static const struct soc_enum rx4_mix1_inp2_chain_enum =
235 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237static const struct soc_enum rx5_mix1_inp1_chain_enum =
238 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
239
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700240static const struct soc_enum rx5_mix1_inp2_chain_enum =
241 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
242
243static const struct soc_enum rx6_mix1_inp1_chain_enum =
244 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
245
246static const struct soc_enum rx6_mix1_inp2_chain_enum =
247 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249static const struct soc_enum sb_tx5_mux_enum =
250 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
251
252static const struct soc_enum sb_tx6_mux_enum =
253 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
254
255static const struct soc_enum sb_tx7_mux_enum =
256 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
257 sb_tx7_to_tx10_mux_text);
258
259static const struct soc_enum sb_tx8_mux_enum =
260 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
261 sb_tx7_to_tx10_mux_text);
262
263static const struct soc_enum sb_tx1_mux_enum =
264 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
265
266static const struct soc_enum dec1_mux_enum =
267 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
268
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700269static const struct soc_enum dec2_mux_enum =
270 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
271
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700272static const struct soc_enum dec3_mux_enum =
273 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
274
275static const struct soc_enum dec4_mux_enum =
276 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278static const struct soc_enum dec5_mux_enum =
279 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
280
281static const struct soc_enum dec6_mux_enum =
282 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
283
284static const struct soc_enum dec7_mux_enum =
285 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
286
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700287static const struct soc_enum dec8_mux_enum =
288 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
289
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700290static const struct soc_enum dec9_mux_enum =
291 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
292
293static const struct soc_enum dec10_mux_enum =
294 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
295
Bradley Rubin229c6a52011-07-12 16:18:48 -0700296static const struct soc_enum anc1_mux_enum =
297 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
298
299static const struct soc_enum anc2_mux_enum =
300 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
301
302static const struct soc_enum anc1_fb_mux_enum =
303 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305static const struct soc_enum iir1_inp1_mux_enum =
306 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
307
308static const struct snd_kcontrol_new rx_mix1_inp1_mux =
309 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
310
Bradley Rubin229c6a52011-07-12 16:18:48 -0700311static const struct snd_kcontrol_new rx_mix1_inp2_mux =
312 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
315 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
316
Bradley Rubin229c6a52011-07-12 16:18:48 -0700317static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
318 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
321 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
322
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700323static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
324 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
327 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
328
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700329static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
330 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
333 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
334
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700335static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
336 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
337
338static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
339 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
340
341static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
342 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344static const struct snd_kcontrol_new sb_tx5_mux =
345 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
346
347static const struct snd_kcontrol_new sb_tx6_mux =
348 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
349
350static const struct snd_kcontrol_new sb_tx7_mux =
351 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
352
353static const struct snd_kcontrol_new sb_tx8_mux =
354 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
355
356static const struct snd_kcontrol_new sb_tx1_mux =
357 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
358
359static const struct snd_kcontrol_new dec1_mux =
360 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
361
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700362static const struct snd_kcontrol_new dec2_mux =
363 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
364
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700365static const struct snd_kcontrol_new dec3_mux =
366 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
367
368static const struct snd_kcontrol_new dec4_mux =
369 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371static const struct snd_kcontrol_new dec5_mux =
372 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
373
374static const struct snd_kcontrol_new dec6_mux =
375 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
376
377static const struct snd_kcontrol_new dec7_mux =
378 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
379
Bradley Rubin229c6a52011-07-12 16:18:48 -0700380static const struct snd_kcontrol_new anc1_mux =
381 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700382static const struct snd_kcontrol_new dec8_mux =
383 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
384
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700385static const struct snd_kcontrol_new dec9_mux =
386 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
387
388static const struct snd_kcontrol_new dec10_mux =
389 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391static const struct snd_kcontrol_new iir1_inp1_mux =
392 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
393
Bradley Rubin229c6a52011-07-12 16:18:48 -0700394static const struct snd_kcontrol_new anc2_mux =
395 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396
Bradley Rubin229c6a52011-07-12 16:18:48 -0700397static const struct snd_kcontrol_new anc1_fb_mux =
398 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
Bradley Rubin229c6a52011-07-12 16:18:48 -0700400static const struct snd_kcontrol_new dac1_switch[] = {
401 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
402};
403static const struct snd_kcontrol_new hphl_switch[] = {
404 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
405};
406static const struct snd_kcontrol_new hphr_switch[] = {
407 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
408};
409static const struct snd_kcontrol_new lineout1_switch[] = {
410 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
411};
412static const struct snd_kcontrol_new lineout2_switch[] = {
413 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
414};
415static const struct snd_kcontrol_new lineout3_switch[] = {
416 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
417};
418static const struct snd_kcontrol_new lineout4_switch[] = {
419 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
420};
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
423 int enable)
424{
425 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
426
427 pr_debug("%s %d\n", __func__, enable);
428
429 if (enable) {
430 tabla->adc_count++;
431 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
432 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
433 } else {
434 tabla->adc_count--;
435 if (!tabla->adc_count) {
436 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
437 0x2, 0x0);
438 if (!tabla->mbhc_polling_active)
439 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
440 0xE0, 0x0);
441 }
442 }
443}
444
445static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
446 struct snd_kcontrol *kcontrol, int event)
447{
448 struct snd_soc_codec *codec = w->codec;
449 u16 adc_reg;
450
451 pr_debug("%s %d\n", __func__, event);
452
453 if (w->reg == TABLA_A_TX_1_2_EN)
454 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
455 else if (w->reg == TABLA_A_TX_3_4_EN)
456 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
457 else if (w->reg == TABLA_A_TX_5_6_EN)
458 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
459 else {
460 pr_err("%s: Error, invalid adc register\n", __func__);
461 return -EINVAL;
462 }
463
464 switch (event) {
465 case SND_SOC_DAPM_PRE_PMU:
466 tabla_codec_enable_adc_block(codec, 1);
467 break;
468 case SND_SOC_DAPM_POST_PMU:
469 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
470 1 << w->shift);
471 usleep_range(1000, 1000);
472 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
473 usleep_range(1000, 1000);
474 break;
475 case SND_SOC_DAPM_POST_PMD:
476 tabla_codec_enable_adc_block(codec, 0);
477 break;
478 }
479 return 0;
480}
481
482static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
483 struct snd_kcontrol *kcontrol, int event)
484{
485 struct snd_soc_codec *codec = w->codec;
486
487 pr_debug("%s %d\n", __func__, event);
488 switch (event) {
489 case SND_SOC_DAPM_PRE_PMU:
490 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
491 break;
492 case SND_SOC_DAPM_POST_PMD:
493 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
494 break;
495 }
496 return 0;
497}
498
499static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
500 struct snd_kcontrol *kcontrol, int event)
501{
502 struct snd_soc_codec *codec = w->codec;
503 u16 lineout_gain_reg;
504
505 pr_debug("%s %d\n", __func__, event);
506
507 switch (w->shift) {
508 case 0:
509 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
510 break;
511 case 1:
512 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
513 break;
514 case 2:
515 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
516 break;
517 case 3:
518 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
519 break;
520 case 4:
521 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
522 break;
523 default:
524 pr_err("%s: Error, incorrect lineout register value\n",
525 __func__);
526 return -EINVAL;
527 }
528
529 switch (event) {
530 case SND_SOC_DAPM_PRE_PMU:
531 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
532 break;
533 case SND_SOC_DAPM_POST_PMU:
534 usleep_range(40000, 40000);
535 break;
536 case SND_SOC_DAPM_POST_PMD:
537 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
538 break;
539 }
540 return 0;
541}
542
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700543
544static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 struct snd_kcontrol *kcontrol, int event)
546{
547 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700548 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
549 u8 dmic_clk_sel, dmic_clk_en;
550
551 if (!strncmp(w->name, "DMIC1", 5)) {
552
553 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL;
554 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL;
555 dmic_clk_sel = 0x2;
556 dmic_clk_en = 0x1;
557
558 } else if (!strncmp(w->name, "DMIC2", 5)) {
559
560 tx_mux_ctl_reg = TABLA_A_CDC_TX2_MUX_CTL;
561 tx_dmic_ctl_reg = TABLA_A_CDC_TX2_DMIC_CTL;
562 dmic_clk_sel = 0x2;
563 dmic_clk_en = 0x1;
564
565 } else if (!strncmp(w->name, "DMIC3", 5)) {
566
567 tx_mux_ctl_reg = TABLA_A_CDC_TX3_MUX_CTL;
568 tx_dmic_ctl_reg = TABLA_A_CDC_TX3_DMIC_CTL;
569 dmic_clk_sel = 0x8;
570 dmic_clk_en = 0x4;
571
572 } else {
573 pr_err("%s: Error, DMIC = %s\n", __func__, w->name);
574 return -EINVAL;
575 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576
577 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579 switch (event) {
580 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700581 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
582
583 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
584 dmic_clk_sel, dmic_clk_sel);
585
586 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
587
588 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
589 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 break;
591 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700592 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
593 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 break;
595 }
596 return 0;
597}
598
Bradley Rubin229c6a52011-07-12 16:18:48 -0700599static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
600 struct snd_kcontrol *kcontrol, int event)
601{
602 struct snd_soc_codec *codec = w->codec;
603 const char *filename;
604 const struct firmware *fw;
605 int i;
606 int ret;
607 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
608 u16 reg;
609 u8 mask, val, old_val;
610
611 pr_debug("%s %d\n", __func__, event);
612 switch (event) {
613 case SND_SOC_DAPM_PRE_PMU:
614
615 filename = "wcd9310_anc.bin";
616
617 ret = request_firmware(&fw, filename, codec->dev);
618 if (ret != 0) {
619 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
620 ret);
621 return -ENODEV;
622 }
623
624 if (fw->size < TABLA_PACKED_REG_SIZE) {
625 dev_err(codec->dev, "Not enough data\n");
626 release_firmware(fw);
627 return -ENOMEM;
628 }
629
630 /* First number is the number of register writes */
631 tabla->anc_writes_size = (u32)(*fw->data);
632
633 if (tabla->anc_writes_size >
634 ((fw->size/TABLA_PACKED_REG_SIZE) - 1)) {
635 dev_err(codec->dev, "Invalid register format\n");
636 release_firmware(fw);
637 return -ENOMEM;
638 }
639
640 tabla->anc_writes = (u32 *)(fw->data + TABLA_PACKED_REG_SIZE);
641
642 for (i = 0; i < tabla->anc_writes_size; i++) {
643 TABLA_CODEC_UNPACK_ENTRY(tabla->anc_writes[i], reg,
644 mask, val);
645 old_val = snd_soc_read(codec, reg);
646 snd_soc_write(codec, reg, (old_val & ~mask) | val);
647 }
648 release_firmware(fw);
649 tabla->anc_writes = NULL;
650
651 break;
652 case SND_SOC_DAPM_POST_PMD:
653 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
654 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
655 break;
656 }
657 return 0;
658}
659
660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
662 struct snd_kcontrol *kcontrol, int event)
663{
664 struct snd_soc_codec *codec = w->codec;
665 u16 micb_cfilt_reg, micb_int_reg;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700666 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700667 char *internal1_text = "Internal1";
668 char *internal2_text = "Internal2";
669 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670
671 pr_debug("%s %d\n", __func__, event);
672 switch (w->reg) {
673 case TABLA_A_MICB_1_CTL:
674 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
675 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700676 cfilt_sel_val = 0x00;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 break;
678 case TABLA_A_MICB_2_CTL:
679 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
680 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700681 cfilt_sel_val = 0x20;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 break;
683 case TABLA_A_MICB_3_CTL:
684 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
685 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700686 cfilt_sel_val = 0x40;
687 break;
688 case TABLA_A_MICB_4_CTL:
689 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
690 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
691 cfilt_sel_val = 0x40;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 break;
693 default:
694 pr_err("%s: Error, invalid micbias register\n", __func__);
695 return -EINVAL;
696 }
697
698 switch (event) {
699 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700700 snd_soc_update_bits(codec, w->reg, 0x60, cfilt_sel_val);
701 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700703
704 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700706 else if (strnstr(w->name, internal2_text, 30))
707 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
708 else if (strnstr(w->name, internal3_text, 30))
709 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 break;
712 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700713 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700715 else if (strnstr(w->name, internal2_text, 30))
716 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
717 else if (strnstr(w->name, internal3_text, 30))
718 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
721 break;
722 }
723
724 return 0;
725}
726
727static void tabla_codec_enable_dec_clock(struct snd_soc_codec *codec,
728 int enable)
729{
730 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
731
732 if (enable) {
733 tabla->dec_count++;
734 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x4, 0x4);
735 } else {
736 tabla->dec_count--;
737 if (!tabla->dec_count)
738 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
739 0x4, 0x0);
740 }
741}
742
743static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
744 struct snd_kcontrol *kcontrol, int event)
745{
746 struct snd_soc_codec *codec = w->codec;
747 u16 dec_reset_reg;
748
749 pr_debug("%s %d\n", __func__, event);
750
751 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
752 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
753 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
754 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
755 else {
756 pr_err("%s: Error, incorrect dec\n", __func__);
757 return -EINVAL;
758 }
759
760 switch (event) {
761 case SND_SOC_DAPM_PRE_PMU:
762 tabla_codec_enable_dec_clock(codec, 1);
763 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
764 1 << w->shift);
765 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
766 break;
767 case SND_SOC_DAPM_POST_PMD:
768 tabla_codec_enable_dec_clock(codec, 0);
769 break;
770 }
771 return 0;
772}
773
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700774static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700775 struct snd_kcontrol *kcontrol, int event)
776{
777 struct snd_soc_codec *codec = w->codec;
778
779 switch (event) {
780 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700781 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
782 1 << w->shift, 1 << w->shift);
783 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
784 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 break;
786 }
787 return 0;
788}
789
Bradley Rubin229c6a52011-07-12 16:18:48 -0700790static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
791 struct snd_kcontrol *kcontrol, int event)
792{
793 switch (event) {
794 case SND_SOC_DAPM_POST_PMU:
795 case SND_SOC_DAPM_POST_PMD:
796 usleep_range(1000, 1000);
797 break;
798 }
799 return 0;
800}
801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
803 /*RX stuff */
804 SND_SOC_DAPM_OUTPUT("EAR"),
805
806 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
807 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
808 SND_SOC_DAPM_PRE_PMD),
809
810 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
811
Bradley Rubin229c6a52011-07-12 16:18:48 -0700812 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
813 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814
Bradley Rubin229c6a52011-07-12 16:18:48 -0700815 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
816 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700817
818 /* Headphone */
819 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
820 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700821 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
822 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823
824 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700825 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
826 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827
828 /* Speaker */
829 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
832 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
833 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700834 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
835 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
836 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
838 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
839 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700840 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
841 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
842 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
843
Bradley Rubin229c6a52011-07-12 16:18:48 -0700844 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
845 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
846 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
847 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
848 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
849 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
850 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
851 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700852
Bradley Rubin229c6a52011-07-12 16:18:48 -0700853 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
854 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
855 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
856 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
857 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
858 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
859 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
860 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
861 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
862 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
863 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
864 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700865
Bradley Rubin229c6a52011-07-12 16:18:48 -0700866 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
867 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
868
869 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
870 &rx_mix1_inp1_mux),
871 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
872 &rx_mix1_inp2_mux),
873 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
874 &rx2_mix1_inp1_mux),
875 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
876 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700877 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
878 &rx3_mix1_inp1_mux),
879 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
880 &rx3_mix1_inp2_mux),
881 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
882 &rx4_mix1_inp1_mux),
883 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
884 &rx4_mix1_inp2_mux),
885 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
886 &rx5_mix1_inp1_mux),
887 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
888 &rx5_mix1_inp2_mux),
889 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
890 &rx6_mix1_inp1_mux),
891 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
892 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893
Bradley Rubin229c6a52011-07-12 16:18:48 -0700894 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
895 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
896 SND_SOC_DAPM_PRE_PMD),
897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700899
900 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
901 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 SND_SOC_DAPM_INPUT("AMIC1"),
904 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
905 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
906 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700907 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
908 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
909 SND_SOC_DAPM_POST_PMD),
910 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
912 SND_SOC_DAPM_POST_PMD),
913 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
914 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
915 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
916
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700917 SND_SOC_DAPM_INPUT("AMIC3"),
918 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
919 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
920 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
921
922 SND_SOC_DAPM_INPUT("AMIC4"),
923 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
924 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
925 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
926
927 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
928 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
929 SND_SOC_DAPM_POST_PMD),
930
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700931 SND_SOC_DAPM_INPUT("AMIC5"),
932 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
933 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
934
935 SND_SOC_DAPM_INPUT("AMIC6"),
936 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
937 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
940 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
941 SND_SOC_DAPM_POST_PMD),
942
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700943 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
944 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
945 SND_SOC_DAPM_POST_PMD),
946
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700947 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
948 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
949 SND_SOC_DAPM_POST_PMD),
950
951 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
952 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
953 SND_SOC_DAPM_POST_PMD),
954
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
956 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
957 SND_SOC_DAPM_POST_PMD),
958
959 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
960 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
961 SND_SOC_DAPM_POST_PMD),
962
963 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
964 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
965 SND_SOC_DAPM_POST_PMD),
966
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700967 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
968 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
969 SND_SOC_DAPM_POST_PMD),
970
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700971 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
972 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
973 SND_SOC_DAPM_POST_PMD),
974
975 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
976 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
977 SND_SOC_DAPM_POST_PMD),
978
Bradley Rubin229c6a52011-07-12 16:18:48 -0700979 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
980 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
981
982 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
983 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
984 SND_SOC_DAPM_POST_PMD),
985
986 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 SND_SOC_DAPM_INPUT("AMIC2"),
989 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
990 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
991 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700992 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
993 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
994 SND_SOC_DAPM_POST_PMD),
995 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
996 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
997 SND_SOC_DAPM_POST_PMD),
998 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1000 SND_SOC_DAPM_POST_PMD),
1001 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
1002 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1003 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001004 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
1005 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1006 SND_SOC_DAPM_POST_PMD),
1007 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001008 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1009 SND_SOC_DAPM_POST_PMD),
1010 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1011 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1012 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1013
1014 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1015 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1016 0, 0),
1017
1018 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1019 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1020 4, 0),
1021
1022 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1023 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1024 5, 0),
1025
1026 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1027 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1028 0, 0),
1029
1030 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1031 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1032 0, 0),
1033
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001034 /* Digital Mic Inputs */
1035 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic),
1036 SND_SOC_DAPM_MIC("DMIC2", &tabla_codec_enable_dmic),
1037 SND_SOC_DAPM_MIC("DMIC3", &tabla_codec_enable_dmic),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038
1039 /* Sidetone */
1040 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1041 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1042};
1043
1044static const struct snd_soc_dapm_route audio_map[] = {
1045 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046
1047 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1048 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1049
1050 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1051 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1052
1053 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1054 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1055
1056 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1057 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001058 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001059 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1060 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1062 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001063 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1064 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001065 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1066 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067
1068 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001069 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1070 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1071 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1073 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1074
1075 /* Earpiece (RX MIX1) */
1076 {"EAR", NULL, "EAR PA"},
1077 {"EAR PA", NULL, "EAR PA Input"},
1078 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001079 {"DAC1", NULL, "CP"},
1080
1081 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1082 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1083 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084
1085 /* Headset (RX MIX1 and RX MIX2) */
1086 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001088
1089 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001091
1092 {"HPHL DAC", NULL, "CP"},
1093 {"HPHR DAC", NULL, "CP"},
1094
1095 {"ANC", NULL, "ANC1 MUX"},
1096 {"ANC", NULL, "ANC2 MUX"},
1097 {"ANC1 MUX", "ADC1", "ADC1"},
1098 {"ANC1 MUX", "ADC2", "ADC2"},
1099 {"ANC1 MUX", "ADC3", "ADC3"},
1100 {"ANC1 MUX", "ADC4", "ADC4"},
1101 {"ANC2 MUX", "ADC1", "ADC1"},
1102 {"ANC2 MUX", "ADC2", "ADC2"},
1103 {"ANC2 MUX", "ADC3", "ADC3"},
1104 {"ANC2 MUX", "ADC4", "ADC4"},
1105
1106 {"DAC1", "Switch", "RX1 CHAIN"},
1107 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1108 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001111 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001113 {"LINEOUT", NULL, "LINEOUT4"},
1114
1115 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1116 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001118 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
1119
Bradley Rubin229c6a52011-07-12 16:18:48 -07001120 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1121 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1122 {"RX1 CHAIN", NULL, "ANC"},
1123 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001124 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1125 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
1126 {"LINEOUT3 DAC", "Switch", "RX5 MIX1"},
1127 {"LINEOUT4 DAC", "Switch", "RX6 MIX1"},
1128
Bradley Rubin229c6a52011-07-12 16:18:48 -07001129 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1130 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1131 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1132 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001133 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1134 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1135 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1136 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1137 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1138 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1139 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1140 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
1141
Bradley Rubin229c6a52011-07-12 16:18:48 -07001142 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1143 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1144 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1145 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1146 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1147 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1148 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1149 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1150 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1151 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1152 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1153 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1154 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1155 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1156 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1157 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1158 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1159 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1160 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1161 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1162 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1163 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1164 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1165 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1166 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1167 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001169 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001170 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001171 {"DEC1 MUX", "ADC6", "ADC6"},
1172 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001173 {"DEC2 MUX", "ADC5", "ADC5"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001174 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001175 {"DEC3 MUX", "ADC4", "ADC4"},
1176 {"DEC4 MUX", "ADC3", "ADC3"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 {"DEC5 MUX", "ADC2", "ADC2"},
1178 {"DEC6 MUX", "ADC1", "ADC1"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001179 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001180 {"DEC7 MUX", "ADC6", "ADC6"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001181 {"DEC8 MUX", "ADC5", "ADC5"},
1182 {"DEC9 MUX", "ADC3", "ADC3"},
1183 {"DEC10 MUX", "ADC4", "ADC4"},
1184
1185 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 {"ADC1", NULL, "AMIC1"},
1187 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001188 {"ADC3", NULL, "AMIC3"},
1189 {"ADC4", NULL, "AMIC4"},
1190 {"ADC5", NULL, "AMIC5"},
1191 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 {"IIR1", NULL, "IIR1 INP1 MUX"},
1194 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001195
1196 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1197 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1198 {"MIC BIAS1 External", NULL, "LDO_H"},
1199 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1200 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1201 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1202 {"MIC BIAS2 External", NULL, "LDO_H"},
1203 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1204 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1205 {"MIC BIAS3 External", NULL, "LDO_H"},
1206 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207};
1208
1209static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1210{
1211 return tabla_reg_readable[reg];
1212}
1213
1214static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1215{
1216 /* Registers lower than 0x100 are top level registers which can be
1217 * written by the Tabla core driver.
1218 */
1219
1220 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1221 return 1;
1222
1223 return 0;
1224}
1225
1226#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1227static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1228 unsigned int value)
1229{
1230 int ret;
1231 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1232
1233 BUG_ON(reg > TABLA_MAX_REGISTER);
1234
1235 if (!tabla_volatile(codec, reg)) {
1236 pr_debug("writing to cache\n");
1237 ret = snd_soc_cache_write(codec, reg, value);
1238 if (ret != 0)
1239 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1240 reg, ret);
1241 }
1242
1243 return tabla_reg_write(codec->control_data, reg, value);
1244}
1245static unsigned int tabla_read(struct snd_soc_codec *codec,
1246 unsigned int reg)
1247{
1248 unsigned int val;
1249 int ret;
1250
1251 BUG_ON(reg > TABLA_MAX_REGISTER);
1252
1253 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1254 reg < codec->driver->reg_cache_size) {
1255 pr_debug("reading from cache\n");
1256 ret = snd_soc_cache_read(codec, reg, &val);
1257 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001258 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 return val;
1260 } else
1261 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1262 reg, ret);
1263 }
1264
1265 val = tabla_reg_read(codec->control_data, reg);
1266 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1267 return val;
1268}
1269
1270static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1271{
1272 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1273 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1274 0x80);
1275 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1276 0x04);
1277 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1278 0x01);
1279 usleep_range(1000, 1000);
1280 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1281 0x00);
1282}
1283
1284static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1285 enum tabla_bandgap_type choice)
1286{
1287 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1288
1289 /* TODO lock resources accessed by audio streams and threaded
1290 * interrupt handlers
1291 */
1292
1293 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1294 tabla->bandgap_type);
1295
1296 if (tabla->bandgap_type == choice)
1297 return;
1298
1299 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1300 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1301 tabla_codec_enable_audio_mode_bandgap(codec);
1302 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1303 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1304 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1305 0x2);
1306 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1307 0x80);
1308 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1309 0x4);
1310 usleep_range(1000, 1000);
1311 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1312 0x00);
1313 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1314 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1315 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1316 usleep_range(100, 100);
1317 tabla_codec_enable_audio_mode_bandgap(codec);
1318 } else if (choice == TABLA_BANDGAP_OFF) {
1319 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1320 } else {
1321 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1322 }
1323 tabla->bandgap_type = choice;
1324}
1325
1326static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1327 int enable)
1328{
1329 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1330
1331 if (enable) {
1332 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1333 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1334 usleep_range(5, 5);
1335 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1336 0x80);
1337 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1338 0x80);
1339 usleep_range(10, 10);
1340 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1341 usleep_range(20, 20);
1342 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1343 } else {
1344 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1345 0);
1346 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1347 }
1348 tabla->config_mode_active = enable ? true : false;
1349
1350 return 0;
1351}
1352
1353static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1354 int config_mode)
1355{
1356 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1357
1358 pr_debug("%s\n", __func__);
1359
1360 if (config_mode) {
1361 tabla_codec_enable_config_mode(codec, 1);
1362 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1363 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1364 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1365 usleep_range(1000, 1000);
1366 } else
1367 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1368
1369 if (!config_mode && tabla->mbhc_polling_active) {
1370 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1371 tabla_codec_enable_config_mode(codec, 0);
1372
1373 }
1374
1375 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1376 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1377 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1378 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1379 usleep_range(50, 50);
1380 tabla->clock_active = true;
1381 return 0;
1382}
1383static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1384{
1385 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1386 pr_debug("%s\n", __func__);
1387 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1388 ndelay(160);
1389 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1390 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1391 tabla->clock_active = false;
1392}
1393
Bradley Rubincb1e2732011-06-23 16:49:20 -07001394static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1395{
1396 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
1397 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1398 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1399 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1400 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1401 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1402}
1403
1404static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1405{
1406 /* TODO store register values in calibration */
1407
1408 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1409 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1410
1411 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1412 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1413 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1414 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1415
1416 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1417 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1418 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1419 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1420 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1421 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1422}
1423
1424static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1425{
1426 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1427 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1428 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1429}
1430
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431static int tabla_startup(struct snd_pcm_substream *substream,
1432 struct snd_soc_dai *dai)
1433{
1434 struct snd_soc_codec *codec = dai->codec;
1435 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1436 int ret = 0;
1437
1438 pr_debug("%s()\n", __func__);
1439
1440 if (!codec) {
1441 pr_err("Error, no codec found\n");
1442 return -EINVAL;
1443 }
1444 tabla->ref_cnt++;
1445
1446 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
1448 0xA0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001449 } else {
1450 tabla->rx_count++;
1451 if (tabla->rx_count == 1)
1452 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1453 0x80);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 }
1455
1456 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001457 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1459 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001460 tabla_codec_calibrate_hs_polling(codec);
1461 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 }
1463
1464 return ret;
1465}
1466
1467static void tabla_shutdown(struct snd_pcm_substream *substream,
1468 struct snd_soc_dai *dai)
1469{
1470 struct snd_soc_codec *codec = dai->codec;
1471 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1472
1473 pr_debug("%s()\n", __func__);
1474
1475 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1476 /* Disable LDO */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001477 } else {
1478 tabla->rx_count--;
1479 if (!tabla->rx_count)
1480 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1481 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482 }
1483
1484 if (!tabla->ref_cnt) {
1485 pr_err("Error, trying to shutdown codec when already down\n");
1486 return;
1487 }
1488 tabla->ref_cnt--;
1489
1490 if (tabla->mbhc_polling_active) {
1491 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001492 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 tabla_codec_enable_bandgap(codec,
1494 TABLA_BANDGAP_MBHC_MODE);
1495 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1496 0x80);
1497 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001498 tabla_codec_calibrate_hs_polling(codec);
1499 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 }
1501 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1502 }
1503}
1504
1505static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1506{
1507 struct snd_soc_codec *codec = codec_dai->codec;
1508
1509 pr_debug("%s %d\n", __func__, mute);
1510
1511 /* TODO mute TX */
1512 if (mute)
1513 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1514 else
1515 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1516
1517 return 0;
1518}
1519
1520static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1521 int clk_id, unsigned int freq, int dir)
1522{
1523 pr_debug("%s\n", __func__);
1524 return 0;
1525}
1526
1527static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1528{
1529 pr_debug("%s\n", __func__);
1530 return 0;
1531}
1532
1533static int tabla_hw_params(struct snd_pcm_substream *substream,
1534 struct snd_pcm_hw_params *params,
1535 struct snd_soc_dai *dai)
1536{
1537 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1538 return 0;
1539}
1540
1541static struct snd_soc_dai_ops tabla_dai_ops = {
1542 .startup = tabla_startup,
1543 .shutdown = tabla_shutdown,
1544 .hw_params = tabla_hw_params,
1545 .set_sysclk = tabla_set_dai_sysclk,
1546 .set_fmt = tabla_set_dai_fmt,
1547 .digital_mute = tabla_digital_mute,
1548};
1549
1550static struct snd_soc_dai_driver tabla_dai[] = {
1551 {
1552 .name = "tabla_rx1",
1553 .id = 1,
1554 .playback = {
1555 .stream_name = "AIF1 Playback",
1556 .rates = SNDRV_PCM_RATE_8000_48000,
1557 .formats = TABLA_FORMATS,
1558 .rate_max = 48000,
1559 .rate_min = 8000,
1560 .channels_min = 1,
1561 .channels_max = 2,
1562 },
1563 .ops = &tabla_dai_ops,
1564 },
1565 {
1566 .name = "tabla_tx1",
1567 .id = 2,
1568 .capture = {
1569 .stream_name = "AIF1 Capture",
1570 .rates = SNDRV_PCM_RATE_8000_48000,
1571 .formats = TABLA_FORMATS,
1572 .rate_max = 48000,
1573 .rate_min = 8000,
1574 .channels_min = 1,
1575 .channels_max = 2,
1576 },
1577 .ops = &tabla_dai_ops,
1578 },
1579};
1580
Bradley Rubincb1e2732011-06-23 16:49:20 -07001581static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1582 int dce)
1583{
1584 u8 bias_msb, bias_lsb;
1585 short bias_value;
1586
1587 if (dce) {
1588 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1589 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1590 } else {
1591 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1592 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1593 msleep(100);
1594 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1595 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1596 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1597 }
1598
1599 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1600 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
1601
1602 bias_value = (bias_msb << 8) | bias_lsb;
1603 pr_debug("read microphone bias value %x\n", bias_value);
1604 return bias_value;
1605}
1606
1607static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608{
1609 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1610 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001611 int micbias_ctl_reg, micbias_cfilt_val_reg, micbias_cfilt_ctl_reg,
1612 micbias_mbhc_reg;
1613 short bias_value, threshold_no_mic;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614
1615 if (!calibration) {
1616 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001617 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 }
1619
1620 tabla->mbhc_polling_active = true;
1621
1622 if (!tabla->ref_cnt) {
1623 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1624 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1625 tabla_codec_enable_clock_block(codec, 1);
1626 }
1627
1628 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0F, 0x0D);
1631 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1632
1633 /* TODO select cfilt separately from the micbias line inside the machine
1634 * driver
1635 */
1636 switch (calibration->bias) {
1637 case TABLA_MICBIAS1:
1638 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1639 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1640 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_1_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001641 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 break;
1643 case TABLA_MICBIAS2:
1644 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1645 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1646 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_2_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001647 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 break;
1649 case TABLA_MICBIAS3:
1650 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1651 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1652 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_3_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001653 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 break;
1655 case TABLA_MICBIAS4:
1656 pr_err("%s: Error, microphone bias 4 not supported\n",
1657 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001658 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 default:
1660 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001661 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 }
1663 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1664
Bradley Rubincb1e2732011-06-23 16:49:20 -07001665 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
1666 snd_soc_update_bits(codec, micbias_ctl_reg, 0x60,
1667 calibration->bias << 5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668
1669 snd_soc_write(codec, micbias_cfilt_val_reg, 0x68);
1670
1671 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001672 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673
1674 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1675 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1676 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1677
1678 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001679 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1680 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681
Bradley Rubincb1e2732011-06-23 16:49:20 -07001682 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1684
Bradley Rubincb1e2732011-06-23 16:49:20 -07001685 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1686 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1687
1688 tabla_codec_calibrate_hs_polling(codec);
1689
1690 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
1691
1692 threshold_no_mic = 0xF7F6;
1693
1694 if (bias_value < threshold_no_mic) {
1695 pr_debug("headphone detected, micbias %x\n", bias_value);
1696 return 0;
1697 } else {
1698 pr_debug("headset detected, micbias %x\n", bias_value);
1699 return 1;
1700 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701}
1702
1703static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1704 int insertion)
1705{
1706 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1707 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1708 int central_bias_enabled = 0;
1709 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1710
1711 if (!calibration) {
1712 pr_err("Error, no tabla calibration\n");
1713 return -EINVAL;
1714 }
1715
1716 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1717
1718 if (insertion)
1719 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1720 else
1721 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1722
1723 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1724 if (!(tabla->clock_active)) {
1725 tabla_codec_enable_config_mode(codec, 1);
1726 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001727 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 usleep_range(calibration->shutdown_plug_removal,
1729 calibration->shutdown_plug_removal);
1730 tabla_codec_enable_config_mode(codec, 0);
1731 } else
1732 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001733 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 }
1735
1736 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1737 calibration->hph_current << 2);
1738
1739 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1740
1741 switch (calibration->bias) {
1742 case TABLA_MICBIAS1:
1743 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1744 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1745 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1746 break;
1747 case TABLA_MICBIAS2:
1748 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1749 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1750 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1751 break;
1752 case TABLA_MICBIAS3:
1753 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1754 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1755 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1756 break;
1757 case TABLA_MICBIAS4:
1758 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1759 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1760 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1761 break;
1762 default:
1763 pr_err("Error, invalid mic bias line\n");
1764 return -EINVAL;
1765 }
1766 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1767 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1768
1769 /* If central bandgap disabled */
1770 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1771 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1772 usleep_range(calibration->bg_fast_settle,
1773 calibration->bg_fast_settle);
1774 central_bias_enabled = 1;
1775 }
1776
1777 /* If LDO_H disabled */
1778 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1779 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1780 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1781 usleep_range(calibration->tldoh, calibration->tldoh);
1782 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1783
1784 if (central_bias_enabled)
1785 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1786 }
1787 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1788 calibration->mic_current << 5);
1789 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1790 usleep_range(calibration->mic_pid, calibration->mic_pid);
1791 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1792
1793 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1794
1795 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1796 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1797 return 0;
1798}
1799
Bradley Rubincb1e2732011-06-23 16:49:20 -07001800int tabla_hs_detect(struct snd_soc_codec *codec,
1801 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 struct tabla_mbhc_calibration *calibration)
1803{
1804 struct tabla_priv *tabla;
1805 if (!codec || !calibration) {
1806 pr_err("Error: no codec or calibration\n");
1807 return -EINVAL;
1808 }
1809 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001810 tabla->headset_jack = headset_jack;
1811 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 tabla->calibration = calibration;
1813
1814 return tabla_codec_enable_hs_detect(codec, 1);
1815}
1816EXPORT_SYMBOL_GPL(tabla_hs_detect);
1817
Bradley Rubincb1e2732011-06-23 16:49:20 -07001818static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819{
1820 struct tabla_priv *priv = data;
1821 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001822
1823 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1824 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1825
1826 pr_debug("%s: Button pressed\n", __func__);
1827 if (priv->button_jack)
1828 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1829 SND_JACK_BTN_0);
1830
1831 priv->buttons_pressed |= SND_JACK_BTN_0;
1832 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1833 0x09);
1834 usleep_range(100000, 100000);
1835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 return IRQ_HANDLED;
1837}
1838
Bradley Rubincb1e2732011-06-23 16:49:20 -07001839static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840{
1841 struct tabla_priv *priv = data;
1842 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001843 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1844 pr_debug("%s: Button released\n", __func__);
1845 if (priv->button_jack)
1846 snd_soc_jack_report(priv->button_jack, 0,
1847 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848
Bradley Rubincb1e2732011-06-23 16:49:20 -07001849 priv->buttons_pressed &= ~SND_JACK_BTN_0;
1850 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1851 0x08);
1852 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854
1855 return IRQ_HANDLED;
1856}
1857
Bradley Rubincb1e2732011-06-23 16:49:20 -07001858static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1859{
1860 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1861 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1862 int micbias_mbhc_reg;
1863
1864 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1865 tabla_codec_enable_config_mode(codec, 1);
1866
1867 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1868 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
1869 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x0);
1870
1871 switch (calibration->bias) {
1872 case TABLA_MICBIAS1:
1873 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1874 break;
1875 case TABLA_MICBIAS2:
1876 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1877 break;
1878 case TABLA_MICBIAS3:
1879 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1880 break;
1881 case TABLA_MICBIAS4:
1882 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1883 break;
1884 default:
1885 pr_err("Error, invalid mic bias line\n");
1886 return;
1887 }
1888 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
1889 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1890 usleep_range(calibration->shutdown_plug_removal,
1891 calibration->shutdown_plug_removal);
1892
1893 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1894 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1895 tabla_codec_enable_config_mode(codec, 0);
1896
1897 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
1898}
1899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
1901{
1902 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001903
1904 tabla_codec_shutdown_hs_removal_detect(codec);
1905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906 if (!tabla->ref_cnt) {
1907 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
1908 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1909 tabla_codec_enable_clock_block(codec, 0);
1910 }
1911
1912 tabla->mbhc_polling_active = false;
1913}
1914
Bradley Rubincb1e2732011-06-23 16:49:20 -07001915static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
1916{
1917 struct tabla_priv *priv = data;
1918 struct snd_soc_codec *codec = priv->codec;
1919 int microphone_present;
1920
1921 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1922
1923 usleep_range(priv->calibration->setup_plug_removal_delay,
1924 priv->calibration->setup_plug_removal_delay);
1925
1926 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
1927 if (priv->headset_jack) {
1928 pr_debug("%s: Reporting removal\n", __func__);
1929 snd_soc_jack_report(priv->headset_jack, 0,
1930 SND_JACK_HEADSET);
1931 }
1932 tabla_codec_shutdown_hs_removal_detect(codec);
1933 tabla_codec_enable_hs_detect(codec, 1);
1934 return IRQ_HANDLED;
1935 }
1936
1937 microphone_present = tabla_codec_setup_hs_polling(codec);
1938
1939 if (microphone_present == 0) {
1940 if (priv->headset_jack) {
1941 pr_debug("%s: Reporting insertion %d\n", __func__,
1942 SND_JACK_HEADPHONE);
1943 snd_soc_jack_report(priv->headset_jack,
1944 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
1945 }
1946 tabla_codec_shutdown_hs_polling(codec);
1947 tabla_codec_enable_hs_detect(codec, 0);
1948 } else if (microphone_present == 1) {
1949 if (priv->headset_jack) {
1950 pr_debug("%s: Reporting insertion %d\n", __func__,
1951 SND_JACK_HEADSET);
1952 snd_soc_jack_report(priv->headset_jack,
1953 SND_JACK_HEADSET, SND_JACK_HEADSET);
1954 }
1955 tabla_codec_start_hs_polling(codec);
1956 }
1957
1958 return IRQ_HANDLED;
1959}
1960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
1962{
1963 struct tabla_priv *priv = data;
1964 struct snd_soc_codec *codec = priv->codec;
1965
1966 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1967 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1968
1969 usleep_range(priv->calibration->shutdown_plug_removal,
1970 priv->calibration->shutdown_plug_removal);
1971
Bradley Rubincb1e2732011-06-23 16:49:20 -07001972 if (priv->headset_jack) {
1973 pr_debug("%s: Reporting removal\n", __func__);
1974 snd_soc_jack_report(priv->headset_jack, 0, SND_JACK_HEADSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975 }
1976 tabla_codec_shutdown_hs_polling(codec);
1977
1978 tabla_codec_enable_hs_detect(codec, 1);
1979
1980 return IRQ_HANDLED;
1981}
1982
1983static unsigned long slimbus_value;
1984
1985static irqreturn_t tabla_slimbus_irq(int irq, void *data)
1986{
1987 struct tabla_priv *priv = data;
1988 struct snd_soc_codec *codec = priv->codec;
1989 int i, j;
1990 u8 val;
1991
1992 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
1993 slimbus_value = tabla_interface_reg_read(codec->control_data,
1994 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
1995 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
1996 val = tabla_interface_reg_read(codec->control_data,
1997 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
1998 if (val & 0x1)
1999 pr_err_ratelimited("overflow error on port %x,"
2000 " value %x\n", i*8 + j, val);
2001 if (val & 0x2)
2002 pr_err_ratelimited("underflow error on port %x,"
2003 " value %x\n", i*8 + j, val);
2004 }
2005 tabla_interface_reg_write(codec->control_data,
2006 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2007 }
2008
2009 return IRQ_HANDLED;
2010}
2011
2012static int tabla_codec_probe(struct snd_soc_codec *codec)
2013{
2014 struct tabla *control;
2015 struct tabla_priv *tabla;
2016 struct snd_soc_dapm_context *dapm = &codec->dapm;
2017 int ret = 0;
2018 int i;
2019 int tx_channel;
2020
2021 codec->control_data = dev_get_drvdata(codec->dev->parent);
2022 control = codec->control_data;
2023
2024 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2025 if (!tabla) {
2026 dev_err(codec->dev, "Failed to allocate private data\n");
2027 return -ENOMEM;
2028 }
2029
2030 snd_soc_codec_set_drvdata(codec, tabla);
2031
2032 tabla->ref_cnt = 0;
2033 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2034 tabla->clock_active = false;
2035 tabla->config_mode_active = false;
2036 tabla->mbhc_polling_active = false;
2037 tabla->codec = codec;
2038
2039 /* TODO only enable bandgap when necessary in order to save power */
2040 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2041 tabla_codec_enable_clock_block(codec, 0);
2042
2043 /* Initialize gain registers to use register gain */
2044 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
2045 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
2046 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
2047 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
2048
2049 /* Initialize mic biases to differential mode */
2050 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
2051 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
2052 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
2053 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
2054
2055 /* Set headset CFILT to fast mode */
2056 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_CTL, 0x00, 0x00);
2057 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_CTL, 0x00, 0x00);
2058 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_CTL, 0x00, 0x00);
2059
2060 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
2061
2062 /* Use 16 bit sample size for now */
2063 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
2064 snd_soc_update_bits(codec,
2065 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
2066 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002067 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068
2069 }
2070 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
2071 snd_soc_update_bits(codec,
2072 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
2073 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002074 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 }
2076 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
2077 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
2078
2079 snd_soc_add_controls(codec, tabla_snd_controls,
2080 ARRAY_SIZE(tabla_snd_controls));
2081 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2082 ARRAY_SIZE(tabla_dapm_widgets));
2083 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2084 snd_soc_dapm_sync(dapm);
2085
2086 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2087 tabla_hs_insert_irq, "Headset insert detect", tabla);
2088 if (ret) {
2089 pr_err("%s: Failed to request irq %d\n", __func__,
2090 TABLA_IRQ_MBHC_INSERTION);
2091 goto err_insert_irq;
2092 }
2093 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2094
2095 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2096 tabla_hs_remove_irq, "Headset remove detect", tabla);
2097 if (ret) {
2098 pr_err("%s: Failed to request irq %d\n", __func__,
2099 TABLA_IRQ_MBHC_REMOVAL);
2100 goto err_remove_irq;
2101 }
2102 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2103
2104 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002105 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106 if (ret) {
2107 pr_err("%s: Failed to request irq %d\n", __func__,
2108 TABLA_IRQ_MBHC_POTENTIAL);
2109 goto err_potential_irq;
2110 }
2111 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2112
Bradley Rubincb1e2732011-06-23 16:49:20 -07002113 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2114 tabla_release_handler, "Button Release detect", tabla);
2115 if (ret) {
2116 pr_err("%s: Failed to request irq %d\n", __func__,
2117 TABLA_IRQ_MBHC_RELEASE);
2118 goto err_release_irq;
2119 }
2120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002121 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2122 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2123 if (ret) {
2124 pr_err("%s: Failed to request irq %d\n", __func__,
2125 TABLA_IRQ_SLIMBUS);
2126 goto err_slimbus_irq;
2127 }
2128
2129 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2130 tabla_interface_reg_write(codec->control_data,
2131 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2132
2133 return ret;
2134
2135err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002136 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2137err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002138 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2139err_potential_irq:
2140 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2141err_remove_irq:
2142 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2143err_insert_irq:
2144 kfree(tabla);
2145 return ret;
2146}
2147static int tabla_codec_remove(struct snd_soc_codec *codec)
2148{
2149 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2150 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002151 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2153 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2154 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2155 tabla_codec_disable_clock_block(codec);
2156 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2157 kfree(tabla);
2158 return 0;
2159}
2160static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2161 .probe = tabla_codec_probe,
2162 .remove = tabla_codec_remove,
2163 .read = tabla_read,
2164 .write = tabla_write,
2165
2166 .readable_register = tabla_readable,
2167 .volatile_register = tabla_volatile,
2168
2169 .reg_cache_size = TABLA_CACHE_SIZE,
2170 .reg_cache_default = tabla_reg_defaults,
2171 .reg_word_size = 1,
2172};
2173static int __devinit tabla_probe(struct platform_device *pdev)
2174{
2175 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2176 tabla_dai, ARRAY_SIZE(tabla_dai));
2177}
2178static int __devexit tabla_remove(struct platform_device *pdev)
2179{
2180 snd_soc_unregister_codec(&pdev->dev);
2181 return 0;
2182}
2183static struct platform_driver tabla_codec_driver = {
2184 .probe = tabla_probe,
2185 .remove = tabla_remove,
2186 .driver = {
2187 .name = "tabla_codec",
2188 .owner = THIS_MODULE,
2189 },
2190};
2191
2192static int __init tabla_codec_init(void)
2193{
2194 return platform_driver_register(&tabla_codec_driver);
2195}
2196
2197static void __exit tabla_codec_exit(void)
2198{
2199 platform_driver_unregister(&tabla_codec_driver);
2200}
2201
2202module_init(tabla_codec_init);
2203module_exit(tabla_codec_exit);
2204
2205MODULE_DESCRIPTION("Tabla codec driver");
2206MODULE_VERSION("1.0");
2207MODULE_LICENSE("GPL v2");