blob: a7227aea02e40d6da03c9101a41dc49dd49c2e6f [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;
599
600 if (!strncmp(w->name, "DMIC1", 5)) {
601
602 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL;
603 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL;
604 dmic_clk_sel = 0x2;
605 dmic_clk_en = 0x1;
606
607 } else if (!strncmp(w->name, "DMIC2", 5)) {
608
609 tx_mux_ctl_reg = TABLA_A_CDC_TX2_MUX_CTL;
610 tx_dmic_ctl_reg = TABLA_A_CDC_TX2_DMIC_CTL;
611 dmic_clk_sel = 0x2;
612 dmic_clk_en = 0x1;
613
614 } else if (!strncmp(w->name, "DMIC3", 5)) {
615
616 tx_mux_ctl_reg = TABLA_A_CDC_TX3_MUX_CTL;
617 tx_dmic_ctl_reg = TABLA_A_CDC_TX3_DMIC_CTL;
618 dmic_clk_sel = 0x8;
619 dmic_clk_en = 0x4;
620
621 } else {
622 pr_err("%s: Error, DMIC = %s\n", __func__, w->name);
623 return -EINVAL;
624 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625
626 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700627
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 switch (event) {
629 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700630 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
631
632 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
633 dmic_clk_sel, dmic_clk_sel);
634
635 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
636
637 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
638 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 break;
640 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700641 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
642 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643 break;
644 }
645 return 0;
646}
647
Bradley Rubin229c6a52011-07-12 16:18:48 -0700648static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
649 struct snd_kcontrol *kcontrol, int event)
650{
651 struct snd_soc_codec *codec = w->codec;
652 const char *filename;
653 const struct firmware *fw;
654 int i;
655 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -0700656 int num_anc_slots;
657 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700658 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -0700659 u32 anc_writes_size = 0;
660 int anc_size_remaining;
661 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700662 u16 reg;
663 u8 mask, val, old_val;
664
665 pr_debug("%s %d\n", __func__, event);
666 switch (event) {
667 case SND_SOC_DAPM_PRE_PMU:
668
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700669 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -0700670
671 ret = request_firmware(&fw, filename, codec->dev);
672 if (ret != 0) {
673 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
674 ret);
675 return -ENODEV;
676 }
677
Bradley Rubina7096d02011-08-03 18:29:02 -0700678 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -0700679 dev_err(codec->dev, "Not enough data\n");
680 release_firmware(fw);
681 return -ENOMEM;
682 }
683
684 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -0700685 anc_head = (struct anc_header *)(fw->data);
686 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
687 anc_size_remaining = fw->size - sizeof(struct anc_header);
688 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700689
Bradley Rubina7096d02011-08-03 18:29:02 -0700690 if (tabla->anc_slot >= num_anc_slots) {
691 dev_err(codec->dev, "Invalid ANC slot selected\n");
692 release_firmware(fw);
693 return -EINVAL;
694 }
695
696 for (i = 0; i < num_anc_slots; i++) {
697
698 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
699 dev_err(codec->dev, "Invalid register format\n");
700 release_firmware(fw);
701 return -EINVAL;
702 }
703 anc_writes_size = (u32)(*anc_ptr);
704 anc_size_remaining -= sizeof(u32);
705 anc_ptr += 1;
706
707 if (anc_writes_size * TABLA_PACKED_REG_SIZE
708 > anc_size_remaining) {
709 dev_err(codec->dev, "Invalid register format\n");
710 release_firmware(fw);
711 return -ENOMEM;
712 }
713
714 if (tabla->anc_slot == i)
715 break;
716
717 anc_size_remaining -= (anc_writes_size *
718 TABLA_PACKED_REG_SIZE);
719 anc_ptr += (anc_writes_size *
720 TABLA_PACKED_REG_SIZE);
721 }
722 if (i == num_anc_slots) {
723 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -0700724 release_firmware(fw);
725 return -ENOMEM;
726 }
727
Bradley Rubina7096d02011-08-03 18:29:02 -0700728 for (i = 0; i < anc_writes_size; i++) {
729 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -0700730 mask, val);
731 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700732 snd_soc_write(codec, reg, (old_val & ~mask) |
733 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -0700734 }
735 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700736
737 break;
738 case SND_SOC_DAPM_POST_PMD:
739 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
740 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
741 break;
742 }
743 return 0;
744}
745
Patrick Lai3043fba2011-08-01 14:15:57 -0700746static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
747 u8 cfilt_sel, int inc)
748{
749 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
750 u32 *cfilt_cnt_ptr = NULL;
751 u16 micb_cfilt_reg;
752
753 switch (cfilt_sel) {
754 case TABLA_CFILT1_SEL:
755 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
756 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
757 break;
758 case TABLA_CFILT2_SEL:
759 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
760 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
761 break;
762 case TABLA_CFILT3_SEL:
763 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
764 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
765 break;
766 default:
767 return; /* should not happen */
768 }
769
770 if (inc) {
771 if (!(*cfilt_cnt_ptr)++)
772 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
773 } else {
774 /* check if count not zero, decrement
775 * then check if zero, go ahead disable cfilter
776 */
777 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr))
778 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
779 }
780}
Bradley Rubin229c6a52011-07-12 16:18:48 -0700781
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700782static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
783{
784 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
785 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
786 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
787 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
788 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
789 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
790 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
791}
792
793static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
794{
795 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
796 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
797 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
798 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
799}
800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
802 struct snd_kcontrol *kcontrol, int event)
803{
804 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -0700805 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
806 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700807 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700808 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700809 char *internal1_text = "Internal1";
810 char *internal2_text = "Internal2";
811 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812
813 pr_debug("%s %d\n", __func__, event);
814 switch (w->reg) {
815 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700817 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700818 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819 break;
820 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700822 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700823 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 break;
825 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700827 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700828 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700829 break;
830 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700831 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700832 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700833 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834 break;
835 default:
836 pr_err("%s: Error, invalid micbias register\n", __func__);
837 return -EINVAL;
838 }
839
840 switch (event) {
841 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700842 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -0700843 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700844
845 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700847 else if (strnstr(w->name, internal2_text, 30))
848 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
849 else if (strnstr(w->name, internal3_text, 30))
850 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700853 case SND_SOC_DAPM_POST_PMU:
854 if (tabla->mbhc_polling_active &&
855 (tabla->calibration->bias == micb_line)) {
856 tabla_codec_pause_hs_polling(codec);
857 tabla_codec_start_hs_polling(codec);
858 }
859 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700861 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700863 else if (strnstr(w->name, internal2_text, 30))
864 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
865 else if (strnstr(w->name, internal3_text, 30))
866 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
867
Patrick Lai3043fba2011-08-01 14:15:57 -0700868 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869 break;
870 }
871
872 return 0;
873}
874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
876 struct snd_kcontrol *kcontrol, int event)
877{
878 struct snd_soc_codec *codec = w->codec;
879 u16 dec_reset_reg;
880
881 pr_debug("%s %d\n", __func__, event);
882
883 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
884 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
885 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
886 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
887 else {
888 pr_err("%s: Error, incorrect dec\n", __func__);
889 return -EINVAL;
890 }
891
892 switch (event) {
893 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
895 1 << w->shift);
896 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
897 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 }
899 return 0;
900}
901
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700902static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 struct snd_kcontrol *kcontrol, int event)
904{
905 struct snd_soc_codec *codec = w->codec;
906
907 switch (event) {
908 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700909 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
910 1 << w->shift, 1 << w->shift);
911 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
912 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 break;
914 }
915 return 0;
916}
917
Bradley Rubin229c6a52011-07-12 16:18:48 -0700918static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
919 struct snd_kcontrol *kcontrol, int event)
920{
921 switch (event) {
922 case SND_SOC_DAPM_POST_PMU:
923 case SND_SOC_DAPM_POST_PMD:
924 usleep_range(1000, 1000);
925 break;
926 }
927 return 0;
928}
929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
931 /*RX stuff */
932 SND_SOC_DAPM_OUTPUT("EAR"),
933
934 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
935 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
936 SND_SOC_DAPM_PRE_PMD),
937
938 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
939
Bradley Rubin229c6a52011-07-12 16:18:48 -0700940 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
941 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942
Bradley Rubin229c6a52011-07-12 16:18:48 -0700943 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
944 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945
946 /* Headphone */
947 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
948 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700949 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
950 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951
952 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700953 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
954 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955
956 /* Speaker */
957 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
960 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
961 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700962 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
963 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
964 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
966 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
967 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700968 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
969 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
970 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
971
Bradley Rubin229c6a52011-07-12 16:18:48 -0700972 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
973 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
974 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
975 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
976 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
977 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
978 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
979 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700980
Bradley Rubin229c6a52011-07-12 16:18:48 -0700981 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
982 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
983 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
984 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
985 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
986 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
987 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
988 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
989 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
990 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
991 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
992 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700993
Bradley Rubin229c6a52011-07-12 16:18:48 -0700994 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
995 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
996
997 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
998 &rx_mix1_inp1_mux),
999 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1000 &rx_mix1_inp2_mux),
1001 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1002 &rx2_mix1_inp1_mux),
1003 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1004 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001005 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1006 &rx3_mix1_inp1_mux),
1007 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1008 &rx3_mix1_inp2_mux),
1009 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1010 &rx4_mix1_inp1_mux),
1011 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1012 &rx4_mix1_inp2_mux),
1013 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1014 &rx5_mix1_inp1_mux),
1015 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1016 &rx5_mix1_inp2_mux),
1017 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1018 &rx6_mix1_inp1_mux),
1019 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1020 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021
Bradley Rubin229c6a52011-07-12 16:18:48 -07001022 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
1023 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1024 SND_SOC_DAPM_PRE_PMD),
1025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001027
Bradley Rubine1d08622011-07-20 18:01:35 -07001028 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1029 0),
1030
Bradley Rubin229c6a52011-07-12 16:18:48 -07001031 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
1032 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 SND_SOC_DAPM_INPUT("AMIC1"),
1035 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
1036 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001037 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001038 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
1039 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001040 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001041 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001043 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
1045 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1046 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1047
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001048 SND_SOC_DAPM_INPUT("AMIC3"),
1049 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
1050 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1051 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1052
1053 SND_SOC_DAPM_INPUT("AMIC4"),
1054 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1055 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1056 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1057
1058 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1059 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001060 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001061
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001062 SND_SOC_DAPM_INPUT("AMIC5"),
1063 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
1064 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1065
1066 SND_SOC_DAPM_INPUT("AMIC6"),
1067 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
1068 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1069
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 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 -07001071 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001073 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 -07001074 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001075
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001076 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 -07001077 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001078
1079 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 -07001080 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 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 -07001083 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084
1085 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 -07001086 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087
1088 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 -07001089 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001091 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 -07001092 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001093
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001094 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 -07001095 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001096
1097 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 -07001098 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001099
Bradley Rubin229c6a52011-07-12 16:18:48 -07001100 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1101 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1102
1103 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1104 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1105 SND_SOC_DAPM_POST_PMD),
1106
1107 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 SND_SOC_DAPM_INPUT("AMIC2"),
1110 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
1111 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001112 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001113 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
1114 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001115 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001116 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
1117 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001118 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001119 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 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),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_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 BIAS3 Internal1", TABLA_A_MICB_3_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 BIAS3 Internal2", TABLA_A_MICB_3_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_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1132 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1133 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1134
1135 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1136 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1137 0, 0),
1138
1139 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1140 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1141 4, 0),
1142
1143 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1144 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1145 5, 0),
1146
1147 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1148 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1149 0, 0),
1150
1151 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1152 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1153 0, 0),
1154
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001155 /* Digital Mic Inputs */
1156 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic),
1157 SND_SOC_DAPM_MIC("DMIC2", &tabla_codec_enable_dmic),
1158 SND_SOC_DAPM_MIC("DMIC3", &tabla_codec_enable_dmic),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159
1160 /* Sidetone */
1161 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1162 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1163};
1164
1165static const struct snd_soc_dapm_route audio_map[] = {
1166 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167
1168 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1169 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1170
1171 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1172 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1173
1174 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1175 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1176
1177 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1178 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001179 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001180 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1181 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1183 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001184 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1185 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001186 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1187 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188
1189 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001190 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1191 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1192 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1194 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1195
1196 /* Earpiece (RX MIX1) */
1197 {"EAR", NULL, "EAR PA"},
1198 {"EAR PA", NULL, "EAR PA Input"},
1199 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001200 {"DAC1", NULL, "CP"},
1201
1202 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1203 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1204 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205
1206 /* Headset (RX MIX1 and RX MIX2) */
1207 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001209
1210 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001212
1213 {"HPHL DAC", NULL, "CP"},
1214 {"HPHR DAC", NULL, "CP"},
1215
1216 {"ANC", NULL, "ANC1 MUX"},
1217 {"ANC", NULL, "ANC2 MUX"},
1218 {"ANC1 MUX", "ADC1", "ADC1"},
1219 {"ANC1 MUX", "ADC2", "ADC2"},
1220 {"ANC1 MUX", "ADC3", "ADC3"},
1221 {"ANC1 MUX", "ADC4", "ADC4"},
1222 {"ANC2 MUX", "ADC1", "ADC1"},
1223 {"ANC2 MUX", "ADC2", "ADC2"},
1224 {"ANC2 MUX", "ADC3", "ADC3"},
1225 {"ANC2 MUX", "ADC4", "ADC4"},
1226
Bradley Rubine1d08622011-07-20 18:01:35 -07001227 {"ANC", NULL, "CDC_CONN"},
1228
Bradley Rubin229c6a52011-07-12 16:18:48 -07001229 {"DAC1", "Switch", "RX1 CHAIN"},
1230 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1231 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001234 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001236 {"LINEOUT", NULL, "LINEOUT4"},
1237
1238 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1239 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001241 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
1242
Bradley Rubin229c6a52011-07-12 16:18:48 -07001243 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1244 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1245 {"RX1 CHAIN", NULL, "ANC"},
1246 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001247 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1248 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
Kiran Kandied246a92011-08-12 14:03:44 -07001249 {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
1250 {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001251
Bradley Rubin229c6a52011-07-12 16:18:48 -07001252 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1253 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1254 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1255 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001256 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1257 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1258 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1259 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1260 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1261 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1262 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1263 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
1264
Bradley Rubin229c6a52011-07-12 16:18:48 -07001265 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1266 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1267 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1268 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1269 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1270 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1271 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1272 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1273 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1274 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1275 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1276 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1277 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1278 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1279 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1280 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1281 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1282 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1283 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1284 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1285 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1286 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1287 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1288 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1289 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1290 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001292 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001293 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001294 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001295 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001296 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001297 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001298 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001299 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001300 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001301 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001302 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001303 {"DEC4 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001305 {"DEC5 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001307 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001308 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001309 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001310 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001311 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001312 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001313 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001314 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001315 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001316 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001317
1318 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 {"ADC1", NULL, "AMIC1"},
1320 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001321 {"ADC3", NULL, "AMIC3"},
1322 {"ADC4", NULL, "AMIC4"},
1323 {"ADC5", NULL, "AMIC5"},
1324 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 {"IIR1", NULL, "IIR1 INP1 MUX"},
1327 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001328
1329 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1330 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1331 {"MIC BIAS1 External", NULL, "LDO_H"},
1332 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1333 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1334 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1335 {"MIC BIAS2 External", NULL, "LDO_H"},
1336 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1337 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1338 {"MIC BIAS3 External", NULL, "LDO_H"},
1339 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340};
1341
1342static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1343{
1344 return tabla_reg_readable[reg];
1345}
1346
1347static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1348{
1349 /* Registers lower than 0x100 are top level registers which can be
1350 * written by the Tabla core driver.
1351 */
1352
1353 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1354 return 1;
1355
1356 return 0;
1357}
1358
1359#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1360static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1361 unsigned int value)
1362{
1363 int ret;
1364 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1365
1366 BUG_ON(reg > TABLA_MAX_REGISTER);
1367
1368 if (!tabla_volatile(codec, reg)) {
1369 pr_debug("writing to cache\n");
1370 ret = snd_soc_cache_write(codec, reg, value);
1371 if (ret != 0)
1372 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1373 reg, ret);
1374 }
1375
1376 return tabla_reg_write(codec->control_data, reg, value);
1377}
1378static unsigned int tabla_read(struct snd_soc_codec *codec,
1379 unsigned int reg)
1380{
1381 unsigned int val;
1382 int ret;
1383
1384 BUG_ON(reg > TABLA_MAX_REGISTER);
1385
1386 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1387 reg < codec->driver->reg_cache_size) {
1388 pr_debug("reading from cache\n");
1389 ret = snd_soc_cache_read(codec, reg, &val);
1390 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001391 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 return val;
1393 } else
1394 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1395 reg, ret);
1396 }
1397
1398 val = tabla_reg_read(codec->control_data, reg);
1399 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1400 return val;
1401}
1402
1403static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1404{
1405 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1406 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1407 0x80);
1408 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1409 0x04);
1410 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1411 0x01);
1412 usleep_range(1000, 1000);
1413 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1414 0x00);
1415}
1416
1417static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1418 enum tabla_bandgap_type choice)
1419{
1420 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1421
1422 /* TODO lock resources accessed by audio streams and threaded
1423 * interrupt handlers
1424 */
1425
1426 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1427 tabla->bandgap_type);
1428
1429 if (tabla->bandgap_type == choice)
1430 return;
1431
1432 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1433 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1434 tabla_codec_enable_audio_mode_bandgap(codec);
1435 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1436 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1437 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1438 0x2);
1439 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1440 0x80);
1441 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1442 0x4);
1443 usleep_range(1000, 1000);
1444 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1445 0x00);
1446 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1447 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1448 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1449 usleep_range(100, 100);
1450 tabla_codec_enable_audio_mode_bandgap(codec);
1451 } else if (choice == TABLA_BANDGAP_OFF) {
1452 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1453 } else {
1454 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1455 }
1456 tabla->bandgap_type = choice;
1457}
1458
1459static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1460 int enable)
1461{
1462 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1463
1464 if (enable) {
1465 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1466 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1467 usleep_range(5, 5);
1468 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1469 0x80);
1470 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1471 0x80);
1472 usleep_range(10, 10);
1473 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1474 usleep_range(20, 20);
1475 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1476 } else {
1477 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1478 0);
1479 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1480 }
1481 tabla->config_mode_active = enable ? true : false;
1482
1483 return 0;
1484}
1485
1486static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1487 int config_mode)
1488{
1489 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1490
1491 pr_debug("%s\n", __func__);
1492
1493 if (config_mode) {
1494 tabla_codec_enable_config_mode(codec, 1);
1495 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1496 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1497 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1498 usleep_range(1000, 1000);
1499 } else
1500 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1501
1502 if (!config_mode && tabla->mbhc_polling_active) {
1503 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1504 tabla_codec_enable_config_mode(codec, 0);
1505
1506 }
1507
1508 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1509 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1510 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1511 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1512 usleep_range(50, 50);
1513 tabla->clock_active = true;
1514 return 0;
1515}
1516static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1517{
1518 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1519 pr_debug("%s\n", __func__);
1520 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1521 ndelay(160);
1522 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1523 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1524 tabla->clock_active = false;
1525}
1526
Bradley Rubincb1e2732011-06-23 16:49:20 -07001527static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1528{
1529 /* TODO store register values in calibration */
1530
1531 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1532 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1533
1534 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1535 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1536 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1537 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1538
1539 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1540 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1541 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1542 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1543 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1544 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1545}
1546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547static int tabla_startup(struct snd_pcm_substream *substream,
1548 struct snd_soc_dai *dai)
1549{
1550 struct snd_soc_codec *codec = dai->codec;
1551 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1552 int ret = 0;
1553
1554 pr_debug("%s()\n", __func__);
1555
1556 if (!codec) {
1557 pr_err("Error, no codec found\n");
1558 return -EINVAL;
1559 }
1560 tabla->ref_cnt++;
1561
Patrick Lai3043fba2011-08-01 14:15:57 -07001562 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001563 tabla->rx_count++;
1564 if (tabla->rx_count == 1)
1565 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1566 0x80);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 }
1568
1569 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001570 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1572 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001573 tabla_codec_calibrate_hs_polling(codec);
1574 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 }
1576
1577 return ret;
1578}
1579
1580static void tabla_shutdown(struct snd_pcm_substream *substream,
1581 struct snd_soc_dai *dai)
1582{
1583 struct snd_soc_codec *codec = dai->codec;
1584 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1585
1586 pr_debug("%s()\n", __func__);
1587
1588 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1589 /* Disable LDO */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001590 } else {
1591 tabla->rx_count--;
1592 if (!tabla->rx_count)
1593 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1594 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 }
1596
1597 if (!tabla->ref_cnt) {
1598 pr_err("Error, trying to shutdown codec when already down\n");
1599 return;
1600 }
1601 tabla->ref_cnt--;
1602
1603 if (tabla->mbhc_polling_active) {
1604 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001605 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 tabla_codec_enable_bandgap(codec,
1607 TABLA_BANDGAP_MBHC_MODE);
1608 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1609 0x80);
1610 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001611 tabla_codec_calibrate_hs_polling(codec);
1612 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 }
1614 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1615 }
1616}
1617
1618static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1619{
1620 struct snd_soc_codec *codec = codec_dai->codec;
1621
1622 pr_debug("%s %d\n", __func__, mute);
1623
1624 /* TODO mute TX */
1625 if (mute)
1626 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1627 else
1628 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1629
1630 return 0;
1631}
1632
1633static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1634 int clk_id, unsigned int freq, int dir)
1635{
1636 pr_debug("%s\n", __func__);
1637 return 0;
1638}
1639
1640static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1641{
1642 pr_debug("%s\n", __func__);
1643 return 0;
1644}
1645
1646static int tabla_hw_params(struct snd_pcm_substream *substream,
1647 struct snd_pcm_hw_params *params,
1648 struct snd_soc_dai *dai)
1649{
1650 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1651 return 0;
1652}
1653
1654static struct snd_soc_dai_ops tabla_dai_ops = {
1655 .startup = tabla_startup,
1656 .shutdown = tabla_shutdown,
1657 .hw_params = tabla_hw_params,
1658 .set_sysclk = tabla_set_dai_sysclk,
1659 .set_fmt = tabla_set_dai_fmt,
1660 .digital_mute = tabla_digital_mute,
1661};
1662
1663static struct snd_soc_dai_driver tabla_dai[] = {
1664 {
1665 .name = "tabla_rx1",
1666 .id = 1,
1667 .playback = {
1668 .stream_name = "AIF1 Playback",
1669 .rates = SNDRV_PCM_RATE_8000_48000,
1670 .formats = TABLA_FORMATS,
1671 .rate_max = 48000,
1672 .rate_min = 8000,
1673 .channels_min = 1,
1674 .channels_max = 2,
1675 },
1676 .ops = &tabla_dai_ops,
1677 },
1678 {
1679 .name = "tabla_tx1",
1680 .id = 2,
1681 .capture = {
1682 .stream_name = "AIF1 Capture",
1683 .rates = SNDRV_PCM_RATE_8000_48000,
1684 .formats = TABLA_FORMATS,
1685 .rate_max = 48000,
1686 .rate_min = 8000,
1687 .channels_min = 1,
1688 .channels_max = 2,
1689 },
1690 .ops = &tabla_dai_ops,
1691 },
1692};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001693static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07001694{
1695 u8 bias_msb, bias_lsb;
1696 short bias_value;
1697
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001698 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1699 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1700 bias_value = (bias_msb << 8) | bias_lsb;
1701 return bias_value;
1702}
1703
1704static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
1705{
1706 u8 bias_msb, bias_lsb;
1707 short bias_value;
1708
1709 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1710 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1711 bias_value = (bias_msb << 8) | bias_lsb;
1712 return bias_value;
1713}
1714
1715static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1716 int dce)
1717{
1718 short bias_value;
1719
Bradley Rubincb1e2732011-06-23 16:49:20 -07001720 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001721 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1722 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1723 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1724 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1725 usleep_range(60000, 60000);
1726 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001727 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001728 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001729 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1730 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001731 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001732 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001733 usleep_range(50, 50);
1734 bias_value = tabla_codec_read_sta_result(codec);
1735 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1736 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001737 }
1738
Bradley Rubincb1e2732011-06-23 16:49:20 -07001739 pr_debug("read microphone bias value %x\n", bias_value);
1740 return bias_value;
1741}
1742
1743static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744{
1745 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1746 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Patrick Lai3043fba2011-08-01 14:15:57 -07001747 int micbias_ctl_reg, micbias_cfilt_ctl_reg,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001748 micbias_mbhc_reg;
1749 short bias_value, threshold_no_mic;
Patrick Lai3043fba2011-08-01 14:15:57 -07001750 unsigned int cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751
1752 if (!calibration) {
1753 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001754 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 }
1756
1757 tabla->mbhc_polling_active = true;
1758
1759 if (!tabla->ref_cnt) {
1760 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1761 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1762 tabla_codec_enable_clock_block(codec, 1);
1763 }
1764
1765 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1768
Patrick Lai3043fba2011-08-01 14:15:57 -07001769 /* select cfilt separately from the micbias line in the platform data */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 switch (calibration->bias) {
1771 case TABLA_MICBIAS1:
1772 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001773 cfilt_sel = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001774 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 break;
1776 case TABLA_MICBIAS2:
1777 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001778 cfilt_sel = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001779 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 break;
1781 case TABLA_MICBIAS3:
1782 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001783 cfilt_sel = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001784 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 break;
1786 case TABLA_MICBIAS4:
1787 pr_err("%s: Error, microphone bias 4 not supported\n",
1788 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001789 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 default:
1791 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001792 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793 }
Patrick Lai3043fba2011-08-01 14:15:57 -07001794
1795 switch (cfilt_sel) {
1796 case TABLA_CFILT1_SEL:
1797 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1798 break;
1799 case TABLA_CFILT2_SEL:
1800 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1801 break;
1802 case TABLA_CFILT3_SEL:
1803 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1804 break;
1805 default: /* default should not happen as check should have been done */
1806 return -EINVAL;
1807 }
1808
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001809 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001810
Bradley Rubincb1e2732011-06-23 16:49:20 -07001811 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812
1813 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001814 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815
1816 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1817 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1818 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1819
1820 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001821 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1822 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823
Bradley Rubincb1e2732011-06-23 16:49:20 -07001824 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1826
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001827 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001828 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1829
1830 tabla_codec_calibrate_hs_polling(codec);
1831
1832 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001833 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1834 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001835 threshold_no_mic = 0xF7F6;
1836
1837 if (bias_value < threshold_no_mic) {
1838 pr_debug("headphone detected, micbias %x\n", bias_value);
1839 return 0;
1840 } else {
1841 pr_debug("headset detected, micbias %x\n", bias_value);
1842 return 1;
1843 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844}
1845
1846static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1847 int insertion)
1848{
1849 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1850 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1851 int central_bias_enabled = 0;
1852 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1853
1854 if (!calibration) {
1855 pr_err("Error, no tabla calibration\n");
1856 return -EINVAL;
1857 }
1858
1859 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1860
1861 if (insertion)
1862 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1863 else
1864 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1865
1866 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1867 if (!(tabla->clock_active)) {
1868 tabla_codec_enable_config_mode(codec, 1);
1869 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001870 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 usleep_range(calibration->shutdown_plug_removal,
1872 calibration->shutdown_plug_removal);
1873 tabla_codec_enable_config_mode(codec, 0);
1874 } else
1875 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001876 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877 }
1878
1879 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1880 calibration->hph_current << 2);
1881
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001882 /* Turn off HPH PAs during insertion detection to avoid false
1883 * insertion interrupts
1884 */
1885 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1887
1888 switch (calibration->bias) {
1889 case TABLA_MICBIAS1:
1890 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1891 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1892 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1893 break;
1894 case TABLA_MICBIAS2:
1895 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1896 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1897 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1898 break;
1899 case TABLA_MICBIAS3:
1900 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1901 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1902 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1903 break;
1904 case TABLA_MICBIAS4:
1905 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1906 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1907 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1908 break;
1909 default:
1910 pr_err("Error, invalid mic bias line\n");
1911 return -EINVAL;
1912 }
1913 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1914 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1915
1916 /* If central bandgap disabled */
1917 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1918 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1919 usleep_range(calibration->bg_fast_settle,
1920 calibration->bg_fast_settle);
1921 central_bias_enabled = 1;
1922 }
1923
1924 /* If LDO_H disabled */
1925 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1926 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1927 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1928 usleep_range(calibration->tldoh, calibration->tldoh);
1929 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1930
1931 if (central_bias_enabled)
1932 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1933 }
1934 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1935 calibration->mic_current << 5);
1936 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1937 usleep_range(calibration->mic_pid, calibration->mic_pid);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001939 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1940
1941 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1942
1943 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1944 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1945 return 0;
1946}
1947
Bradley Rubincb1e2732011-06-23 16:49:20 -07001948int tabla_hs_detect(struct snd_soc_codec *codec,
1949 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 struct tabla_mbhc_calibration *calibration)
1951{
1952 struct tabla_priv *tabla;
1953 if (!codec || !calibration) {
1954 pr_err("Error: no codec or calibration\n");
1955 return -EINVAL;
1956 }
1957 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001958 tabla->headset_jack = headset_jack;
1959 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 tabla->calibration = calibration;
1961
1962 return tabla_codec_enable_hs_detect(codec, 1);
1963}
1964EXPORT_SYMBOL_GPL(tabla_hs_detect);
1965
Bradley Rubin688c66a2011-08-16 12:25:13 -07001966#define TABLA_BUTTON_MARGIN_ERROR 4
Bradley Rubincb1e2732011-06-23 16:49:20 -07001967static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001968{
1969 struct tabla_priv *priv = data;
1970 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin688c66a2011-08-16 12:25:13 -07001971 short bias_value, bias_value2;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001972
1973 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1974 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1975
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001976 bias_value = tabla_codec_read_dce_result(codec);
1977 pr_debug("button press interrupt, bias value is %d\n", bias_value);
1978
Bradley Rubin688c66a2011-08-16 12:25:13 -07001979 /* Do another DCE to make sure button voltage is the same */
1980 bias_value2 = tabla_codec_measure_micbias_voltage(codec, 1);
1981 pr_debug("button press part 2, bias value is %d\n", bias_value2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001982
Bradley Rubin688c66a2011-08-16 12:25:13 -07001983 if (abs(bias_value - bias_value2) < TABLA_BUTTON_MARGIN_ERROR) {
1984 if (priv->button_jack)
1985 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1986 SND_JACK_BTN_0);
1987
1988 priv->buttons_pressed |= SND_JACK_BTN_0;
1989 }
1990 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x09);
1991 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 return IRQ_HANDLED;
1994}
1995
Bradley Rubincb1e2732011-06-23 16:49:20 -07001996static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997{
1998 struct tabla_priv *priv = data;
1999 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002000 pr_debug("%s\n", __func__);
2001 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002002 if (priv->buttons_pressed & SND_JACK_BTN_0) {
2003 pr_debug("%s: Button released\n", __func__);
2004 if (priv->button_jack)
2005 snd_soc_jack_report(priv->button_jack, 0,
2006 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007
Bradley Rubincb1e2732011-06-23 16:49:20 -07002008 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010
Bradley Rubin688c66a2011-08-16 12:25:13 -07002011 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
2012 tabla_codec_start_hs_polling(codec);
2013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 return IRQ_HANDLED;
2015}
2016
Bradley Rubincb1e2732011-06-23 16:49:20 -07002017static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
2018{
2019 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2020 struct tabla_mbhc_calibration *calibration = tabla->calibration;
2021 int micbias_mbhc_reg;
2022
2023 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2024 tabla_codec_enable_config_mode(codec, 1);
2025
2026 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2027 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002028
2029 switch (calibration->bias) {
2030 case TABLA_MICBIAS1:
2031 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
2032 break;
2033 case TABLA_MICBIAS2:
2034 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
2035 break;
2036 case TABLA_MICBIAS3:
2037 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
2038 break;
2039 case TABLA_MICBIAS4:
2040 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
2041 break;
2042 default:
2043 pr_err("Error, invalid mic bias line\n");
2044 return;
2045 }
2046 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002047 usleep_range(calibration->shutdown_plug_removal,
2048 calibration->shutdown_plug_removal);
2049
2050 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
2051 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2052 tabla_codec_enable_config_mode(codec, 0);
2053
2054 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
2055}
2056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
2058{
2059 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002060
2061 tabla_codec_shutdown_hs_removal_detect(codec);
2062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002063 if (!tabla->ref_cnt) {
2064 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
2065 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2066 tabla_codec_enable_clock_block(codec, 0);
2067 }
2068
2069 tabla->mbhc_polling_active = false;
2070}
2071
Bradley Rubincb1e2732011-06-23 16:49:20 -07002072static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
2073{
2074 struct tabla_priv *priv = data;
2075 struct snd_soc_codec *codec = priv->codec;
2076 int microphone_present;
2077
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002078 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002079 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2080
2081 usleep_range(priv->calibration->setup_plug_removal_delay,
2082 priv->calibration->setup_plug_removal_delay);
2083
2084 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
2085 if (priv->headset_jack) {
2086 pr_debug("%s: Reporting removal\n", __func__);
2087 snd_soc_jack_report(priv->headset_jack, 0,
2088 SND_JACK_HEADSET);
2089 }
2090 tabla_codec_shutdown_hs_removal_detect(codec);
2091 tabla_codec_enable_hs_detect(codec, 1);
2092 return IRQ_HANDLED;
2093 }
2094
2095 microphone_present = tabla_codec_setup_hs_polling(codec);
2096
2097 if (microphone_present == 0) {
2098 if (priv->headset_jack) {
2099 pr_debug("%s: Reporting insertion %d\n", __func__,
2100 SND_JACK_HEADPHONE);
2101 snd_soc_jack_report(priv->headset_jack,
2102 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
2103 }
2104 tabla_codec_shutdown_hs_polling(codec);
2105 tabla_codec_enable_hs_detect(codec, 0);
2106 } else if (microphone_present == 1) {
2107 if (priv->headset_jack) {
2108 pr_debug("%s: Reporting insertion %d\n", __func__,
2109 SND_JACK_HEADSET);
2110 snd_soc_jack_report(priv->headset_jack,
2111 SND_JACK_HEADSET, SND_JACK_HEADSET);
2112 }
2113 tabla_codec_start_hs_polling(codec);
2114 }
2115
2116 return IRQ_HANDLED;
2117}
2118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
2120{
2121 struct tabla_priv *priv = data;
2122 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002123 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124
2125 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2126 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002127 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128
2129 usleep_range(priv->calibration->shutdown_plug_removal,
2130 priv->calibration->shutdown_plug_removal);
2131
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002132 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
2133 pr_debug("removal interrupt, bias value is %d\n", bias_value);
2134
2135 if (bias_value < -90) {
2136 pr_debug("False alarm, headset not actually removed\n");
2137 tabla_codec_start_hs_polling(codec);
2138 } else {
2139 if (priv->headset_jack) {
2140 pr_debug("%s: Reporting removal\n", __func__);
2141 snd_soc_jack_report(priv->headset_jack, 0,
2142 SND_JACK_HEADSET);
2143 }
2144 tabla_codec_shutdown_hs_polling(codec);
2145
2146 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148 return IRQ_HANDLED;
2149}
2150
2151static unsigned long slimbus_value;
2152
2153static irqreturn_t tabla_slimbus_irq(int irq, void *data)
2154{
2155 struct tabla_priv *priv = data;
2156 struct snd_soc_codec *codec = priv->codec;
2157 int i, j;
2158 u8 val;
2159
2160 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
2161 slimbus_value = tabla_interface_reg_read(codec->control_data,
2162 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
2163 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
2164 val = tabla_interface_reg_read(codec->control_data,
2165 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
2166 if (val & 0x1)
2167 pr_err_ratelimited("overflow error on port %x,"
2168 " value %x\n", i*8 + j, val);
2169 if (val & 0x2)
2170 pr_err_ratelimited("underflow error on port %x,"
2171 " value %x\n", i*8 + j, val);
2172 }
2173 tabla_interface_reg_write(codec->control_data,
2174 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2175 }
2176
2177 return IRQ_HANDLED;
2178}
2179
Patrick Lai3043fba2011-08-01 14:15:57 -07002180static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2181{
2182 int rc = -EINVAL;
2183 unsigned min_mv, max_mv;
2184
2185 switch (ldoh_v) {
2186 case TABLA_LDOH_1P95_V:
2187 min_mv = 160;
2188 max_mv = 1800;
2189 break;
2190 case TABLA_LDOH_2P35_V:
2191 min_mv = 200;
2192 max_mv = 2200;
2193 break;
2194 case TABLA_LDOH_2P75_V:
2195 min_mv = 240;
2196 max_mv = 2600;
2197 break;
2198 case TABLA_LDOH_2P85_V:
2199 min_mv = 250;
2200 max_mv = 2700;
2201 break;
2202 default:
2203 goto done;
2204 }
2205
2206 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2207 goto done;
2208
2209 for (rc = 4; rc <= 44; rc++) {
2210 min_mv = max_mv * (rc) / 44;
2211 if (min_mv >= cfilt_mv) {
2212 rc -= 4;
2213 break;
2214 }
2215 }
2216done:
2217 return rc;
2218}
2219
2220static int tabla_handle_pdata(struct tabla_priv *tabla)
2221{
2222 struct snd_soc_codec *codec = tabla->codec;
2223 struct tabla_pdata *pdata = tabla->pdata;
2224 int k1, k2, k3, rc = 0;
2225
2226 if (!pdata) {
2227 rc = -ENODEV;
2228 goto done;
2229 }
2230
2231 /* Make sure settings are correct */
2232 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
2233 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
2234 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
2235 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
2236 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
2237 rc = -EINVAL;
2238 goto done;
2239 }
2240
2241 /* figure out k value */
2242 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
2243 pdata->micbias.cfilt1_mv);
2244 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
2245 pdata->micbias.cfilt2_mv);
2246 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
2247 pdata->micbias.cfilt3_mv);
2248
2249 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
2250 rc = -EINVAL;
2251 goto done;
2252 }
2253
2254 /* Set voltage level and always use LDO */
2255 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
2256 (pdata->micbias.ldoh_v << 2));
2257
2258 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
2259 (k1 << 2));
2260 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
2261 (k2 << 2));
2262 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
2263 (k3 << 2));
2264
2265 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
2266 (pdata->micbias.bias1_cfilt_sel << 5));
2267 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
2268 (pdata->micbias.bias2_cfilt_sel << 5));
2269 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
2270 (pdata->micbias.bias3_cfilt_sel << 5));
2271 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
2272 (pdata->micbias.bias4_cfilt_sel << 5));
2273
2274done:
2275 return rc;
2276}
2277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278static int tabla_codec_probe(struct snd_soc_codec *codec)
2279{
2280 struct tabla *control;
2281 struct tabla_priv *tabla;
2282 struct snd_soc_dapm_context *dapm = &codec->dapm;
2283 int ret = 0;
2284 int i;
2285 int tx_channel;
2286
2287 codec->control_data = dev_get_drvdata(codec->dev->parent);
2288 control = codec->control_data;
2289
2290 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2291 if (!tabla) {
2292 dev_err(codec->dev, "Failed to allocate private data\n");
2293 return -ENOMEM;
2294 }
2295
2296 snd_soc_codec_set_drvdata(codec, tabla);
2297
2298 tabla->ref_cnt = 0;
2299 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2300 tabla->clock_active = false;
2301 tabla->config_mode_active = false;
2302 tabla->mbhc_polling_active = false;
2303 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002304 tabla->pdata = dev_get_platdata(codec->dev->parent);
2305
2306 ret = tabla_handle_pdata(tabla);
2307
2308 if (IS_ERR_VALUE(ret)) {
2309 pr_err("%s: bad pdata\n", __func__);
2310 goto err_pdata;
2311 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312
2313 /* TODO only enable bandgap when necessary in order to save power */
2314 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2315 tabla_codec_enable_clock_block(codec, 0);
2316
2317 /* Initialize gain registers to use register gain */
2318 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
2319 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
2320 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002321 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002323 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324
2325 /* Initialize mic biases to differential mode */
2326 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
2327 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
2328 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
2329 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
2330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
2332
2333 /* Use 16 bit sample size for now */
2334 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
2335 snd_soc_update_bits(codec,
2336 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
2337 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002338 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339
2340 }
2341 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
2342 snd_soc_update_bits(codec,
2343 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
2344 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002345 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 }
2347 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
2348 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
2349
2350 snd_soc_add_controls(codec, tabla_snd_controls,
2351 ARRAY_SIZE(tabla_snd_controls));
2352 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2353 ARRAY_SIZE(tabla_dapm_widgets));
2354 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2355 snd_soc_dapm_sync(dapm);
2356
2357 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2358 tabla_hs_insert_irq, "Headset insert detect", tabla);
2359 if (ret) {
2360 pr_err("%s: Failed to request irq %d\n", __func__,
2361 TABLA_IRQ_MBHC_INSERTION);
2362 goto err_insert_irq;
2363 }
2364 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2365
2366 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2367 tabla_hs_remove_irq, "Headset remove detect", tabla);
2368 if (ret) {
2369 pr_err("%s: Failed to request irq %d\n", __func__,
2370 TABLA_IRQ_MBHC_REMOVAL);
2371 goto err_remove_irq;
2372 }
2373 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2374
2375 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002376 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377 if (ret) {
2378 pr_err("%s: Failed to request irq %d\n", __func__,
2379 TABLA_IRQ_MBHC_POTENTIAL);
2380 goto err_potential_irq;
2381 }
2382 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2383
Bradley Rubincb1e2732011-06-23 16:49:20 -07002384 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2385 tabla_release_handler, "Button Release detect", tabla);
2386 if (ret) {
2387 pr_err("%s: Failed to request irq %d\n", __func__,
2388 TABLA_IRQ_MBHC_RELEASE);
2389 goto err_release_irq;
2390 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002391 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2394 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2395 if (ret) {
2396 pr_err("%s: Failed to request irq %d\n", __func__,
2397 TABLA_IRQ_SLIMBUS);
2398 goto err_slimbus_irq;
2399 }
2400
2401 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2402 tabla_interface_reg_write(codec->control_data,
2403 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2404
2405 return ret;
2406
2407err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002408 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2409err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2411err_potential_irq:
2412 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2413err_remove_irq:
2414 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2415err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07002416err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417 kfree(tabla);
2418 return ret;
2419}
2420static int tabla_codec_remove(struct snd_soc_codec *codec)
2421{
2422 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2423 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002424 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2426 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2427 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2428 tabla_codec_disable_clock_block(codec);
2429 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2430 kfree(tabla);
2431 return 0;
2432}
2433static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2434 .probe = tabla_codec_probe,
2435 .remove = tabla_codec_remove,
2436 .read = tabla_read,
2437 .write = tabla_write,
2438
2439 .readable_register = tabla_readable,
2440 .volatile_register = tabla_volatile,
2441
2442 .reg_cache_size = TABLA_CACHE_SIZE,
2443 .reg_cache_default = tabla_reg_defaults,
2444 .reg_word_size = 1,
2445};
2446static int __devinit tabla_probe(struct platform_device *pdev)
2447{
2448 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2449 tabla_dai, ARRAY_SIZE(tabla_dai));
2450}
2451static int __devexit tabla_remove(struct platform_device *pdev)
2452{
2453 snd_soc_unregister_codec(&pdev->dev);
2454 return 0;
2455}
2456static struct platform_driver tabla_codec_driver = {
2457 .probe = tabla_probe,
2458 .remove = tabla_remove,
2459 .driver = {
2460 .name = "tabla_codec",
2461 .owner = THIS_MODULE,
2462 },
2463};
2464
2465static int __init tabla_codec_init(void)
2466{
2467 return platform_driver_register(&tabla_codec_driver);
2468}
2469
2470static void __exit tabla_codec_exit(void)
2471{
2472 platform_driver_unregister(&tabla_codec_driver);
2473}
2474
2475module_init(tabla_codec_init);
2476module_exit(tabla_codec_exit);
2477
2478MODULE_DESCRIPTION("Tabla codec driver");
2479MODULE_VERSION("1.0");
2480MODULE_LICENSE("GPL v2");