blob: b23f91efed8433a2b2f7e2b59ac70be8d2167ebc [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
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700126 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
127 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700128 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
129 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700130 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
131 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132
133 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700134 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
135 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136};
137
138static const char *rx_mix1_text[] = {
139 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
140 "RX5", "RX6", "RX7"
141};
142
143static const char *sb_tx1_mux_text[] = {
144 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
145 "DEC1"
146};
147
148static const char *sb_tx5_mux_text[] = {
149 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
150 "DEC5"
151};
152
153static const char *sb_tx6_mux_text[] = {
154 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
155 "DEC6"
156};
157
158static const char const *sb_tx7_to_tx10_mux_text[] = {
159 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
160 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
161 "DEC9", "DEC10"
162};
163
164static const char *dec1_mux_text[] = {
165 "ZERO", "DMIC1", "ADC6",
166};
167
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700168static const char *dec2_mux_text[] = {
169 "ZERO", "DMIC2", "ADC5",
170};
171
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700172static const char *dec3_mux_text[] = {
173 "ZERO", "DMIC3", "ADC4",
174};
175
176static const char *dec4_mux_text[] = {
177 "ZERO", "DMIC4", "ADC3",
178};
179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180static const char *dec5_mux_text[] = {
181 "ZERO", "DMIC5", "ADC2",
182};
183
184static const char *dec6_mux_text[] = {
185 "ZERO", "DMIC6", "ADC1",
186};
187
188static const char const *dec7_mux_text[] = {
189 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
190};
191
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700192static const char *dec8_mux_text[] = {
193 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
194};
195
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700196static const char *dec9_mux_text[] = {
197 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
198};
199
200static const char *dec10_mux_text[] = {
201 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
202};
203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204static const char *iir1_inp1_text[] = {
205 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
206 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
207};
208
209static const struct soc_enum rx_mix1_inp1_chain_enum =
210 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
211
212static const struct soc_enum rx2_mix1_inp1_chain_enum =
213 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
214
215static const struct soc_enum rx3_mix1_inp1_chain_enum =
216 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
217
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700218static const struct soc_enum rx3_mix1_inp2_chain_enum =
219 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221static const struct soc_enum rx4_mix1_inp1_chain_enum =
222 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
223
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700224static const struct soc_enum rx4_mix1_inp2_chain_enum =
225 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227static const struct soc_enum rx5_mix1_inp1_chain_enum =
228 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
229
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700230static const struct soc_enum rx5_mix1_inp2_chain_enum =
231 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
232
233static const struct soc_enum rx6_mix1_inp1_chain_enum =
234 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
235
236static const struct soc_enum rx6_mix1_inp2_chain_enum =
237 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239static const struct soc_enum sb_tx5_mux_enum =
240 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
241
242static const struct soc_enum sb_tx6_mux_enum =
243 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
244
245static const struct soc_enum sb_tx7_mux_enum =
246 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
247 sb_tx7_to_tx10_mux_text);
248
249static const struct soc_enum sb_tx8_mux_enum =
250 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
251 sb_tx7_to_tx10_mux_text);
252
253static const struct soc_enum sb_tx1_mux_enum =
254 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
255
256static const struct soc_enum dec1_mux_enum =
257 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
258
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700259static const struct soc_enum dec2_mux_enum =
260 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
261
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700262static const struct soc_enum dec3_mux_enum =
263 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
264
265static const struct soc_enum dec4_mux_enum =
266 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268static const struct soc_enum dec5_mux_enum =
269 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
270
271static const struct soc_enum dec6_mux_enum =
272 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
273
274static const struct soc_enum dec7_mux_enum =
275 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
276
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700277static const struct soc_enum dec8_mux_enum =
278 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
279
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700280static const struct soc_enum dec9_mux_enum =
281 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
282
283static const struct soc_enum dec10_mux_enum =
284 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286static const struct soc_enum iir1_inp1_mux_enum =
287 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
288
289static const struct snd_kcontrol_new rx_mix1_inp1_mux =
290 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
291
292static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
293 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
294
295static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
296 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
297
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700298static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
299 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
302 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
303
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700304static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
305 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
308 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
309
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700310static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
311 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
312
313static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
314 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
315
316static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
317 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319static const struct snd_kcontrol_new sb_tx5_mux =
320 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
321
322static const struct snd_kcontrol_new sb_tx6_mux =
323 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
324
325static const struct snd_kcontrol_new sb_tx7_mux =
326 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
327
328static const struct snd_kcontrol_new sb_tx8_mux =
329 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
330
331static const struct snd_kcontrol_new sb_tx1_mux =
332 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
333
334static const struct snd_kcontrol_new dec1_mux =
335 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
336
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700337static const struct snd_kcontrol_new dec2_mux =
338 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
339
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700340static const struct snd_kcontrol_new dec3_mux =
341 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
342
343static const struct snd_kcontrol_new dec4_mux =
344 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346static const struct snd_kcontrol_new dec5_mux =
347 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
348
349static const struct snd_kcontrol_new dec6_mux =
350 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
351
352static const struct snd_kcontrol_new dec7_mux =
353 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
354
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700355static const struct snd_kcontrol_new dec8_mux =
356 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
357
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700358static const struct snd_kcontrol_new dec9_mux =
359 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
360
361static const struct snd_kcontrol_new dec10_mux =
362 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364static const struct snd_kcontrol_new iir1_inp1_mux =
365 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
366
367static const struct snd_kcontrol_new dac1_control =
368 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0);
369
370static const struct snd_kcontrol_new hphl_switch =
371 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0);
372
373static const struct snd_kcontrol_new hphr_switch =
374 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0);
375
376static const struct snd_kcontrol_new lineout1_switch =
377 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0);
378
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700379static const struct snd_kcontrol_new lineout2_switch =
380 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0);
381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382static const struct snd_kcontrol_new lineout3_switch =
383 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
384
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700385static const struct snd_kcontrol_new lineout4_switch =
386 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
387
388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
390 int enable)
391{
392 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
393
394 pr_debug("%s %d\n", __func__, enable);
395
396 if (enable) {
397 tabla->adc_count++;
398 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
399 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
400 } else {
401 tabla->adc_count--;
402 if (!tabla->adc_count) {
403 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
404 0x2, 0x0);
405 if (!tabla->mbhc_polling_active)
406 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
407 0xE0, 0x0);
408 }
409 }
410}
411
412static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
413 struct snd_kcontrol *kcontrol, int event)
414{
415 struct snd_soc_codec *codec = w->codec;
416 u16 adc_reg;
417
418 pr_debug("%s %d\n", __func__, event);
419
420 if (w->reg == TABLA_A_TX_1_2_EN)
421 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
422 else if (w->reg == TABLA_A_TX_3_4_EN)
423 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
424 else if (w->reg == TABLA_A_TX_5_6_EN)
425 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
426 else {
427 pr_err("%s: Error, invalid adc register\n", __func__);
428 return -EINVAL;
429 }
430
431 switch (event) {
432 case SND_SOC_DAPM_PRE_PMU:
433 tabla_codec_enable_adc_block(codec, 1);
434 break;
435 case SND_SOC_DAPM_POST_PMU:
436 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
437 1 << w->shift);
438 usleep_range(1000, 1000);
439 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
440 usleep_range(1000, 1000);
441 break;
442 case SND_SOC_DAPM_POST_PMD:
443 tabla_codec_enable_adc_block(codec, 0);
444 break;
445 }
446 return 0;
447}
448
449static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
450 struct snd_kcontrol *kcontrol, int event)
451{
452 struct snd_soc_codec *codec = w->codec;
453
454 pr_debug("%s %d\n", __func__, event);
455 switch (event) {
456 case SND_SOC_DAPM_PRE_PMU:
457 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
458 break;
459 case SND_SOC_DAPM_POST_PMD:
460 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
461 break;
462 }
463 return 0;
464}
465
466static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
467 struct snd_kcontrol *kcontrol, int event)
468{
469 struct snd_soc_codec *codec = w->codec;
470 u16 lineout_gain_reg;
471
472 pr_debug("%s %d\n", __func__, event);
473
474 switch (w->shift) {
475 case 0:
476 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
477 break;
478 case 1:
479 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
480 break;
481 case 2:
482 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
483 break;
484 case 3:
485 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
486 break;
487 case 4:
488 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
489 break;
490 default:
491 pr_err("%s: Error, incorrect lineout register value\n",
492 __func__);
493 return -EINVAL;
494 }
495
496 switch (event) {
497 case SND_SOC_DAPM_PRE_PMU:
498 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
499 break;
500 case SND_SOC_DAPM_POST_PMU:
501 usleep_range(40000, 40000);
502 break;
503 case SND_SOC_DAPM_POST_PMD:
504 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
505 break;
506 }
507 return 0;
508}
509
510static int tabla_codec_enable_dmic1(struct snd_soc_dapm_widget *w,
511 struct snd_kcontrol *kcontrol, int event)
512{
513 struct snd_soc_codec *codec = w->codec;
514
515 pr_debug("%s %d\n", __func__, event);
516 switch (event) {
517 case SND_SOC_DAPM_PRE_PMU:
518 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_MUX_CTL, 0x1, 0x1);
519 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x2, 0x2);
520 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1);
521 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x1, 0x1);
522 break;
523 case SND_SOC_DAPM_POST_PMD:
524 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0);
525 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x3, 0);
526 break;
527 }
528 return 0;
529}
530
531static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
532 struct snd_kcontrol *kcontrol, int event)
533{
534 struct snd_soc_codec *codec = w->codec;
535 u16 micb_cfilt_reg, micb_int_reg;
536 char *internal_text = "Internal";
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700537 u8 cfilt_sel_val = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538
539 pr_debug("%s %d\n", __func__, event);
540 switch (w->reg) {
541 case TABLA_A_MICB_1_CTL:
542 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
543 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700544 cfilt_sel_val = 0x00;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 break;
546 case TABLA_A_MICB_2_CTL:
547 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
548 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700549 cfilt_sel_val = 0x20;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 break;
551 case TABLA_A_MICB_3_CTL:
552 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
553 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700554 cfilt_sel_val = 0x40;
555 break;
556 case TABLA_A_MICB_4_CTL:
557 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
558 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
559 cfilt_sel_val = 0x40;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 break;
561 default:
562 pr_err("%s: Error, invalid micbias register\n", __func__);
563 return -EINVAL;
564 }
565
566 switch (event) {
567 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700568 snd_soc_update_bits(codec, w->reg, 0x60, cfilt_sel_val);
569 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
571 if (strnstr(w->name, internal_text, 20))
572 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
573 break;
574 case SND_SOC_DAPM_POST_PMD:
575 if (strnstr(w->name, internal_text, 20))
576 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
577 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
578 break;
579 }
580
581 return 0;
582}
583
584static void tabla_codec_enable_dec_clock(struct snd_soc_codec *codec,
585 int enable)
586{
587 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
588
589 if (enable) {
590 tabla->dec_count++;
591 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x4, 0x4);
592 } else {
593 tabla->dec_count--;
594 if (!tabla->dec_count)
595 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
596 0x4, 0x0);
597 }
598}
599
600static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
601 struct snd_kcontrol *kcontrol, int event)
602{
603 struct snd_soc_codec *codec = w->codec;
604 u16 dec_reset_reg;
605
606 pr_debug("%s %d\n", __func__, event);
607
608 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
609 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
610 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
611 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
612 else {
613 pr_err("%s: Error, incorrect dec\n", __func__);
614 return -EINVAL;
615 }
616
617 switch (event) {
618 case SND_SOC_DAPM_PRE_PMU:
619 tabla_codec_enable_dec_clock(codec, 1);
620 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
621 1 << w->shift);
622 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
623 break;
624 case SND_SOC_DAPM_POST_PMD:
625 tabla_codec_enable_dec_clock(codec, 0);
626 break;
627 }
628 return 0;
629}
630
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700631static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 struct snd_kcontrol *kcontrol, int event)
633{
634 struct snd_soc_codec *codec = w->codec;
635
636 switch (event) {
637 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700638 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
639 1 << w->shift, 1 << w->shift);
640 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
641 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 break;
643 }
644 return 0;
645}
646
647static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
648 /*RX stuff */
649 SND_SOC_DAPM_OUTPUT("EAR"),
650
651 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
652 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
653 SND_SOC_DAPM_PRE_PMD),
654
655 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
656
657 SND_SOC_DAPM_SWITCH("DAC1", TABLA_A_RX_EAR_EN, 6, 0, &dac1_control),
658 SND_SOC_DAPM_PGA_E("RX1 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
659 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
660 SND_SOC_DAPM_PRE_PMD),
661 SND_SOC_DAPM_PGA("RX BIAS", TABLA_A_RX_COM_BIAS, 7, 0, NULL, 0),
662 SND_SOC_DAPM_MUX_E("RX1 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0,
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700663 &rx_mix1_inp1_mux, tabla_codec_reset_interpolator,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 SND_SOC_DAPM_PRE_PMU),
665 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0,
666 TABLA_A_CDC_RX1_B6_CTL, 5, 0),
667
668 /* RX 2 path */
669 SND_SOC_DAPM_PGA_E("RX2 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
670 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
671 SND_SOC_DAPM_PRE_PMD),
672 SND_SOC_DAPM_MUX_E("RX2 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0,
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700673 &rx2_mix1_inp1_mux, tabla_codec_reset_interpolator,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 SND_SOC_DAPM_PRE_PMU),
675 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0,
676 TABLA_A_CDC_RX2_B6_CTL, 5, 0),
677
678 /* Headphone */
679 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
680 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
681 SND_SOC_DAPM_SWITCH("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
682 &hphl_switch),
683
684 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
685 SND_SOC_DAPM_SWITCH("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
686 &hphr_switch),
687
688 /* Speaker */
689 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
692 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
693 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700694 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
695 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
696 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700697 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
698 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
699 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700700 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
701 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
702 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
703
704 SND_SOC_DAPM_SWITCH("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
705 &lineout1_switch),
706 SND_SOC_DAPM_SWITCH("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
707 &lineout2_switch),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
709 &lineout3_switch),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700710 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
711 &lineout4_switch),
712
713 SND_SOC_DAPM_PGA_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL, 0,
714 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
715 SND_SOC_DAPM_PGA_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL, 0,
716 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
717 SND_SOC_DAPM_PGA_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL, 0,
718 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
719 SND_SOC_DAPM_PGA_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL, 0,
720 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
721
722 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
723 &rx3_mix1_inp1_mux),
724 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
725 &rx3_mix1_inp2_mux),
726 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
727 &rx4_mix1_inp1_mux),
728 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
729 &rx4_mix1_inp2_mux),
730 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
731 &rx5_mix1_inp1_mux),
732 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
733 &rx5_mix1_inp2_mux),
734 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
735 &rx6_mix1_inp1_mux),
736 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
737 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738
739 /* TX */
740 SND_SOC_DAPM_INPUT("AMIC1"),
741 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
742 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
743 SND_SOC_DAPM_POST_PMD),
744 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal", TABLA_A_MICB_1_CTL, 7, 0,
745 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
746 SND_SOC_DAPM_POST_PMD),
747 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
748 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
749 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
750
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700751 SND_SOC_DAPM_INPUT("AMIC3"),
752 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
753 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
754 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
755
756 SND_SOC_DAPM_INPUT("AMIC4"),
757 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
758 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
759 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
760
761 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
762 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
763 SND_SOC_DAPM_POST_PMD),
764
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700765 SND_SOC_DAPM_INPUT("AMIC5"),
766 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
767 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
768
769 SND_SOC_DAPM_INPUT("AMIC6"),
770 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
771 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
774 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
775 SND_SOC_DAPM_POST_PMD),
776
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700777 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
778 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
779 SND_SOC_DAPM_POST_PMD),
780
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700781 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
782 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
783 SND_SOC_DAPM_POST_PMD),
784
785 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
786 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
787 SND_SOC_DAPM_POST_PMD),
788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
790 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
791 SND_SOC_DAPM_POST_PMD),
792
793 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
794 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
795 SND_SOC_DAPM_POST_PMD),
796
797 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
798 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
799 SND_SOC_DAPM_POST_PMD),
800
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700801 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
802 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
803 SND_SOC_DAPM_POST_PMD),
804
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700805 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
806 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
807 SND_SOC_DAPM_POST_PMD),
808
809 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
810 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
811 SND_SOC_DAPM_POST_PMD),
812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 SND_SOC_DAPM_INPUT("AMIC2"),
814 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
815 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
816 SND_SOC_DAPM_POST_PMD),
817 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal", TABLA_A_MICB_2_CTL, 7, 0,
818 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
819 SND_SOC_DAPM_POST_PMD),
820 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
821 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
822 SND_SOC_DAPM_POST_PMD),
823 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal", TABLA_A_MICB_3_CTL, 7, 0,
824 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
825 SND_SOC_DAPM_POST_PMD),
826 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
827 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
828 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
829
830 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
831 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
832 0, 0),
833
834 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
835 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
836 4, 0),
837
838 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
839 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
840 5, 0),
841
842 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
843 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
844 0, 0),
845
846 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
847 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
848 0, 0),
849
850 /* Digital Mic */
851 SND_SOC_DAPM_INPUT("DMIC1 IN"),
852 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic1),
853
854 /* Sidetone */
855 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
856 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
857};
858
859static const struct snd_soc_dapm_route audio_map[] = {
860 /* SLIMBUS Connections */
861 {"RX BIAS", NULL, "SLIM RX1"},
862 {"RX BIAS", NULL, "SLIM RX2"},
863
864 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
865 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
866
867 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
868 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
869
870 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
871 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
872
873 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
874 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700875 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700876 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
877 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
879 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700880 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
881 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700882 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
883 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884
885 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
886 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
887 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
888
889 /* Earpiece (RX MIX1) */
890 {"EAR", NULL, "EAR PA"},
891 {"EAR PA", NULL, "EAR PA Input"},
892 {"EAR PA Input", NULL, "DAC1"},
893 {"DAC1", "Switch", "RX1 CP"},
894 {"RX1 CP", NULL, "RX1 MIX1 INP1"},
895 {"RX1 MIX1 INP1", "RX1", "RX BIAS"},
896
897 /* Headset (RX MIX1 and RX MIX2) */
898 {"HEADPHONE", NULL, "HPHL"},
899 {"HPHL", NULL, "HPHL DAC"},
900 {"HPHL DAC", "Switch", "RX1 MIX1 INP1"},
901
902 {"HEADPHONE", NULL, "HPHR"},
903 {"HPHR", NULL, "HPHR DAC"},
904 {"HPHR DAC", "Switch", "RX2 CP"},
905 {"RX2 CP", NULL, "RX2 MIX1 INP1"},
906 {"RX2 MIX1 INP1", "RX2", "RX BIAS"},
907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700909 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700911 {"LINEOUT", NULL, "LINEOUT4"},
912
913 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
914 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700916 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
917
918 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
919 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
920 {"LINEOUT3 DAC", "Switch", "RX5 MIX1"},
921 {"LINEOUT4 DAC", "Switch", "RX6 MIX1"},
922
923 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
924 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
925 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
926 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
927 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
928 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
929 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
930 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
931
932 {"RX3 MIX1 INP1", "RX1", "RX BIAS"},
933 {"RX3 MIX1 INP1", "RX2", "RX BIAS"},
934 {"RX3 MIX1 INP2", "RX1", "RX BIAS"},
935 {"RX3 MIX1 INP2", "RX2", "RX BIAS"},
936 {"RX4 MIX1 INP1", "RX1", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937 {"RX4 MIX1 INP1", "RX2", "RX BIAS"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700938 {"RX4 MIX1 INP2", "RX1", "RX BIAS"},
939 {"RX4 MIX1 INP2", "RX2", "RX BIAS"},
940 {"RX5 MIX1 INP1", "RX1", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 {"RX5 MIX1 INP1", "RX2", "RX BIAS"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700942 {"RX5 MIX1 INP2", "RX1", "RX BIAS"},
943 {"RX5 MIX1 INP2", "RX2", "RX BIAS"},
944 {"RX6 MIX1 INP1", "RX1", "RX BIAS"},
945 {"RX6 MIX1 INP1", "RX2", "RX BIAS"},
946 {"RX6 MIX1 INP2", "RX1", "RX BIAS"},
947 {"RX6 MIX1 INP2", "RX2", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700949 /* Decimator Inputs */
950 {"DEC1 MUX", "ADC6", "ADC6"},
951 {"DEC1 MUX", "DMIC1", "DMIC1"},
952 {"DEC2 MUX", "ADC5", "ADC5"},
953 {"DEC3 MUX", "ADC4", "ADC4"},
954 {"DEC4 MUX", "ADC3", "ADC3"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955 {"DEC5 MUX", "ADC2", "ADC2"},
956 {"DEC6 MUX", "ADC1", "ADC1"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700957 {"DEC7 MUX", "ADC6", "ADC6"},
958 {"DEC7 MUX", "DMIC1", "DMIC1"},
959 {"DEC8 MUX", "ADC5", "ADC5"},
960 {"DEC9 MUX", "ADC3", "ADC3"},
961 {"DEC10 MUX", "ADC4", "ADC4"},
962
963 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 {"ADC1", NULL, "AMIC1"},
965 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700966 {"ADC3", NULL, "AMIC3"},
967 {"ADC4", NULL, "AMIC4"},
968 {"ADC5", NULL, "AMIC5"},
969 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970
971 /* Digital Mic */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972 {"DMIC1", NULL, "DMIC1 IN"},
973
974 /* Sidetone (IIR1) */
975 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
976 {"IIR1", NULL, "IIR1 INP1 MUX"},
977 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978};
979
980static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
981{
982 return tabla_reg_readable[reg];
983}
984
985static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
986{
987 /* Registers lower than 0x100 are top level registers which can be
988 * written by the Tabla core driver.
989 */
990
991 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
992 return 1;
993
994 return 0;
995}
996
997#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
998static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
999 unsigned int value)
1000{
1001 int ret;
1002 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1003
1004 BUG_ON(reg > TABLA_MAX_REGISTER);
1005
1006 if (!tabla_volatile(codec, reg)) {
1007 pr_debug("writing to cache\n");
1008 ret = snd_soc_cache_write(codec, reg, value);
1009 if (ret != 0)
1010 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1011 reg, ret);
1012 }
1013
1014 return tabla_reg_write(codec->control_data, reg, value);
1015}
1016static unsigned int tabla_read(struct snd_soc_codec *codec,
1017 unsigned int reg)
1018{
1019 unsigned int val;
1020 int ret;
1021
1022 BUG_ON(reg > TABLA_MAX_REGISTER);
1023
1024 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1025 reg < codec->driver->reg_cache_size) {
1026 pr_debug("reading from cache\n");
1027 ret = snd_soc_cache_read(codec, reg, &val);
1028 if (ret >= 0) {
1029 pr_debug("register %d, value %d\n", reg, val);
1030 return val;
1031 } else
1032 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1033 reg, ret);
1034 }
1035
1036 val = tabla_reg_read(codec->control_data, reg);
1037 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1038 return val;
1039}
1040
1041static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1042{
1043 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1044 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1045 0x80);
1046 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1047 0x04);
1048 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1049 0x01);
1050 usleep_range(1000, 1000);
1051 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1052 0x00);
1053}
1054
1055static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1056 enum tabla_bandgap_type choice)
1057{
1058 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1059
1060 /* TODO lock resources accessed by audio streams and threaded
1061 * interrupt handlers
1062 */
1063
1064 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1065 tabla->bandgap_type);
1066
1067 if (tabla->bandgap_type == choice)
1068 return;
1069
1070 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1071 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1072 tabla_codec_enable_audio_mode_bandgap(codec);
1073 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1074 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1075 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1076 0x2);
1077 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1078 0x80);
1079 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1080 0x4);
1081 usleep_range(1000, 1000);
1082 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1083 0x00);
1084 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1085 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1086 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1087 usleep_range(100, 100);
1088 tabla_codec_enable_audio_mode_bandgap(codec);
1089 } else if (choice == TABLA_BANDGAP_OFF) {
1090 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1091 } else {
1092 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1093 }
1094 tabla->bandgap_type = choice;
1095}
1096
1097static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1098 int enable)
1099{
1100 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1101
1102 if (enable) {
1103 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1104 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1105 usleep_range(5, 5);
1106 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1107 0x80);
1108 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1109 0x80);
1110 usleep_range(10, 10);
1111 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1112 usleep_range(20, 20);
1113 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1114 } else {
1115 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1116 0);
1117 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1118 }
1119 tabla->config_mode_active = enable ? true : false;
1120
1121 return 0;
1122}
1123
1124static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1125 int config_mode)
1126{
1127 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1128
1129 pr_debug("%s\n", __func__);
1130
1131 if (config_mode) {
1132 tabla_codec_enable_config_mode(codec, 1);
1133 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1134 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1135 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1136 usleep_range(1000, 1000);
1137 } else
1138 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1139
1140 if (!config_mode && tabla->mbhc_polling_active) {
1141 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1142 tabla_codec_enable_config_mode(codec, 0);
1143
1144 }
1145
1146 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1147 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1148 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1149 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1150 usleep_range(50, 50);
1151 tabla->clock_active = true;
1152 return 0;
1153}
1154static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1155{
1156 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1157 pr_debug("%s\n", __func__);
1158 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1159 ndelay(160);
1160 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1161 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1162 tabla->clock_active = false;
1163}
1164
Bradley Rubincb1e2732011-06-23 16:49:20 -07001165static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1166{
1167 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
1168 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1169 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1170 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1171 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1172 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1173}
1174
1175static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1176{
1177 /* TODO store register values in calibration */
1178
1179 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1180 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1181
1182 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1183 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1184 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1185 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1186
1187 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1188 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1189 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1190 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1191 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1192 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1193}
1194
1195static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1196{
1197 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1198 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1199 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1200}
1201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202static int tabla_startup(struct snd_pcm_substream *substream,
1203 struct snd_soc_dai *dai)
1204{
1205 struct snd_soc_codec *codec = dai->codec;
1206 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1207 int ret = 0;
1208
1209 pr_debug("%s()\n", __func__);
1210
1211 if (!codec) {
1212 pr_err("Error, no codec found\n");
1213 return -EINVAL;
1214 }
1215 tabla->ref_cnt++;
1216
1217 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1218 /* Enable LDO */
1219 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
1220 0xA0);
1221 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
1222 usleep_range(1000, 1000);
1223 }
1224
1225 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001226 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1228 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001229 tabla_codec_calibrate_hs_polling(codec);
1230 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231 }
1232
1233 return ret;
1234}
1235
1236static void tabla_shutdown(struct snd_pcm_substream *substream,
1237 struct snd_soc_dai *dai)
1238{
1239 struct snd_soc_codec *codec = dai->codec;
1240 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1241
1242 pr_debug("%s()\n", __func__);
1243
1244 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1245 /* Disable LDO */
1246 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x00);
1247 usleep_range(1000, 1000);
1248 }
1249
1250 if (!tabla->ref_cnt) {
1251 pr_err("Error, trying to shutdown codec when already down\n");
1252 return;
1253 }
1254 tabla->ref_cnt--;
1255
1256 if (tabla->mbhc_polling_active) {
1257 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001258 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 tabla_codec_enable_bandgap(codec,
1260 TABLA_BANDGAP_MBHC_MODE);
1261 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1262 0x80);
1263 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001264 tabla_codec_calibrate_hs_polling(codec);
1265 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 }
1267 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1268 }
1269}
1270
1271static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1272{
1273 struct snd_soc_codec *codec = codec_dai->codec;
1274
1275 pr_debug("%s %d\n", __func__, mute);
1276
1277 /* TODO mute TX */
1278 if (mute)
1279 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1280 else
1281 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1282
1283 return 0;
1284}
1285
1286static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1287 int clk_id, unsigned int freq, int dir)
1288{
1289 pr_debug("%s\n", __func__);
1290 return 0;
1291}
1292
1293static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1294{
1295 pr_debug("%s\n", __func__);
1296 return 0;
1297}
1298
1299static int tabla_hw_params(struct snd_pcm_substream *substream,
1300 struct snd_pcm_hw_params *params,
1301 struct snd_soc_dai *dai)
1302{
1303 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1304 return 0;
1305}
1306
1307static struct snd_soc_dai_ops tabla_dai_ops = {
1308 .startup = tabla_startup,
1309 .shutdown = tabla_shutdown,
1310 .hw_params = tabla_hw_params,
1311 .set_sysclk = tabla_set_dai_sysclk,
1312 .set_fmt = tabla_set_dai_fmt,
1313 .digital_mute = tabla_digital_mute,
1314};
1315
1316static struct snd_soc_dai_driver tabla_dai[] = {
1317 {
1318 .name = "tabla_rx1",
1319 .id = 1,
1320 .playback = {
1321 .stream_name = "AIF1 Playback",
1322 .rates = SNDRV_PCM_RATE_8000_48000,
1323 .formats = TABLA_FORMATS,
1324 .rate_max = 48000,
1325 .rate_min = 8000,
1326 .channels_min = 1,
1327 .channels_max = 2,
1328 },
1329 .ops = &tabla_dai_ops,
1330 },
1331 {
1332 .name = "tabla_tx1",
1333 .id = 2,
1334 .capture = {
1335 .stream_name = "AIF1 Capture",
1336 .rates = SNDRV_PCM_RATE_8000_48000,
1337 .formats = TABLA_FORMATS,
1338 .rate_max = 48000,
1339 .rate_min = 8000,
1340 .channels_min = 1,
1341 .channels_max = 2,
1342 },
1343 .ops = &tabla_dai_ops,
1344 },
1345};
1346
Bradley Rubincb1e2732011-06-23 16:49:20 -07001347static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1348 int dce)
1349{
1350 u8 bias_msb, bias_lsb;
1351 short bias_value;
1352
1353 if (dce) {
1354 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1355 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1356 } else {
1357 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1358 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1359 msleep(100);
1360 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1361 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1362 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1363 }
1364
1365 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1366 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
1367
1368 bias_value = (bias_msb << 8) | bias_lsb;
1369 pr_debug("read microphone bias value %x\n", bias_value);
1370 return bias_value;
1371}
1372
1373static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374{
1375 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1376 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001377 int micbias_ctl_reg, micbias_cfilt_val_reg, micbias_cfilt_ctl_reg,
1378 micbias_mbhc_reg;
1379 short bias_value, threshold_no_mic;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380
1381 if (!calibration) {
1382 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001383 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 }
1385
1386 tabla->mbhc_polling_active = true;
1387
1388 if (!tabla->ref_cnt) {
1389 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1390 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1391 tabla_codec_enable_clock_block(codec, 1);
1392 }
1393
1394 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0F, 0x0D);
1397 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1398
1399 /* TODO select cfilt separately from the micbias line inside the machine
1400 * driver
1401 */
1402 switch (calibration->bias) {
1403 case TABLA_MICBIAS1:
1404 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1405 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1406 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_1_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001407 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 break;
1409 case TABLA_MICBIAS2:
1410 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1411 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1412 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_2_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001413 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414 break;
1415 case TABLA_MICBIAS3:
1416 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1417 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1418 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_3_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001419 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 break;
1421 case TABLA_MICBIAS4:
1422 pr_err("%s: Error, microphone bias 4 not supported\n",
1423 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001424 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 default:
1426 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001427 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 }
1429 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1430
Bradley Rubincb1e2732011-06-23 16:49:20 -07001431 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
1432 snd_soc_update_bits(codec, micbias_ctl_reg, 0x60,
1433 calibration->bias << 5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434
1435 snd_soc_write(codec, micbias_cfilt_val_reg, 0x68);
1436
1437 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001438 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439
1440 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1441 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1442 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1443
1444 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001445 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1446 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447
Bradley Rubincb1e2732011-06-23 16:49:20 -07001448 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1450
Bradley Rubincb1e2732011-06-23 16:49:20 -07001451 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1452 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1453
1454 tabla_codec_calibrate_hs_polling(codec);
1455
1456 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
1457
1458 threshold_no_mic = 0xF7F6;
1459
1460 if (bias_value < threshold_no_mic) {
1461 pr_debug("headphone detected, micbias %x\n", bias_value);
1462 return 0;
1463 } else {
1464 pr_debug("headset detected, micbias %x\n", bias_value);
1465 return 1;
1466 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467}
1468
1469static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1470 int insertion)
1471{
1472 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1473 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1474 int central_bias_enabled = 0;
1475 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1476
1477 if (!calibration) {
1478 pr_err("Error, no tabla calibration\n");
1479 return -EINVAL;
1480 }
1481
1482 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1483
1484 if (insertion)
1485 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1486 else
1487 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1488
1489 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1490 if (!(tabla->clock_active)) {
1491 tabla_codec_enable_config_mode(codec, 1);
1492 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001493 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 usleep_range(calibration->shutdown_plug_removal,
1495 calibration->shutdown_plug_removal);
1496 tabla_codec_enable_config_mode(codec, 0);
1497 } else
1498 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001499 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 }
1501
1502 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1503 calibration->hph_current << 2);
1504
1505 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1506
1507 switch (calibration->bias) {
1508 case TABLA_MICBIAS1:
1509 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1510 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1511 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1512 break;
1513 case TABLA_MICBIAS2:
1514 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1515 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1516 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1517 break;
1518 case TABLA_MICBIAS3:
1519 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1520 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1521 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1522 break;
1523 case TABLA_MICBIAS4:
1524 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1525 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1526 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1527 break;
1528 default:
1529 pr_err("Error, invalid mic bias line\n");
1530 return -EINVAL;
1531 }
1532 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1533 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1534
1535 /* If central bandgap disabled */
1536 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1537 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1538 usleep_range(calibration->bg_fast_settle,
1539 calibration->bg_fast_settle);
1540 central_bias_enabled = 1;
1541 }
1542
1543 /* If LDO_H disabled */
1544 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1545 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1546 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1547 usleep_range(calibration->tldoh, calibration->tldoh);
1548 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1549
1550 if (central_bias_enabled)
1551 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1552 }
1553 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1554 calibration->mic_current << 5);
1555 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1556 usleep_range(calibration->mic_pid, calibration->mic_pid);
1557 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1558
1559 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1560
1561 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1562 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1563 return 0;
1564}
1565
Bradley Rubincb1e2732011-06-23 16:49:20 -07001566int tabla_hs_detect(struct snd_soc_codec *codec,
1567 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 struct tabla_mbhc_calibration *calibration)
1569{
1570 struct tabla_priv *tabla;
1571 if (!codec || !calibration) {
1572 pr_err("Error: no codec or calibration\n");
1573 return -EINVAL;
1574 }
1575 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001576 tabla->headset_jack = headset_jack;
1577 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 tabla->calibration = calibration;
1579
1580 return tabla_codec_enable_hs_detect(codec, 1);
1581}
1582EXPORT_SYMBOL_GPL(tabla_hs_detect);
1583
Bradley Rubincb1e2732011-06-23 16:49:20 -07001584static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585{
1586 struct tabla_priv *priv = data;
1587 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001588
1589 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1590 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1591
1592 pr_debug("%s: Button pressed\n", __func__);
1593 if (priv->button_jack)
1594 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1595 SND_JACK_BTN_0);
1596
1597 priv->buttons_pressed |= SND_JACK_BTN_0;
1598 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1599 0x09);
1600 usleep_range(100000, 100000);
1601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001602 return IRQ_HANDLED;
1603}
1604
Bradley Rubincb1e2732011-06-23 16:49:20 -07001605static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606{
1607 struct tabla_priv *priv = data;
1608 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001609 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1610 pr_debug("%s: Button released\n", __func__);
1611 if (priv->button_jack)
1612 snd_soc_jack_report(priv->button_jack, 0,
1613 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614
Bradley Rubincb1e2732011-06-23 16:49:20 -07001615 priv->buttons_pressed &= ~SND_JACK_BTN_0;
1616 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1617 0x08);
1618 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620
1621 return IRQ_HANDLED;
1622}
1623
Bradley Rubincb1e2732011-06-23 16:49:20 -07001624static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1625{
1626 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1627 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1628 int micbias_mbhc_reg;
1629
1630 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1631 tabla_codec_enable_config_mode(codec, 1);
1632
1633 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1634 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
1635 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x0);
1636
1637 switch (calibration->bias) {
1638 case TABLA_MICBIAS1:
1639 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1640 break;
1641 case TABLA_MICBIAS2:
1642 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1643 break;
1644 case TABLA_MICBIAS3:
1645 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1646 break;
1647 case TABLA_MICBIAS4:
1648 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1649 break;
1650 default:
1651 pr_err("Error, invalid mic bias line\n");
1652 return;
1653 }
1654 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
1655 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1656 usleep_range(calibration->shutdown_plug_removal,
1657 calibration->shutdown_plug_removal);
1658
1659 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1660 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1661 tabla_codec_enable_config_mode(codec, 0);
1662
1663 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
1664}
1665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
1667{
1668 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001669
1670 tabla_codec_shutdown_hs_removal_detect(codec);
1671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 if (!tabla->ref_cnt) {
1673 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
1674 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1675 tabla_codec_enable_clock_block(codec, 0);
1676 }
1677
1678 tabla->mbhc_polling_active = false;
1679}
1680
Bradley Rubincb1e2732011-06-23 16:49:20 -07001681static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
1682{
1683 struct tabla_priv *priv = data;
1684 struct snd_soc_codec *codec = priv->codec;
1685 int microphone_present;
1686
1687 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1688
1689 usleep_range(priv->calibration->setup_plug_removal_delay,
1690 priv->calibration->setup_plug_removal_delay);
1691
1692 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
1693 if (priv->headset_jack) {
1694 pr_debug("%s: Reporting removal\n", __func__);
1695 snd_soc_jack_report(priv->headset_jack, 0,
1696 SND_JACK_HEADSET);
1697 }
1698 tabla_codec_shutdown_hs_removal_detect(codec);
1699 tabla_codec_enable_hs_detect(codec, 1);
1700 return IRQ_HANDLED;
1701 }
1702
1703 microphone_present = tabla_codec_setup_hs_polling(codec);
1704
1705 if (microphone_present == 0) {
1706 if (priv->headset_jack) {
1707 pr_debug("%s: Reporting insertion %d\n", __func__,
1708 SND_JACK_HEADPHONE);
1709 snd_soc_jack_report(priv->headset_jack,
1710 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
1711 }
1712 tabla_codec_shutdown_hs_polling(codec);
1713 tabla_codec_enable_hs_detect(codec, 0);
1714 } else if (microphone_present == 1) {
1715 if (priv->headset_jack) {
1716 pr_debug("%s: Reporting insertion %d\n", __func__,
1717 SND_JACK_HEADSET);
1718 snd_soc_jack_report(priv->headset_jack,
1719 SND_JACK_HEADSET, SND_JACK_HEADSET);
1720 }
1721 tabla_codec_start_hs_polling(codec);
1722 }
1723
1724 return IRQ_HANDLED;
1725}
1726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
1728{
1729 struct tabla_priv *priv = data;
1730 struct snd_soc_codec *codec = priv->codec;
1731
1732 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1733 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1734
1735 usleep_range(priv->calibration->shutdown_plug_removal,
1736 priv->calibration->shutdown_plug_removal);
1737
Bradley Rubincb1e2732011-06-23 16:49:20 -07001738 if (priv->headset_jack) {
1739 pr_debug("%s: Reporting removal\n", __func__);
1740 snd_soc_jack_report(priv->headset_jack, 0, SND_JACK_HEADSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 }
1742 tabla_codec_shutdown_hs_polling(codec);
1743
1744 tabla_codec_enable_hs_detect(codec, 1);
1745
1746 return IRQ_HANDLED;
1747}
1748
1749static unsigned long slimbus_value;
1750
1751static irqreturn_t tabla_slimbus_irq(int irq, void *data)
1752{
1753 struct tabla_priv *priv = data;
1754 struct snd_soc_codec *codec = priv->codec;
1755 int i, j;
1756 u8 val;
1757
1758 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
1759 slimbus_value = tabla_interface_reg_read(codec->control_data,
1760 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
1761 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
1762 val = tabla_interface_reg_read(codec->control_data,
1763 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
1764 if (val & 0x1)
1765 pr_err_ratelimited("overflow error on port %x,"
1766 " value %x\n", i*8 + j, val);
1767 if (val & 0x2)
1768 pr_err_ratelimited("underflow error on port %x,"
1769 " value %x\n", i*8 + j, val);
1770 }
1771 tabla_interface_reg_write(codec->control_data,
1772 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
1773 }
1774
1775 return IRQ_HANDLED;
1776}
1777
1778static int tabla_codec_probe(struct snd_soc_codec *codec)
1779{
1780 struct tabla *control;
1781 struct tabla_priv *tabla;
1782 struct snd_soc_dapm_context *dapm = &codec->dapm;
1783 int ret = 0;
1784 int i;
1785 int tx_channel;
1786
1787 codec->control_data = dev_get_drvdata(codec->dev->parent);
1788 control = codec->control_data;
1789
1790 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
1791 if (!tabla) {
1792 dev_err(codec->dev, "Failed to allocate private data\n");
1793 return -ENOMEM;
1794 }
1795
1796 snd_soc_codec_set_drvdata(codec, tabla);
1797
1798 tabla->ref_cnt = 0;
1799 tabla->bandgap_type = TABLA_BANDGAP_OFF;
1800 tabla->clock_active = false;
1801 tabla->config_mode_active = false;
1802 tabla->mbhc_polling_active = false;
1803 tabla->codec = codec;
1804
1805 /* TODO only enable bandgap when necessary in order to save power */
1806 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1807 tabla_codec_enable_clock_block(codec, 0);
1808
1809 /* Initialize gain registers to use register gain */
1810 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
1811 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
1812 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
1813 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
1814
1815 /* Initialize mic biases to differential mode */
1816 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
1817 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
1818 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
1819 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
1820
1821 /* Set headset CFILT to fast mode */
1822 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_CTL, 0x00, 0x00);
1823 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_CTL, 0x00, 0x00);
1824 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_CTL, 0x00, 0x00);
1825
1826 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
1827
1828 /* Use 16 bit sample size for now */
1829 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
1830 snd_soc_update_bits(codec,
1831 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
1832 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07001833 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834
1835 }
1836 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
1837 snd_soc_update_bits(codec,
1838 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
1839 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07001840 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841 }
1842 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
1843 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
1844
1845 snd_soc_add_controls(codec, tabla_snd_controls,
1846 ARRAY_SIZE(tabla_snd_controls));
1847 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
1848 ARRAY_SIZE(tabla_dapm_widgets));
1849 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
1850 snd_soc_dapm_sync(dapm);
1851
1852 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
1853 tabla_hs_insert_irq, "Headset insert detect", tabla);
1854 if (ret) {
1855 pr_err("%s: Failed to request irq %d\n", __func__,
1856 TABLA_IRQ_MBHC_INSERTION);
1857 goto err_insert_irq;
1858 }
1859 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1860
1861 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
1862 tabla_hs_remove_irq, "Headset remove detect", tabla);
1863 if (ret) {
1864 pr_err("%s: Failed to request irq %d\n", __func__,
1865 TABLA_IRQ_MBHC_REMOVAL);
1866 goto err_remove_irq;
1867 }
1868 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1869
1870 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001871 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 if (ret) {
1873 pr_err("%s: Failed to request irq %d\n", __func__,
1874 TABLA_IRQ_MBHC_POTENTIAL);
1875 goto err_potential_irq;
1876 }
1877 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1878
Bradley Rubincb1e2732011-06-23 16:49:20 -07001879 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
1880 tabla_release_handler, "Button Release detect", tabla);
1881 if (ret) {
1882 pr_err("%s: Failed to request irq %d\n", __func__,
1883 TABLA_IRQ_MBHC_RELEASE);
1884 goto err_release_irq;
1885 }
1886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
1888 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
1889 if (ret) {
1890 pr_err("%s: Failed to request irq %d\n", __func__,
1891 TABLA_IRQ_SLIMBUS);
1892 goto err_slimbus_irq;
1893 }
1894
1895 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
1896 tabla_interface_reg_write(codec->control_data,
1897 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
1898
1899 return ret;
1900
1901err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07001902 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
1903err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
1905err_potential_irq:
1906 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
1907err_remove_irq:
1908 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
1909err_insert_irq:
1910 kfree(tabla);
1911 return ret;
1912}
1913static int tabla_codec_remove(struct snd_soc_codec *codec)
1914{
1915 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1916 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001917 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
1919 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
1920 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
1921 tabla_codec_disable_clock_block(codec);
1922 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
1923 kfree(tabla);
1924 return 0;
1925}
1926static struct snd_soc_codec_driver soc_codec_dev_tabla = {
1927 .probe = tabla_codec_probe,
1928 .remove = tabla_codec_remove,
1929 .read = tabla_read,
1930 .write = tabla_write,
1931
1932 .readable_register = tabla_readable,
1933 .volatile_register = tabla_volatile,
1934
1935 .reg_cache_size = TABLA_CACHE_SIZE,
1936 .reg_cache_default = tabla_reg_defaults,
1937 .reg_word_size = 1,
1938};
1939static int __devinit tabla_probe(struct platform_device *pdev)
1940{
1941 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
1942 tabla_dai, ARRAY_SIZE(tabla_dai));
1943}
1944static int __devexit tabla_remove(struct platform_device *pdev)
1945{
1946 snd_soc_unregister_codec(&pdev->dev);
1947 return 0;
1948}
1949static struct platform_driver tabla_codec_driver = {
1950 .probe = tabla_probe,
1951 .remove = tabla_remove,
1952 .driver = {
1953 .name = "tabla_codec",
1954 .owner = THIS_MODULE,
1955 },
1956};
1957
1958static int __init tabla_codec_init(void)
1959{
1960 return platform_driver_register(&tabla_codec_driver);
1961}
1962
1963static void __exit tabla_codec_exit(void)
1964{
1965 platform_driver_unregister(&tabla_codec_driver);
1966}
1967
1968module_init(tabla_codec_init);
1969module_exit(tabla_codec_exit);
1970
1971MODULE_DESCRIPTION("Tabla codec driver");
1972MODULE_VERSION("1.0");
1973MODULE_LICENSE("GPL v2");