blob: ca63532561399ed313d3c2a251e1bb25c53ebcda [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>
Patrick Lai3043fba2011-08-01 14:15:57 -070021#include <linux/mfd/wcd9310/pdata.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <sound/jack.h>
23#include <sound/soc.h>
24#include <sound/soc-dapm.h>
25#include <sound/tlv.h>
26#include <linux/bitops.h>
27#include <linux/delay.h>
28#include "wcd9310.h"
29
30static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
31static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
32static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
33
34enum tabla_bandgap_type {
35 TABLA_BANDGAP_OFF = 0,
36 TABLA_BANDGAP_AUDIO_MODE,
37 TABLA_BANDGAP_MBHC_MODE,
38};
39
Bradley Rubin229c6a52011-07-12 16:18:48 -070040struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041 struct snd_soc_codec *codec;
42 u32 ref_cnt;
43 u32 adc_count;
Bradley Rubin229c6a52011-07-12 16:18:48 -070044 u32 rx_count;
Patrick Lai3043fba2011-08-01 14:15:57 -070045 u32 cfilt1_cnt;
46 u32 cfilt2_cnt;
47 u32 cfilt3_cnt;
48
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049 enum tabla_bandgap_type bandgap_type;
50 bool clock_active;
51 bool config_mode_active;
52 bool mbhc_polling_active;
Bradley Rubincb1e2732011-06-23 16:49:20 -070053 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054
55 struct tabla_mbhc_calibration *calibration;
56
Bradley Rubincb1e2732011-06-23 16:49:20 -070057 struct snd_soc_jack *headset_jack;
58 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -070059
Patrick Lai3043fba2011-08-01 14:15:57 -070060 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -070061 u32 anc_slot;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062};
63
64static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
65 struct snd_kcontrol *kcontrol, int event)
66{
67 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068
69 pr_debug("%s %d\n", __func__, event);
70 switch (event) {
71 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072 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);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 break;
89 }
90 return 0;
91}
92
Bradley Rubina7096d02011-08-03 18:29:02 -070093static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
94 struct snd_ctl_elem_value *ucontrol)
95{
96 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
97 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
98 ucontrol->value.integer.value[0] = tabla->anc_slot;
99 return 0;
100}
101
102static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
103 struct snd_ctl_elem_value *ucontrol)
104{
105 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
106 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
107 tabla->anc_slot = ucontrol->value.integer.value[0];
108 return 0;
109}
110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111static const struct snd_kcontrol_new tabla_snd_controls[] = {
112 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
113 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700114 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
115 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
117 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700118 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
119 line_gain),
120
121 SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
122 SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
123 SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
124 SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
125 SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
126 SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
129 line_gain),
130 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
131 line_gain),
132
Bradley Rubin410383f2011-07-22 13:44:23 -0700133 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
134 -84, 40, digital_gain),
135 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
136 -84, 40, digital_gain),
137 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
138 -84, 40, digital_gain),
139 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
140 -84, 40, digital_gain),
141 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
142 -84, 40, digital_gain),
143 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
144 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145
Bradley Rubin410383f2011-07-22 13:44:23 -0700146 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700148 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700150 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
151 digital_gain),
152 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
153 digital_gain),
154 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
155 digital_gain),
156 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
157 digital_gain),
158 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
159 digital_gain),
160 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
161 digital_gain),
162 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
163 digital_gain),
164 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
165 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700167 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
168 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700169 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
170 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700171 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
172 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173
174 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700175 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
176 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700177
178 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
179 tabla_put_anc_slot),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180};
181
182static const char *rx_mix1_text[] = {
183 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
184 "RX5", "RX6", "RX7"
185};
186
187static const char *sb_tx1_mux_text[] = {
188 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
189 "DEC1"
190};
191
192static const char *sb_tx5_mux_text[] = {
193 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
194 "DEC5"
195};
196
197static const char *sb_tx6_mux_text[] = {
198 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
199 "DEC6"
200};
201
202static const char const *sb_tx7_to_tx10_mux_text[] = {
203 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
204 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
205 "DEC9", "DEC10"
206};
207
208static const char *dec1_mux_text[] = {
209 "ZERO", "DMIC1", "ADC6",
210};
211
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700212static const char *dec2_mux_text[] = {
213 "ZERO", "DMIC2", "ADC5",
214};
215
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700216static const char *dec3_mux_text[] = {
217 "ZERO", "DMIC3", "ADC4",
218};
219
220static const char *dec4_mux_text[] = {
221 "ZERO", "DMIC4", "ADC3",
222};
223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224static const char *dec5_mux_text[] = {
225 "ZERO", "DMIC5", "ADC2",
226};
227
228static const char *dec6_mux_text[] = {
229 "ZERO", "DMIC6", "ADC1",
230};
231
232static const char const *dec7_mux_text[] = {
233 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
234};
235
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700236static const char *dec8_mux_text[] = {
237 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
238};
239
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700240static const char *dec9_mux_text[] = {
241 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
242};
243
244static const char *dec10_mux_text[] = {
245 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
246};
247
Bradley Rubin229c6a52011-07-12 16:18:48 -0700248static const char const *anc_mux_text[] = {
249 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
250 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
251};
252
253static const char const *anc1_fb_mux_text[] = {
254 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
255};
256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257static const char *iir1_inp1_text[] = {
258 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
259 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
260};
261
262static const struct soc_enum rx_mix1_inp1_chain_enum =
263 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
264
Bradley Rubin229c6a52011-07-12 16:18:48 -0700265static const struct soc_enum rx_mix1_inp2_chain_enum =
266 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268static const struct soc_enum rx2_mix1_inp1_chain_enum =
269 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
270
Bradley Rubin229c6a52011-07-12 16:18:48 -0700271static const struct soc_enum rx2_mix1_inp2_chain_enum =
272 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274static const struct soc_enum rx3_mix1_inp1_chain_enum =
275 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
276
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700277static const struct soc_enum rx3_mix1_inp2_chain_enum =
278 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280static const struct soc_enum rx4_mix1_inp1_chain_enum =
281 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
282
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700283static const struct soc_enum rx4_mix1_inp2_chain_enum =
284 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286static const struct soc_enum rx5_mix1_inp1_chain_enum =
287 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
288
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700289static const struct soc_enum rx5_mix1_inp2_chain_enum =
290 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
291
292static const struct soc_enum rx6_mix1_inp1_chain_enum =
293 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
294
295static const struct soc_enum rx6_mix1_inp2_chain_enum =
296 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298static const struct soc_enum sb_tx5_mux_enum =
299 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
300
301static const struct soc_enum sb_tx6_mux_enum =
302 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
303
304static const struct soc_enum sb_tx7_mux_enum =
305 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
306 sb_tx7_to_tx10_mux_text);
307
308static const struct soc_enum sb_tx8_mux_enum =
309 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
310 sb_tx7_to_tx10_mux_text);
311
312static const struct soc_enum sb_tx1_mux_enum =
313 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
314
315static const struct soc_enum dec1_mux_enum =
316 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
317
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700318static const struct soc_enum dec2_mux_enum =
319 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
320
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700321static const struct soc_enum dec3_mux_enum =
322 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
323
324static const struct soc_enum dec4_mux_enum =
325 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327static const struct soc_enum dec5_mux_enum =
328 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
329
330static const struct soc_enum dec6_mux_enum =
331 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
332
333static const struct soc_enum dec7_mux_enum =
334 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
335
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700336static const struct soc_enum dec8_mux_enum =
337 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
338
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700339static const struct soc_enum dec9_mux_enum =
340 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
341
342static const struct soc_enum dec10_mux_enum =
343 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
344
Bradley Rubin229c6a52011-07-12 16:18:48 -0700345static const struct soc_enum anc1_mux_enum =
346 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
347
348static const struct soc_enum anc2_mux_enum =
349 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
350
351static const struct soc_enum anc1_fb_mux_enum =
352 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static const struct soc_enum iir1_inp1_mux_enum =
355 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
356
357static const struct snd_kcontrol_new rx_mix1_inp1_mux =
358 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
359
Bradley Rubin229c6a52011-07-12 16:18:48 -0700360static const struct snd_kcontrol_new rx_mix1_inp2_mux =
361 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
364 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
365
Bradley Rubin229c6a52011-07-12 16:18:48 -0700366static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
367 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
370 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
371
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700372static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
373 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
374
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
376 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
377
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700378static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
379 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
382 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
383
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700384static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
385 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
386
387static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
388 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
389
390static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
391 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393static const struct snd_kcontrol_new sb_tx5_mux =
394 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
395
396static const struct snd_kcontrol_new sb_tx6_mux =
397 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
398
399static const struct snd_kcontrol_new sb_tx7_mux =
400 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
401
402static const struct snd_kcontrol_new sb_tx8_mux =
403 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
404
405static const struct snd_kcontrol_new sb_tx1_mux =
406 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
407
408static const struct snd_kcontrol_new dec1_mux =
409 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
410
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700411static const struct snd_kcontrol_new dec2_mux =
412 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
413
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700414static const struct snd_kcontrol_new dec3_mux =
415 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
416
417static const struct snd_kcontrol_new dec4_mux =
418 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420static const struct snd_kcontrol_new dec5_mux =
421 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
422
423static const struct snd_kcontrol_new dec6_mux =
424 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
425
426static const struct snd_kcontrol_new dec7_mux =
427 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
428
Bradley Rubin229c6a52011-07-12 16:18:48 -0700429static const struct snd_kcontrol_new anc1_mux =
430 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700431static const struct snd_kcontrol_new dec8_mux =
432 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
433
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700434static const struct snd_kcontrol_new dec9_mux =
435 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
436
437static const struct snd_kcontrol_new dec10_mux =
438 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440static const struct snd_kcontrol_new iir1_inp1_mux =
441 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
442
Bradley Rubin229c6a52011-07-12 16:18:48 -0700443static const struct snd_kcontrol_new anc2_mux =
444 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445
Bradley Rubin229c6a52011-07-12 16:18:48 -0700446static const struct snd_kcontrol_new anc1_fb_mux =
447 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448
Bradley Rubin229c6a52011-07-12 16:18:48 -0700449static const struct snd_kcontrol_new dac1_switch[] = {
450 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
451};
452static const struct snd_kcontrol_new hphl_switch[] = {
453 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
454};
455static const struct snd_kcontrol_new hphr_switch[] = {
456 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
457};
458static const struct snd_kcontrol_new lineout1_switch[] = {
459 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
460};
461static const struct snd_kcontrol_new lineout2_switch[] = {
462 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
463};
464static const struct snd_kcontrol_new lineout3_switch[] = {
465 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
466};
467static const struct snd_kcontrol_new lineout4_switch[] = {
468 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
469};
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
472 int enable)
473{
474 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
475
476 pr_debug("%s %d\n", __func__, enable);
477
478 if (enable) {
479 tabla->adc_count++;
480 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
481 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
482 } else {
483 tabla->adc_count--;
484 if (!tabla->adc_count) {
485 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
486 0x2, 0x0);
487 if (!tabla->mbhc_polling_active)
488 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
489 0xE0, 0x0);
490 }
491 }
492}
493
494static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
495 struct snd_kcontrol *kcontrol, int event)
496{
497 struct snd_soc_codec *codec = w->codec;
498 u16 adc_reg;
499
500 pr_debug("%s %d\n", __func__, event);
501
502 if (w->reg == TABLA_A_TX_1_2_EN)
503 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
504 else if (w->reg == TABLA_A_TX_3_4_EN)
505 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
506 else if (w->reg == TABLA_A_TX_5_6_EN)
507 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
508 else {
509 pr_err("%s: Error, invalid adc register\n", __func__);
510 return -EINVAL;
511 }
512
513 switch (event) {
514 case SND_SOC_DAPM_PRE_PMU:
515 tabla_codec_enable_adc_block(codec, 1);
516 break;
517 case SND_SOC_DAPM_POST_PMU:
518 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
519 1 << w->shift);
520 usleep_range(1000, 1000);
521 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
522 usleep_range(1000, 1000);
523 break;
524 case SND_SOC_DAPM_POST_PMD:
525 tabla_codec_enable_adc_block(codec, 0);
526 break;
527 }
528 return 0;
529}
530
531static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
532 struct snd_kcontrol *kcontrol, int event)
533{
534 struct snd_soc_codec *codec = w->codec;
535
536 pr_debug("%s %d\n", __func__, event);
537 switch (event) {
538 case SND_SOC_DAPM_PRE_PMU:
539 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
540 break;
541 case SND_SOC_DAPM_POST_PMD:
542 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
543 break;
544 }
545 return 0;
546}
547
548static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
549 struct snd_kcontrol *kcontrol, int event)
550{
551 struct snd_soc_codec *codec = w->codec;
552 u16 lineout_gain_reg;
553
554 pr_debug("%s %d\n", __func__, event);
555
556 switch (w->shift) {
557 case 0:
558 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
559 break;
560 case 1:
561 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
562 break;
563 case 2:
564 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
565 break;
566 case 3:
567 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
568 break;
569 case 4:
570 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
571 break;
572 default:
573 pr_err("%s: Error, incorrect lineout register value\n",
574 __func__);
575 return -EINVAL;
576 }
577
578 switch (event) {
579 case SND_SOC_DAPM_PRE_PMU:
580 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
581 break;
582 case SND_SOC_DAPM_POST_PMU:
583 usleep_range(40000, 40000);
584 break;
585 case SND_SOC_DAPM_POST_PMD:
586 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
587 break;
588 }
589 return 0;
590}
591
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700592
593static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 struct snd_kcontrol *kcontrol, int event)
595{
596 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700597 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
598 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -0700599 unsigned int dmic;
600 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700601
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -0700602 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
603 if (ret < 0) {
604 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700605 return -EINVAL;
606 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -0700608 switch (dmic) {
609 case 1:
610 case 2:
611 dmic_clk_sel = 0x02;
612 dmic_clk_en = 0x01;
613 break;
614
615 case 3:
616 case 4:
617 dmic_clk_sel = 0x08;
618 dmic_clk_en = 0x04;
619 break;
620
621 case 5:
622 case 6:
623 dmic_clk_sel = 0x20;
624 dmic_clk_en = 0x10;
625 break;
626
627 default:
628 pr_err("%s: Invalid DMIC Selection\n", __func__);
629 return -EINVAL;
630 }
631
632 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
633 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 switch (event) {
638 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700639 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
640
641 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
642 dmic_clk_sel, dmic_clk_sel);
643
644 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
645
646 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
647 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648 break;
649 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700650 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
651 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 break;
653 }
654 return 0;
655}
656
Bradley Rubin229c6a52011-07-12 16:18:48 -0700657static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
658 struct snd_kcontrol *kcontrol, int event)
659{
660 struct snd_soc_codec *codec = w->codec;
661 const char *filename;
662 const struct firmware *fw;
663 int i;
664 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -0700665 int num_anc_slots;
666 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700667 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -0700668 u32 anc_writes_size = 0;
669 int anc_size_remaining;
670 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700671 u16 reg;
672 u8 mask, val, old_val;
673
674 pr_debug("%s %d\n", __func__, event);
675 switch (event) {
676 case SND_SOC_DAPM_PRE_PMU:
677
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700678 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -0700679
680 ret = request_firmware(&fw, filename, codec->dev);
681 if (ret != 0) {
682 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
683 ret);
684 return -ENODEV;
685 }
686
Bradley Rubina7096d02011-08-03 18:29:02 -0700687 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -0700688 dev_err(codec->dev, "Not enough data\n");
689 release_firmware(fw);
690 return -ENOMEM;
691 }
692
693 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -0700694 anc_head = (struct anc_header *)(fw->data);
695 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
696 anc_size_remaining = fw->size - sizeof(struct anc_header);
697 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700698
Bradley Rubina7096d02011-08-03 18:29:02 -0700699 if (tabla->anc_slot >= num_anc_slots) {
700 dev_err(codec->dev, "Invalid ANC slot selected\n");
701 release_firmware(fw);
702 return -EINVAL;
703 }
704
705 for (i = 0; i < num_anc_slots; i++) {
706
707 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
708 dev_err(codec->dev, "Invalid register format\n");
709 release_firmware(fw);
710 return -EINVAL;
711 }
712 anc_writes_size = (u32)(*anc_ptr);
713 anc_size_remaining -= sizeof(u32);
714 anc_ptr += 1;
715
716 if (anc_writes_size * TABLA_PACKED_REG_SIZE
717 > anc_size_remaining) {
718 dev_err(codec->dev, "Invalid register format\n");
719 release_firmware(fw);
720 return -ENOMEM;
721 }
722
723 if (tabla->anc_slot == i)
724 break;
725
726 anc_size_remaining -= (anc_writes_size *
727 TABLA_PACKED_REG_SIZE);
728 anc_ptr += (anc_writes_size *
729 TABLA_PACKED_REG_SIZE);
730 }
731 if (i == num_anc_slots) {
732 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -0700733 release_firmware(fw);
734 return -ENOMEM;
735 }
736
Bradley Rubina7096d02011-08-03 18:29:02 -0700737 for (i = 0; i < anc_writes_size; i++) {
738 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -0700739 mask, val);
740 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700741 snd_soc_write(codec, reg, (old_val & ~mask) |
742 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -0700743 }
744 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700745
746 break;
747 case SND_SOC_DAPM_POST_PMD:
748 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
749 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
750 break;
751 }
752 return 0;
753}
754
Patrick Lai3043fba2011-08-01 14:15:57 -0700755static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
756 u8 cfilt_sel, int inc)
757{
758 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
759 u32 *cfilt_cnt_ptr = NULL;
760 u16 micb_cfilt_reg;
761
762 switch (cfilt_sel) {
763 case TABLA_CFILT1_SEL:
764 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
765 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
766 break;
767 case TABLA_CFILT2_SEL:
768 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
769 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
770 break;
771 case TABLA_CFILT3_SEL:
772 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
773 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
774 break;
775 default:
776 return; /* should not happen */
777 }
778
779 if (inc) {
780 if (!(*cfilt_cnt_ptr)++)
781 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
782 } else {
783 /* check if count not zero, decrement
784 * then check if zero, go ahead disable cfilter
785 */
786 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr))
787 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
788 }
789}
Bradley Rubin229c6a52011-07-12 16:18:48 -0700790
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700791static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
792{
793 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
794 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
795 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
796 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
797 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
798 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
799 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
800}
801
802static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
803{
804 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
805 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
806 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
807 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
808}
809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
811 struct snd_kcontrol *kcontrol, int event)
812{
813 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -0700814 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
815 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700816 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700817 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700818 char *internal1_text = "Internal1";
819 char *internal2_text = "Internal2";
820 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821
822 pr_debug("%s %d\n", __func__, event);
823 switch (w->reg) {
824 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700826 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700827 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828 break;
829 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700831 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700832 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833 break;
834 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700836 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700837 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700838 break;
839 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700840 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700841 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700842 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843 break;
844 default:
845 pr_err("%s: Error, invalid micbias register\n", __func__);
846 return -EINVAL;
847 }
848
849 switch (event) {
850 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700851 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -0700852 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700853
854 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700856 else if (strnstr(w->name, internal2_text, 30))
857 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
858 else if (strnstr(w->name, internal3_text, 30))
859 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700862 case SND_SOC_DAPM_POST_PMU:
863 if (tabla->mbhc_polling_active &&
864 (tabla->calibration->bias == micb_line)) {
865 tabla_codec_pause_hs_polling(codec);
866 tabla_codec_start_hs_polling(codec);
867 }
868 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700870 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700872 else if (strnstr(w->name, internal2_text, 30))
873 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
874 else if (strnstr(w->name, internal3_text, 30))
875 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
876
Patrick Lai3043fba2011-08-01 14:15:57 -0700877 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 break;
879 }
880
881 return 0;
882}
883
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
885 struct snd_kcontrol *kcontrol, int event)
886{
887 struct snd_soc_codec *codec = w->codec;
888 u16 dec_reset_reg;
889
890 pr_debug("%s %d\n", __func__, event);
891
892 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
893 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
894 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
895 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
896 else {
897 pr_err("%s: Error, incorrect dec\n", __func__);
898 return -EINVAL;
899 }
900
901 switch (event) {
902 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
904 1 << w->shift);
905 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
906 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 }
908 return 0;
909}
910
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700911static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 struct snd_kcontrol *kcontrol, int event)
913{
914 struct snd_soc_codec *codec = w->codec;
915
916 switch (event) {
917 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700918 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
919 1 << w->shift, 1 << w->shift);
920 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
921 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922 break;
923 }
924 return 0;
925}
926
Bradley Rubin229c6a52011-07-12 16:18:48 -0700927static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
928 struct snd_kcontrol *kcontrol, int event)
929{
930 switch (event) {
931 case SND_SOC_DAPM_POST_PMU:
932 case SND_SOC_DAPM_POST_PMD:
933 usleep_range(1000, 1000);
934 break;
935 }
936 return 0;
937}
938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
940 /*RX stuff */
941 SND_SOC_DAPM_OUTPUT("EAR"),
942
943 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
944 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
945 SND_SOC_DAPM_PRE_PMD),
946
947 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
948
Bradley Rubin229c6a52011-07-12 16:18:48 -0700949 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
950 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951
Bradley Rubin229c6a52011-07-12 16:18:48 -0700952 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
953 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954
955 /* Headphone */
956 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
957 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700958 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
959 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960
961 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700962 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
963 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964
965 /* Speaker */
966 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
969 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
970 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700971 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
972 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
973 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
975 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
976 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700977 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
978 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
979 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
980
Bradley Rubin229c6a52011-07-12 16:18:48 -0700981 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
982 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
983 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
984 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
985 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
986 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
987 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
988 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700989
Bradley Rubin229c6a52011-07-12 16:18:48 -0700990 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
991 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
992 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
993 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
994 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
995 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
996 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
997 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
998 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
999 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1000 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1001 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001002
Bradley Rubin229c6a52011-07-12 16:18:48 -07001003 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1004 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1005
1006 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1007 &rx_mix1_inp1_mux),
1008 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1009 &rx_mix1_inp2_mux),
1010 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1011 &rx2_mix1_inp1_mux),
1012 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1013 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001014 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1015 &rx3_mix1_inp1_mux),
1016 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1017 &rx3_mix1_inp2_mux),
1018 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1019 &rx4_mix1_inp1_mux),
1020 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1021 &rx4_mix1_inp2_mux),
1022 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1023 &rx5_mix1_inp1_mux),
1024 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1025 &rx5_mix1_inp2_mux),
1026 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1027 &rx6_mix1_inp1_mux),
1028 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1029 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030
Bradley Rubin229c6a52011-07-12 16:18:48 -07001031 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
1032 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1033 SND_SOC_DAPM_PRE_PMD),
1034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001036
Bradley Rubine1d08622011-07-20 18:01:35 -07001037 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1038 0),
1039
Bradley Rubin229c6a52011-07-12 16:18:48 -07001040 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
1041 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 SND_SOC_DAPM_INPUT("AMIC1"),
1044 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
1045 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001046 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001047 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
1048 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001049 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001050 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001052 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
1054 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1055 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1056
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001057 SND_SOC_DAPM_INPUT("AMIC3"),
1058 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
1059 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1060 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1061
1062 SND_SOC_DAPM_INPUT("AMIC4"),
1063 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1064 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1065 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1066
1067 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1068 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001069 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001070
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001071 SND_SOC_DAPM_INPUT("AMIC5"),
1072 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
1073 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1074
1075 SND_SOC_DAPM_INPUT("AMIC6"),
1076 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
1077 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001080 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001082 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001083 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001084
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001085 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001086 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001087
1088 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001089 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001092 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093
1094 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001095 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096
1097 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001098 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001100 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001101 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001102
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001103 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001104 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001105
1106 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001107 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001108
Bradley Rubin229c6a52011-07-12 16:18:48 -07001109 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1110 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1111
1112 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1113 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1114 SND_SOC_DAPM_POST_PMD),
1115
1116 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 SND_SOC_DAPM_INPUT("AMIC2"),
1119 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
1120 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001121 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001122 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
1123 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001124 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001125 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
1126 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001127 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001128 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001130 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
1132 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001133 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001134 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
1135 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001136 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001137 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001139 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1141 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1142 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1143
1144 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1145 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1146 0, 0),
1147
1148 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1149 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1150 4, 0),
1151
1152 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1153 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1154 5, 0),
1155
1156 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1157 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1158 0, 0),
1159
1160 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1161 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1162 0, 0),
1163
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001164 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001165 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
1166 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1167 SND_SOC_DAPM_POST_PMD),
1168
1169 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
1170 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1171 SND_SOC_DAPM_POST_PMD),
1172
1173 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
1174 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1175 SND_SOC_DAPM_POST_PMD),
1176
1177 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
1178 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1179 SND_SOC_DAPM_POST_PMD),
1180
1181 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
1182 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1183 SND_SOC_DAPM_POST_PMD),
1184
1185 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
1186 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1187 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188
1189 /* Sidetone */
1190 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1191 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1192};
1193
1194static const struct snd_soc_dapm_route audio_map[] = {
1195 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196
1197 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1198 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1199
1200 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1201 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1202
1203 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1204 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1205
1206 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1207 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001208 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001209 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1210 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1212 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001213 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1214 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001215 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1216 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217
1218 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001219 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1220 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1221 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1223 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1224
1225 /* Earpiece (RX MIX1) */
1226 {"EAR", NULL, "EAR PA"},
1227 {"EAR PA", NULL, "EAR PA Input"},
1228 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001229 {"DAC1", NULL, "CP"},
1230
1231 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1232 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1233 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234
1235 /* Headset (RX MIX1 and RX MIX2) */
1236 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001238
1239 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001241
1242 {"HPHL DAC", NULL, "CP"},
1243 {"HPHR DAC", NULL, "CP"},
1244
1245 {"ANC", NULL, "ANC1 MUX"},
1246 {"ANC", NULL, "ANC2 MUX"},
1247 {"ANC1 MUX", "ADC1", "ADC1"},
1248 {"ANC1 MUX", "ADC2", "ADC2"},
1249 {"ANC1 MUX", "ADC3", "ADC3"},
1250 {"ANC1 MUX", "ADC4", "ADC4"},
1251 {"ANC2 MUX", "ADC1", "ADC1"},
1252 {"ANC2 MUX", "ADC2", "ADC2"},
1253 {"ANC2 MUX", "ADC3", "ADC3"},
1254 {"ANC2 MUX", "ADC4", "ADC4"},
1255
Bradley Rubine1d08622011-07-20 18:01:35 -07001256 {"ANC", NULL, "CDC_CONN"},
1257
Bradley Rubin229c6a52011-07-12 16:18:48 -07001258 {"DAC1", "Switch", "RX1 CHAIN"},
1259 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1260 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001263 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001265 {"LINEOUT", NULL, "LINEOUT4"},
1266
1267 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1268 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001270 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
1271
Bradley Rubin229c6a52011-07-12 16:18:48 -07001272 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1273 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1274 {"RX1 CHAIN", NULL, "ANC"},
1275 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001276 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1277 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
Kiran Kandied246a92011-08-12 14:03:44 -07001278 {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
1279 {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001280
Bradley Rubin229c6a52011-07-12 16:18:48 -07001281 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1282 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1283 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1284 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001285 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1286 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1287 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1288 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1289 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1290 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1291 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1292 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
1293
Bradley Rubin229c6a52011-07-12 16:18:48 -07001294 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1295 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1296 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1297 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1298 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1299 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1300 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1301 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1302 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1303 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1304 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1305 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1306 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1307 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1308 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1309 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1310 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1311 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1312 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1313 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1314 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1315 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1316 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1317 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1318 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1319 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001321 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001322 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001323 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001324 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001325 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001326 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001327 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001328 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001329 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001330 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001331 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001332 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001333 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001334 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001336 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001337 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001339 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001340 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001341 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001342 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001343 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001344 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001345 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001346 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001347 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001348 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001349
1350 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351 {"ADC1", NULL, "AMIC1"},
1352 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001353 {"ADC3", NULL, "AMIC3"},
1354 {"ADC4", NULL, "AMIC4"},
1355 {"ADC5", NULL, "AMIC5"},
1356 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 {"IIR1", NULL, "IIR1 INP1 MUX"},
1359 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001360
1361 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1362 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1363 {"MIC BIAS1 External", NULL, "LDO_H"},
1364 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1365 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1366 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1367 {"MIC BIAS2 External", NULL, "LDO_H"},
1368 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1369 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1370 {"MIC BIAS3 External", NULL, "LDO_H"},
1371 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372};
1373
1374static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1375{
1376 return tabla_reg_readable[reg];
1377}
1378
1379static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1380{
1381 /* Registers lower than 0x100 are top level registers which can be
1382 * written by the Tabla core driver.
1383 */
1384
1385 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1386 return 1;
1387
1388 return 0;
1389}
1390
1391#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1392static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1393 unsigned int value)
1394{
1395 int ret;
1396 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1397
1398 BUG_ON(reg > TABLA_MAX_REGISTER);
1399
1400 if (!tabla_volatile(codec, reg)) {
1401 pr_debug("writing to cache\n");
1402 ret = snd_soc_cache_write(codec, reg, value);
1403 if (ret != 0)
1404 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1405 reg, ret);
1406 }
1407
1408 return tabla_reg_write(codec->control_data, reg, value);
1409}
1410static unsigned int tabla_read(struct snd_soc_codec *codec,
1411 unsigned int reg)
1412{
1413 unsigned int val;
1414 int ret;
1415
1416 BUG_ON(reg > TABLA_MAX_REGISTER);
1417
1418 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1419 reg < codec->driver->reg_cache_size) {
1420 pr_debug("reading from cache\n");
1421 ret = snd_soc_cache_read(codec, reg, &val);
1422 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001423 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 return val;
1425 } else
1426 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1427 reg, ret);
1428 }
1429
1430 val = tabla_reg_read(codec->control_data, reg);
1431 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1432 return val;
1433}
1434
1435static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1436{
1437 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1438 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1439 0x80);
1440 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1441 0x04);
1442 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1443 0x01);
1444 usleep_range(1000, 1000);
1445 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1446 0x00);
1447}
1448
1449static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1450 enum tabla_bandgap_type choice)
1451{
1452 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1453
1454 /* TODO lock resources accessed by audio streams and threaded
1455 * interrupt handlers
1456 */
1457
1458 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1459 tabla->bandgap_type);
1460
1461 if (tabla->bandgap_type == choice)
1462 return;
1463
1464 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1465 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1466 tabla_codec_enable_audio_mode_bandgap(codec);
1467 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1468 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1469 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1470 0x2);
1471 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1472 0x80);
1473 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1474 0x4);
1475 usleep_range(1000, 1000);
1476 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1477 0x00);
1478 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1479 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1480 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1481 usleep_range(100, 100);
1482 tabla_codec_enable_audio_mode_bandgap(codec);
1483 } else if (choice == TABLA_BANDGAP_OFF) {
1484 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1485 } else {
1486 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1487 }
1488 tabla->bandgap_type = choice;
1489}
1490
1491static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1492 int enable)
1493{
1494 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1495
1496 if (enable) {
1497 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1498 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1499 usleep_range(5, 5);
1500 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1501 0x80);
1502 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1503 0x80);
1504 usleep_range(10, 10);
1505 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1506 usleep_range(20, 20);
1507 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1508 } else {
1509 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1510 0);
1511 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1512 }
1513 tabla->config_mode_active = enable ? true : false;
1514
1515 return 0;
1516}
1517
1518static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1519 int config_mode)
1520{
1521 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1522
1523 pr_debug("%s\n", __func__);
1524
1525 if (config_mode) {
1526 tabla_codec_enable_config_mode(codec, 1);
1527 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1528 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1529 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1530 usleep_range(1000, 1000);
1531 } else
1532 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1533
1534 if (!config_mode && tabla->mbhc_polling_active) {
1535 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1536 tabla_codec_enable_config_mode(codec, 0);
1537
1538 }
1539
1540 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1541 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1542 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1543 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1544 usleep_range(50, 50);
1545 tabla->clock_active = true;
1546 return 0;
1547}
1548static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1549{
1550 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1551 pr_debug("%s\n", __func__);
1552 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1553 ndelay(160);
1554 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1555 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1556 tabla->clock_active = false;
1557}
1558
Bradley Rubincb1e2732011-06-23 16:49:20 -07001559static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1560{
1561 /* TODO store register values in calibration */
1562
1563 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1564 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1565
1566 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1567 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1568 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1569 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1570
1571 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1572 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1573 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1574 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1575 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1576 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1577}
1578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579static int tabla_startup(struct snd_pcm_substream *substream,
1580 struct snd_soc_dai *dai)
1581{
1582 struct snd_soc_codec *codec = dai->codec;
1583 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1584 int ret = 0;
1585
1586 pr_debug("%s()\n", __func__);
1587
1588 if (!codec) {
1589 pr_err("Error, no codec found\n");
1590 return -EINVAL;
1591 }
1592 tabla->ref_cnt++;
1593
Patrick Lai3043fba2011-08-01 14:15:57 -07001594 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001595 tabla->rx_count++;
1596 if (tabla->rx_count == 1)
1597 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1598 0x80);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 }
1600
1601 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001602 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1604 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001605 tabla_codec_calibrate_hs_polling(codec);
1606 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 }
1608
1609 return ret;
1610}
1611
1612static void tabla_shutdown(struct snd_pcm_substream *substream,
1613 struct snd_soc_dai *dai)
1614{
1615 struct snd_soc_codec *codec = dai->codec;
1616 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1617
1618 pr_debug("%s()\n", __func__);
1619
1620 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1621 /* Disable LDO */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001622 } else {
1623 tabla->rx_count--;
1624 if (!tabla->rx_count)
1625 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1626 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 }
1628
1629 if (!tabla->ref_cnt) {
1630 pr_err("Error, trying to shutdown codec when already down\n");
1631 return;
1632 }
1633 tabla->ref_cnt--;
1634
1635 if (tabla->mbhc_polling_active) {
1636 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001637 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 tabla_codec_enable_bandgap(codec,
1639 TABLA_BANDGAP_MBHC_MODE);
1640 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1641 0x80);
1642 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001643 tabla_codec_calibrate_hs_polling(codec);
1644 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001645 }
1646 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1647 }
1648}
1649
1650static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1651{
1652 struct snd_soc_codec *codec = codec_dai->codec;
1653
1654 pr_debug("%s %d\n", __func__, mute);
1655
1656 /* TODO mute TX */
1657 if (mute)
1658 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1659 else
1660 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1661
1662 return 0;
1663}
1664
1665static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1666 int clk_id, unsigned int freq, int dir)
1667{
1668 pr_debug("%s\n", __func__);
1669 return 0;
1670}
1671
1672static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1673{
1674 pr_debug("%s\n", __func__);
1675 return 0;
1676}
1677
1678static int tabla_hw_params(struct snd_pcm_substream *substream,
1679 struct snd_pcm_hw_params *params,
1680 struct snd_soc_dai *dai)
1681{
1682 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1683 return 0;
1684}
1685
1686static struct snd_soc_dai_ops tabla_dai_ops = {
1687 .startup = tabla_startup,
1688 .shutdown = tabla_shutdown,
1689 .hw_params = tabla_hw_params,
1690 .set_sysclk = tabla_set_dai_sysclk,
1691 .set_fmt = tabla_set_dai_fmt,
1692 .digital_mute = tabla_digital_mute,
1693};
1694
1695static struct snd_soc_dai_driver tabla_dai[] = {
1696 {
1697 .name = "tabla_rx1",
1698 .id = 1,
1699 .playback = {
1700 .stream_name = "AIF1 Playback",
1701 .rates = SNDRV_PCM_RATE_8000_48000,
1702 .formats = TABLA_FORMATS,
1703 .rate_max = 48000,
1704 .rate_min = 8000,
1705 .channels_min = 1,
1706 .channels_max = 2,
1707 },
1708 .ops = &tabla_dai_ops,
1709 },
1710 {
1711 .name = "tabla_tx1",
1712 .id = 2,
1713 .capture = {
1714 .stream_name = "AIF1 Capture",
1715 .rates = SNDRV_PCM_RATE_8000_48000,
1716 .formats = TABLA_FORMATS,
1717 .rate_max = 48000,
1718 .rate_min = 8000,
1719 .channels_min = 1,
1720 .channels_max = 2,
1721 },
1722 .ops = &tabla_dai_ops,
1723 },
1724};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001725static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07001726{
1727 u8 bias_msb, bias_lsb;
1728 short bias_value;
1729
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001730 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1731 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1732 bias_value = (bias_msb << 8) | bias_lsb;
1733 return bias_value;
1734}
1735
1736static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
1737{
1738 u8 bias_msb, bias_lsb;
1739 short bias_value;
1740
1741 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1742 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1743 bias_value = (bias_msb << 8) | bias_lsb;
1744 return bias_value;
1745}
1746
1747static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1748 int dce)
1749{
1750 short bias_value;
1751
Bradley Rubincb1e2732011-06-23 16:49:20 -07001752 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001753 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1754 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1755 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1756 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1757 usleep_range(60000, 60000);
1758 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001759 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001760 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001761 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1762 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001763 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001764 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001765 usleep_range(50, 50);
1766 bias_value = tabla_codec_read_sta_result(codec);
1767 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1768 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001769 }
1770
Bradley Rubincb1e2732011-06-23 16:49:20 -07001771 pr_debug("read microphone bias value %x\n", bias_value);
1772 return bias_value;
1773}
1774
1775static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776{
1777 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1778 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Patrick Lai3043fba2011-08-01 14:15:57 -07001779 int micbias_ctl_reg, micbias_cfilt_ctl_reg,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001780 micbias_mbhc_reg;
1781 short bias_value, threshold_no_mic;
Patrick Lai3043fba2011-08-01 14:15:57 -07001782 unsigned int cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783
1784 if (!calibration) {
1785 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001786 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 }
1788
1789 tabla->mbhc_polling_active = true;
1790
1791 if (!tabla->ref_cnt) {
1792 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1793 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1794 tabla_codec_enable_clock_block(codec, 1);
1795 }
1796
1797 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1800
Patrick Lai3043fba2011-08-01 14:15:57 -07001801 /* select cfilt separately from the micbias line in the platform data */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 switch (calibration->bias) {
1803 case TABLA_MICBIAS1:
1804 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001805 cfilt_sel = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001806 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 break;
1808 case TABLA_MICBIAS2:
1809 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001810 cfilt_sel = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001811 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 break;
1813 case TABLA_MICBIAS3:
1814 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001815 cfilt_sel = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001816 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 break;
1818 case TABLA_MICBIAS4:
1819 pr_err("%s: Error, microphone bias 4 not supported\n",
1820 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001821 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 default:
1823 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001824 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 }
Patrick Lai3043fba2011-08-01 14:15:57 -07001826
1827 switch (cfilt_sel) {
1828 case TABLA_CFILT1_SEL:
1829 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1830 break;
1831 case TABLA_CFILT2_SEL:
1832 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1833 break;
1834 case TABLA_CFILT3_SEL:
1835 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1836 break;
1837 default: /* default should not happen as check should have been done */
1838 return -EINVAL;
1839 }
1840
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001841 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842
Bradley Rubincb1e2732011-06-23 16:49:20 -07001843 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844
1845 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001846 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847
1848 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1849 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1850 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1851
1852 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001853 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1854 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855
Bradley Rubincb1e2732011-06-23 16:49:20 -07001856 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1858
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001859 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001860 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1861
1862 tabla_codec_calibrate_hs_polling(codec);
1863
1864 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001865 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1866 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001867 threshold_no_mic = 0xF7F6;
1868
1869 if (bias_value < threshold_no_mic) {
1870 pr_debug("headphone detected, micbias %x\n", bias_value);
1871 return 0;
1872 } else {
1873 pr_debug("headset detected, micbias %x\n", bias_value);
1874 return 1;
1875 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876}
1877
1878static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1879 int insertion)
1880{
1881 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1882 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1883 int central_bias_enabled = 0;
1884 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1885
1886 if (!calibration) {
1887 pr_err("Error, no tabla calibration\n");
1888 return -EINVAL;
1889 }
1890
1891 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1892
1893 if (insertion)
1894 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1895 else
1896 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1897
1898 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1899 if (!(tabla->clock_active)) {
1900 tabla_codec_enable_config_mode(codec, 1);
1901 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001902 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 usleep_range(calibration->shutdown_plug_removal,
1904 calibration->shutdown_plug_removal);
1905 tabla_codec_enable_config_mode(codec, 0);
1906 } else
1907 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001908 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 }
1910
1911 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1912 calibration->hph_current << 2);
1913
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001914 /* Turn off HPH PAs during insertion detection to avoid false
1915 * insertion interrupts
1916 */
1917 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1919
1920 switch (calibration->bias) {
1921 case TABLA_MICBIAS1:
1922 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1923 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1924 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1925 break;
1926 case TABLA_MICBIAS2:
1927 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1928 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1929 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1930 break;
1931 case TABLA_MICBIAS3:
1932 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1933 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1934 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1935 break;
1936 case TABLA_MICBIAS4:
1937 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1938 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1939 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1940 break;
1941 default:
1942 pr_err("Error, invalid mic bias line\n");
1943 return -EINVAL;
1944 }
1945 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1946 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1947
1948 /* If central bandgap disabled */
1949 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1950 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1951 usleep_range(calibration->bg_fast_settle,
1952 calibration->bg_fast_settle);
1953 central_bias_enabled = 1;
1954 }
1955
1956 /* If LDO_H disabled */
1957 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1958 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1959 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1960 usleep_range(calibration->tldoh, calibration->tldoh);
1961 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1962
1963 if (central_bias_enabled)
1964 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1965 }
1966 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1967 calibration->mic_current << 5);
1968 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1969 usleep_range(calibration->mic_pid, calibration->mic_pid);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1972
1973 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1974
1975 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1976 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1977 return 0;
1978}
1979
Bradley Rubincb1e2732011-06-23 16:49:20 -07001980int tabla_hs_detect(struct snd_soc_codec *codec,
1981 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 struct tabla_mbhc_calibration *calibration)
1983{
1984 struct tabla_priv *tabla;
1985 if (!codec || !calibration) {
1986 pr_err("Error: no codec or calibration\n");
1987 return -EINVAL;
1988 }
1989 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001990 tabla->headset_jack = headset_jack;
1991 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992 tabla->calibration = calibration;
1993
1994 return tabla_codec_enable_hs_detect(codec, 1);
1995}
1996EXPORT_SYMBOL_GPL(tabla_hs_detect);
1997
Bradley Rubin688c66a2011-08-16 12:25:13 -07001998#define TABLA_BUTTON_MARGIN_ERROR 4
Bradley Rubincb1e2732011-06-23 16:49:20 -07001999static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000{
2001 struct tabla_priv *priv = data;
2002 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin688c66a2011-08-16 12:25:13 -07002003 short bias_value, bias_value2;
Bradley Rubincb1e2732011-06-23 16:49:20 -07002004
2005 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2006 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2007
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002008 bias_value = tabla_codec_read_dce_result(codec);
2009 pr_debug("button press interrupt, bias value is %d\n", bias_value);
2010
Bradley Rubin688c66a2011-08-16 12:25:13 -07002011 /* Do another DCE to make sure button voltage is the same */
2012 bias_value2 = tabla_codec_measure_micbias_voltage(codec, 1);
2013 pr_debug("button press part 2, bias value is %d\n", bias_value2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002014
Bradley Rubin688c66a2011-08-16 12:25:13 -07002015 if (abs(bias_value - bias_value2) < TABLA_BUTTON_MARGIN_ERROR) {
2016 if (priv->button_jack)
2017 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
2018 SND_JACK_BTN_0);
2019
2020 priv->buttons_pressed |= SND_JACK_BTN_0;
2021 }
2022 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x09);
2023 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 return IRQ_HANDLED;
2026}
2027
Bradley Rubincb1e2732011-06-23 16:49:20 -07002028static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029{
2030 struct tabla_priv *priv = data;
2031 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002032 pr_debug("%s\n", __func__);
2033 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002034 if (priv->buttons_pressed & SND_JACK_BTN_0) {
2035 pr_debug("%s: Button released\n", __func__);
2036 if (priv->button_jack)
2037 snd_soc_jack_report(priv->button_jack, 0,
2038 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039
Bradley Rubincb1e2732011-06-23 16:49:20 -07002040 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002042
Bradley Rubin688c66a2011-08-16 12:25:13 -07002043 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
2044 tabla_codec_start_hs_polling(codec);
2045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 return IRQ_HANDLED;
2047}
2048
Bradley Rubincb1e2732011-06-23 16:49:20 -07002049static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
2050{
2051 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2052 struct tabla_mbhc_calibration *calibration = tabla->calibration;
2053 int micbias_mbhc_reg;
2054
2055 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2056 tabla_codec_enable_config_mode(codec, 1);
2057
2058 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2059 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002060
2061 switch (calibration->bias) {
2062 case TABLA_MICBIAS1:
2063 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
2064 break;
2065 case TABLA_MICBIAS2:
2066 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
2067 break;
2068 case TABLA_MICBIAS3:
2069 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
2070 break;
2071 case TABLA_MICBIAS4:
2072 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
2073 break;
2074 default:
2075 pr_err("Error, invalid mic bias line\n");
2076 return;
2077 }
2078 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002079 usleep_range(calibration->shutdown_plug_removal,
2080 calibration->shutdown_plug_removal);
2081
2082 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
2083 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2084 tabla_codec_enable_config_mode(codec, 0);
2085
2086 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
2087}
2088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
2090{
2091 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002092
2093 tabla_codec_shutdown_hs_removal_detect(codec);
2094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 if (!tabla->ref_cnt) {
2096 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
2097 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2098 tabla_codec_enable_clock_block(codec, 0);
2099 }
2100
2101 tabla->mbhc_polling_active = false;
2102}
2103
Bradley Rubincb1e2732011-06-23 16:49:20 -07002104static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
2105{
2106 struct tabla_priv *priv = data;
2107 struct snd_soc_codec *codec = priv->codec;
2108 int microphone_present;
2109
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002110 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002111 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2112
2113 usleep_range(priv->calibration->setup_plug_removal_delay,
2114 priv->calibration->setup_plug_removal_delay);
2115
2116 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
2117 if (priv->headset_jack) {
2118 pr_debug("%s: Reporting removal\n", __func__);
2119 snd_soc_jack_report(priv->headset_jack, 0,
2120 SND_JACK_HEADSET);
2121 }
2122 tabla_codec_shutdown_hs_removal_detect(codec);
2123 tabla_codec_enable_hs_detect(codec, 1);
2124 return IRQ_HANDLED;
2125 }
2126
2127 microphone_present = tabla_codec_setup_hs_polling(codec);
2128
2129 if (microphone_present == 0) {
2130 if (priv->headset_jack) {
2131 pr_debug("%s: Reporting insertion %d\n", __func__,
2132 SND_JACK_HEADPHONE);
2133 snd_soc_jack_report(priv->headset_jack,
2134 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
2135 }
2136 tabla_codec_shutdown_hs_polling(codec);
2137 tabla_codec_enable_hs_detect(codec, 0);
2138 } else if (microphone_present == 1) {
2139 if (priv->headset_jack) {
2140 pr_debug("%s: Reporting insertion %d\n", __func__,
2141 SND_JACK_HEADSET);
2142 snd_soc_jack_report(priv->headset_jack,
2143 SND_JACK_HEADSET, SND_JACK_HEADSET);
2144 }
2145 tabla_codec_start_hs_polling(codec);
2146 }
2147
2148 return IRQ_HANDLED;
2149}
2150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
2152{
2153 struct tabla_priv *priv = data;
2154 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002155 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156
2157 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2158 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002159 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160
2161 usleep_range(priv->calibration->shutdown_plug_removal,
2162 priv->calibration->shutdown_plug_removal);
2163
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002164 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
2165 pr_debug("removal interrupt, bias value is %d\n", bias_value);
2166
2167 if (bias_value < -90) {
2168 pr_debug("False alarm, headset not actually removed\n");
2169 tabla_codec_start_hs_polling(codec);
2170 } else {
2171 if (priv->headset_jack) {
2172 pr_debug("%s: Reporting removal\n", __func__);
2173 snd_soc_jack_report(priv->headset_jack, 0,
2174 SND_JACK_HEADSET);
2175 }
2176 tabla_codec_shutdown_hs_polling(codec);
2177
2178 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 return IRQ_HANDLED;
2181}
2182
2183static unsigned long slimbus_value;
2184
2185static irqreturn_t tabla_slimbus_irq(int irq, void *data)
2186{
2187 struct tabla_priv *priv = data;
2188 struct snd_soc_codec *codec = priv->codec;
2189 int i, j;
2190 u8 val;
2191
2192 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
2193 slimbus_value = tabla_interface_reg_read(codec->control_data,
2194 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
2195 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
2196 val = tabla_interface_reg_read(codec->control_data,
2197 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
2198 if (val & 0x1)
2199 pr_err_ratelimited("overflow error on port %x,"
2200 " value %x\n", i*8 + j, val);
2201 if (val & 0x2)
2202 pr_err_ratelimited("underflow error on port %x,"
2203 " value %x\n", i*8 + j, val);
2204 }
2205 tabla_interface_reg_write(codec->control_data,
2206 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2207 }
2208
2209 return IRQ_HANDLED;
2210}
2211
Patrick Lai3043fba2011-08-01 14:15:57 -07002212static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2213{
2214 int rc = -EINVAL;
2215 unsigned min_mv, max_mv;
2216
2217 switch (ldoh_v) {
2218 case TABLA_LDOH_1P95_V:
2219 min_mv = 160;
2220 max_mv = 1800;
2221 break;
2222 case TABLA_LDOH_2P35_V:
2223 min_mv = 200;
2224 max_mv = 2200;
2225 break;
2226 case TABLA_LDOH_2P75_V:
2227 min_mv = 240;
2228 max_mv = 2600;
2229 break;
2230 case TABLA_LDOH_2P85_V:
2231 min_mv = 250;
2232 max_mv = 2700;
2233 break;
2234 default:
2235 goto done;
2236 }
2237
2238 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2239 goto done;
2240
2241 for (rc = 4; rc <= 44; rc++) {
2242 min_mv = max_mv * (rc) / 44;
2243 if (min_mv >= cfilt_mv) {
2244 rc -= 4;
2245 break;
2246 }
2247 }
2248done:
2249 return rc;
2250}
2251
2252static int tabla_handle_pdata(struct tabla_priv *tabla)
2253{
2254 struct snd_soc_codec *codec = tabla->codec;
2255 struct tabla_pdata *pdata = tabla->pdata;
2256 int k1, k2, k3, rc = 0;
2257
2258 if (!pdata) {
2259 rc = -ENODEV;
2260 goto done;
2261 }
2262
2263 /* Make sure settings are correct */
2264 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
2265 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
2266 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
2267 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
2268 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
2269 rc = -EINVAL;
2270 goto done;
2271 }
2272
2273 /* figure out k value */
2274 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
2275 pdata->micbias.cfilt1_mv);
2276 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
2277 pdata->micbias.cfilt2_mv);
2278 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
2279 pdata->micbias.cfilt3_mv);
2280
2281 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
2282 rc = -EINVAL;
2283 goto done;
2284 }
2285
2286 /* Set voltage level and always use LDO */
2287 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
2288 (pdata->micbias.ldoh_v << 2));
2289
2290 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
2291 (k1 << 2));
2292 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
2293 (k2 << 2));
2294 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
2295 (k3 << 2));
2296
2297 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
2298 (pdata->micbias.bias1_cfilt_sel << 5));
2299 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
2300 (pdata->micbias.bias2_cfilt_sel << 5));
2301 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
2302 (pdata->micbias.bias3_cfilt_sel << 5));
2303 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
2304 (pdata->micbias.bias4_cfilt_sel << 5));
2305
2306done:
2307 return rc;
2308}
2309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310static int tabla_codec_probe(struct snd_soc_codec *codec)
2311{
2312 struct tabla *control;
2313 struct tabla_priv *tabla;
2314 struct snd_soc_dapm_context *dapm = &codec->dapm;
2315 int ret = 0;
2316 int i;
2317 int tx_channel;
2318
2319 codec->control_data = dev_get_drvdata(codec->dev->parent);
2320 control = codec->control_data;
2321
2322 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2323 if (!tabla) {
2324 dev_err(codec->dev, "Failed to allocate private data\n");
2325 return -ENOMEM;
2326 }
2327
2328 snd_soc_codec_set_drvdata(codec, tabla);
2329
2330 tabla->ref_cnt = 0;
2331 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2332 tabla->clock_active = false;
2333 tabla->config_mode_active = false;
2334 tabla->mbhc_polling_active = false;
2335 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002336 tabla->pdata = dev_get_platdata(codec->dev->parent);
2337
2338 ret = tabla_handle_pdata(tabla);
2339
2340 if (IS_ERR_VALUE(ret)) {
2341 pr_err("%s: bad pdata\n", __func__);
2342 goto err_pdata;
2343 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344
2345 /* TODO only enable bandgap when necessary in order to save power */
2346 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2347 tabla_codec_enable_clock_block(codec, 0);
2348
2349 /* Initialize gain registers to use register gain */
2350 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
2351 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
2352 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002353 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002354 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002355 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002356
2357 /* Initialize mic biases to differential mode */
2358 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
2359 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
2360 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
2361 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
2362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
2364
2365 /* Use 16 bit sample size for now */
2366 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
2367 snd_soc_update_bits(codec,
2368 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
2369 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002370 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371
2372 }
2373 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
2374 snd_soc_update_bits(codec,
2375 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
2376 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002377 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378 }
2379 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
2380 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
2381
2382 snd_soc_add_controls(codec, tabla_snd_controls,
2383 ARRAY_SIZE(tabla_snd_controls));
2384 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2385 ARRAY_SIZE(tabla_dapm_widgets));
2386 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2387 snd_soc_dapm_sync(dapm);
2388
2389 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2390 tabla_hs_insert_irq, "Headset insert detect", tabla);
2391 if (ret) {
2392 pr_err("%s: Failed to request irq %d\n", __func__,
2393 TABLA_IRQ_MBHC_INSERTION);
2394 goto err_insert_irq;
2395 }
2396 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2397
2398 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2399 tabla_hs_remove_irq, "Headset remove detect", tabla);
2400 if (ret) {
2401 pr_err("%s: Failed to request irq %d\n", __func__,
2402 TABLA_IRQ_MBHC_REMOVAL);
2403 goto err_remove_irq;
2404 }
2405 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2406
2407 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002408 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 if (ret) {
2410 pr_err("%s: Failed to request irq %d\n", __func__,
2411 TABLA_IRQ_MBHC_POTENTIAL);
2412 goto err_potential_irq;
2413 }
2414 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2415
Bradley Rubincb1e2732011-06-23 16:49:20 -07002416 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2417 tabla_release_handler, "Button Release detect", tabla);
2418 if (ret) {
2419 pr_err("%s: Failed to request irq %d\n", __func__,
2420 TABLA_IRQ_MBHC_RELEASE);
2421 goto err_release_irq;
2422 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002423 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2426 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2427 if (ret) {
2428 pr_err("%s: Failed to request irq %d\n", __func__,
2429 TABLA_IRQ_SLIMBUS);
2430 goto err_slimbus_irq;
2431 }
2432
2433 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2434 tabla_interface_reg_write(codec->control_data,
2435 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2436
2437 return ret;
2438
2439err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002440 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2441err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2443err_potential_irq:
2444 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2445err_remove_irq:
2446 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2447err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07002448err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002449 kfree(tabla);
2450 return ret;
2451}
2452static int tabla_codec_remove(struct snd_soc_codec *codec)
2453{
2454 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2455 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002456 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2458 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2459 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2460 tabla_codec_disable_clock_block(codec);
2461 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2462 kfree(tabla);
2463 return 0;
2464}
2465static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2466 .probe = tabla_codec_probe,
2467 .remove = tabla_codec_remove,
2468 .read = tabla_read,
2469 .write = tabla_write,
2470
2471 .readable_register = tabla_readable,
2472 .volatile_register = tabla_volatile,
2473
2474 .reg_cache_size = TABLA_CACHE_SIZE,
2475 .reg_cache_default = tabla_reg_defaults,
2476 .reg_word_size = 1,
2477};
2478static int __devinit tabla_probe(struct platform_device *pdev)
2479{
2480 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2481 tabla_dai, ARRAY_SIZE(tabla_dai));
2482}
2483static int __devexit tabla_remove(struct platform_device *pdev)
2484{
2485 snd_soc_unregister_codec(&pdev->dev);
2486 return 0;
2487}
2488static struct platform_driver tabla_codec_driver = {
2489 .probe = tabla_probe,
2490 .remove = tabla_remove,
2491 .driver = {
2492 .name = "tabla_codec",
2493 .owner = THIS_MODULE,
2494 },
2495};
2496
2497static int __init tabla_codec_init(void)
2498{
2499 return platform_driver_register(&tabla_codec_driver);
2500}
2501
2502static void __exit tabla_codec_exit(void)
2503{
2504 platform_driver_unregister(&tabla_codec_driver);
2505}
2506
2507module_init(tabla_codec_init);
2508module_exit(tabla_codec_exit);
2509
2510MODULE_DESCRIPTION("Tabla codec driver");
2511MODULE_VERSION("1.0");
2512MODULE_LICENSE("GPL v2");