blob: 15c2cf5ce60067e867bca229a2a949a5ed985eec [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
133 SOC_SINGLE_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL, 0,
134 100, 0, digital_gain),
135 SOC_SINGLE_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL, 0,
136 100, 0, digital_gain),
137
138 SOC_SINGLE_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, 100, 0,
139 digital_gain),
140 SOC_SINGLE_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, 100, 0,
141 digital_gain),
142
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700143 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
144 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700145 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
146 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700147 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
148 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149
150 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700151 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
152 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700153
154 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
155 tabla_put_anc_slot),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156};
157
158static const char *rx_mix1_text[] = {
159 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
160 "RX5", "RX6", "RX7"
161};
162
163static const char *sb_tx1_mux_text[] = {
164 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
165 "DEC1"
166};
167
168static const char *sb_tx5_mux_text[] = {
169 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
170 "DEC5"
171};
172
173static const char *sb_tx6_mux_text[] = {
174 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
175 "DEC6"
176};
177
178static const char const *sb_tx7_to_tx10_mux_text[] = {
179 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
180 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
181 "DEC9", "DEC10"
182};
183
184static const char *dec1_mux_text[] = {
185 "ZERO", "DMIC1", "ADC6",
186};
187
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700188static const char *dec2_mux_text[] = {
189 "ZERO", "DMIC2", "ADC5",
190};
191
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700192static const char *dec3_mux_text[] = {
193 "ZERO", "DMIC3", "ADC4",
194};
195
196static const char *dec4_mux_text[] = {
197 "ZERO", "DMIC4", "ADC3",
198};
199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200static const char *dec5_mux_text[] = {
201 "ZERO", "DMIC5", "ADC2",
202};
203
204static const char *dec6_mux_text[] = {
205 "ZERO", "DMIC6", "ADC1",
206};
207
208static const char const *dec7_mux_text[] = {
209 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
210};
211
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700212static const char *dec8_mux_text[] = {
213 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
214};
215
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700216static const char *dec9_mux_text[] = {
217 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
218};
219
220static const char *dec10_mux_text[] = {
221 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
222};
223
Bradley Rubin229c6a52011-07-12 16:18:48 -0700224static const char const *anc_mux_text[] = {
225 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
226 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
227};
228
229static const char const *anc1_fb_mux_text[] = {
230 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
231};
232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233static const char *iir1_inp1_text[] = {
234 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
235 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
236};
237
238static const struct soc_enum rx_mix1_inp1_chain_enum =
239 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
240
Bradley Rubin229c6a52011-07-12 16:18:48 -0700241static const struct soc_enum rx_mix1_inp2_chain_enum =
242 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244static const struct soc_enum rx2_mix1_inp1_chain_enum =
245 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
246
Bradley Rubin229c6a52011-07-12 16:18:48 -0700247static const struct soc_enum rx2_mix1_inp2_chain_enum =
248 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250static const struct soc_enum rx3_mix1_inp1_chain_enum =
251 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
252
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700253static const struct soc_enum rx3_mix1_inp2_chain_enum =
254 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256static const struct soc_enum rx4_mix1_inp1_chain_enum =
257 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
258
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700259static const struct soc_enum rx4_mix1_inp2_chain_enum =
260 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262static const struct soc_enum rx5_mix1_inp1_chain_enum =
263 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
264
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700265static const struct soc_enum rx5_mix1_inp2_chain_enum =
266 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
267
268static const struct soc_enum rx6_mix1_inp1_chain_enum =
269 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
270
271static const struct soc_enum rx6_mix1_inp2_chain_enum =
272 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274static const struct soc_enum sb_tx5_mux_enum =
275 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
276
277static const struct soc_enum sb_tx6_mux_enum =
278 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
279
280static const struct soc_enum sb_tx7_mux_enum =
281 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
282 sb_tx7_to_tx10_mux_text);
283
284static const struct soc_enum sb_tx8_mux_enum =
285 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
286 sb_tx7_to_tx10_mux_text);
287
288static const struct soc_enum sb_tx1_mux_enum =
289 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
290
291static const struct soc_enum dec1_mux_enum =
292 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
293
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700294static const struct soc_enum dec2_mux_enum =
295 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
296
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700297static const struct soc_enum dec3_mux_enum =
298 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
299
300static const struct soc_enum dec4_mux_enum =
301 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303static const struct soc_enum dec5_mux_enum =
304 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
305
306static const struct soc_enum dec6_mux_enum =
307 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
308
309static const struct soc_enum dec7_mux_enum =
310 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
311
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700312static const struct soc_enum dec8_mux_enum =
313 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
314
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700315static const struct soc_enum dec9_mux_enum =
316 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
317
318static const struct soc_enum dec10_mux_enum =
319 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
320
Bradley Rubin229c6a52011-07-12 16:18:48 -0700321static const struct soc_enum anc1_mux_enum =
322 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
323
324static const struct soc_enum anc2_mux_enum =
325 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
326
327static const struct soc_enum anc1_fb_mux_enum =
328 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330static const struct soc_enum iir1_inp1_mux_enum =
331 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
332
333static const struct snd_kcontrol_new rx_mix1_inp1_mux =
334 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
335
Bradley Rubin229c6a52011-07-12 16:18:48 -0700336static const struct snd_kcontrol_new rx_mix1_inp2_mux =
337 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
340 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
341
Bradley Rubin229c6a52011-07-12 16:18:48 -0700342static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
343 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
346 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
347
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700348static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
349 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
350
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
352 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
353
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700354static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
355 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
358 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
359
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700360static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
361 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
362
363static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
364 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
365
366static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
367 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369static const struct snd_kcontrol_new sb_tx5_mux =
370 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
371
372static const struct snd_kcontrol_new sb_tx6_mux =
373 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
374
375static const struct snd_kcontrol_new sb_tx7_mux =
376 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
377
378static const struct snd_kcontrol_new sb_tx8_mux =
379 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
380
381static const struct snd_kcontrol_new sb_tx1_mux =
382 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
383
384static const struct snd_kcontrol_new dec1_mux =
385 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
386
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700387static const struct snd_kcontrol_new dec2_mux =
388 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
389
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700390static const struct snd_kcontrol_new dec3_mux =
391 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
392
393static const struct snd_kcontrol_new dec4_mux =
394 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396static const struct snd_kcontrol_new dec5_mux =
397 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
398
399static const struct snd_kcontrol_new dec6_mux =
400 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
401
402static const struct snd_kcontrol_new dec7_mux =
403 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
404
Bradley Rubin229c6a52011-07-12 16:18:48 -0700405static const struct snd_kcontrol_new anc1_mux =
406 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700407static const struct snd_kcontrol_new dec8_mux =
408 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
409
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700410static const struct snd_kcontrol_new dec9_mux =
411 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
412
413static const struct snd_kcontrol_new dec10_mux =
414 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416static const struct snd_kcontrol_new iir1_inp1_mux =
417 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
418
Bradley Rubin229c6a52011-07-12 16:18:48 -0700419static const struct snd_kcontrol_new anc2_mux =
420 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421
Bradley Rubin229c6a52011-07-12 16:18:48 -0700422static const struct snd_kcontrol_new anc1_fb_mux =
423 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424
Bradley Rubin229c6a52011-07-12 16:18:48 -0700425static const struct snd_kcontrol_new dac1_switch[] = {
426 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
427};
428static const struct snd_kcontrol_new hphl_switch[] = {
429 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
430};
431static const struct snd_kcontrol_new hphr_switch[] = {
432 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
433};
434static const struct snd_kcontrol_new lineout1_switch[] = {
435 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
436};
437static const struct snd_kcontrol_new lineout2_switch[] = {
438 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
439};
440static const struct snd_kcontrol_new lineout3_switch[] = {
441 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
442};
443static const struct snd_kcontrol_new lineout4_switch[] = {
444 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
445};
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
448 int enable)
449{
450 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
451
452 pr_debug("%s %d\n", __func__, enable);
453
454 if (enable) {
455 tabla->adc_count++;
456 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
457 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
458 } else {
459 tabla->adc_count--;
460 if (!tabla->adc_count) {
461 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
462 0x2, 0x0);
463 if (!tabla->mbhc_polling_active)
464 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
465 0xE0, 0x0);
466 }
467 }
468}
469
470static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
471 struct snd_kcontrol *kcontrol, int event)
472{
473 struct snd_soc_codec *codec = w->codec;
474 u16 adc_reg;
475
476 pr_debug("%s %d\n", __func__, event);
477
478 if (w->reg == TABLA_A_TX_1_2_EN)
479 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
480 else if (w->reg == TABLA_A_TX_3_4_EN)
481 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
482 else if (w->reg == TABLA_A_TX_5_6_EN)
483 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
484 else {
485 pr_err("%s: Error, invalid adc register\n", __func__);
486 return -EINVAL;
487 }
488
489 switch (event) {
490 case SND_SOC_DAPM_PRE_PMU:
491 tabla_codec_enable_adc_block(codec, 1);
492 break;
493 case SND_SOC_DAPM_POST_PMU:
494 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
495 1 << w->shift);
496 usleep_range(1000, 1000);
497 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
498 usleep_range(1000, 1000);
499 break;
500 case SND_SOC_DAPM_POST_PMD:
501 tabla_codec_enable_adc_block(codec, 0);
502 break;
503 }
504 return 0;
505}
506
507static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
508 struct snd_kcontrol *kcontrol, int event)
509{
510 struct snd_soc_codec *codec = w->codec;
511
512 pr_debug("%s %d\n", __func__, event);
513 switch (event) {
514 case SND_SOC_DAPM_PRE_PMU:
515 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
516 break;
517 case SND_SOC_DAPM_POST_PMD:
518 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
519 break;
520 }
521 return 0;
522}
523
524static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
525 struct snd_kcontrol *kcontrol, int event)
526{
527 struct snd_soc_codec *codec = w->codec;
528 u16 lineout_gain_reg;
529
530 pr_debug("%s %d\n", __func__, event);
531
532 switch (w->shift) {
533 case 0:
534 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
535 break;
536 case 1:
537 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
538 break;
539 case 2:
540 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
541 break;
542 case 3:
543 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
544 break;
545 case 4:
546 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
547 break;
548 default:
549 pr_err("%s: Error, incorrect lineout register value\n",
550 __func__);
551 return -EINVAL;
552 }
553
554 switch (event) {
555 case SND_SOC_DAPM_PRE_PMU:
556 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
557 break;
558 case SND_SOC_DAPM_POST_PMU:
559 usleep_range(40000, 40000);
560 break;
561 case SND_SOC_DAPM_POST_PMD:
562 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
563 break;
564 }
565 return 0;
566}
567
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700568
569static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 struct snd_kcontrol *kcontrol, int event)
571{
572 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700573 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
574 u8 dmic_clk_sel, dmic_clk_en;
575
576 if (!strncmp(w->name, "DMIC1", 5)) {
577
578 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL;
579 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL;
580 dmic_clk_sel = 0x2;
581 dmic_clk_en = 0x1;
582
583 } else if (!strncmp(w->name, "DMIC2", 5)) {
584
585 tx_mux_ctl_reg = TABLA_A_CDC_TX2_MUX_CTL;
586 tx_dmic_ctl_reg = TABLA_A_CDC_TX2_DMIC_CTL;
587 dmic_clk_sel = 0x2;
588 dmic_clk_en = 0x1;
589
590 } else if (!strncmp(w->name, "DMIC3", 5)) {
591
592 tx_mux_ctl_reg = TABLA_A_CDC_TX3_MUX_CTL;
593 tx_dmic_ctl_reg = TABLA_A_CDC_TX3_DMIC_CTL;
594 dmic_clk_sel = 0x8;
595 dmic_clk_en = 0x4;
596
597 } else {
598 pr_err("%s: Error, DMIC = %s\n", __func__, w->name);
599 return -EINVAL;
600 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601
602 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 switch (event) {
605 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700606 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
607
608 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
609 dmic_clk_sel, dmic_clk_sel);
610
611 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
612
613 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
614 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 break;
616 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700617 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
618 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 break;
620 }
621 return 0;
622}
623
Bradley Rubin229c6a52011-07-12 16:18:48 -0700624static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
625 struct snd_kcontrol *kcontrol, int event)
626{
627 struct snd_soc_codec *codec = w->codec;
628 const char *filename;
629 const struct firmware *fw;
630 int i;
631 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -0700632 int num_anc_slots;
633 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700634 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -0700635 u32 anc_writes_size = 0;
636 int anc_size_remaining;
637 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700638 u16 reg;
639 u8 mask, val, old_val;
640
641 pr_debug("%s %d\n", __func__, event);
642 switch (event) {
643 case SND_SOC_DAPM_PRE_PMU:
644
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700645 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -0700646
647 ret = request_firmware(&fw, filename, codec->dev);
648 if (ret != 0) {
649 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
650 ret);
651 return -ENODEV;
652 }
653
Bradley Rubina7096d02011-08-03 18:29:02 -0700654 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -0700655 dev_err(codec->dev, "Not enough data\n");
656 release_firmware(fw);
657 return -ENOMEM;
658 }
659
660 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -0700661 anc_head = (struct anc_header *)(fw->data);
662 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
663 anc_size_remaining = fw->size - sizeof(struct anc_header);
664 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700665
Bradley Rubina7096d02011-08-03 18:29:02 -0700666 if (tabla->anc_slot >= num_anc_slots) {
667 dev_err(codec->dev, "Invalid ANC slot selected\n");
668 release_firmware(fw);
669 return -EINVAL;
670 }
671
672 for (i = 0; i < num_anc_slots; i++) {
673
674 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
675 dev_err(codec->dev, "Invalid register format\n");
676 release_firmware(fw);
677 return -EINVAL;
678 }
679 anc_writes_size = (u32)(*anc_ptr);
680 anc_size_remaining -= sizeof(u32);
681 anc_ptr += 1;
682
683 if (anc_writes_size * TABLA_PACKED_REG_SIZE
684 > anc_size_remaining) {
685 dev_err(codec->dev, "Invalid register format\n");
686 release_firmware(fw);
687 return -ENOMEM;
688 }
689
690 if (tabla->anc_slot == i)
691 break;
692
693 anc_size_remaining -= (anc_writes_size *
694 TABLA_PACKED_REG_SIZE);
695 anc_ptr += (anc_writes_size *
696 TABLA_PACKED_REG_SIZE);
697 }
698 if (i == num_anc_slots) {
699 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -0700700 release_firmware(fw);
701 return -ENOMEM;
702 }
703
Bradley Rubina7096d02011-08-03 18:29:02 -0700704 for (i = 0; i < anc_writes_size; i++) {
705 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -0700706 mask, val);
707 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700708 snd_soc_write(codec, reg, (old_val & ~mask) |
709 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -0700710 }
711 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700712
713 break;
714 case SND_SOC_DAPM_POST_PMD:
715 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
716 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
717 break;
718 }
719 return 0;
720}
721
Patrick Lai3043fba2011-08-01 14:15:57 -0700722static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
723 u8 cfilt_sel, int inc)
724{
725 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
726 u32 *cfilt_cnt_ptr = NULL;
727 u16 micb_cfilt_reg;
728
729 switch (cfilt_sel) {
730 case TABLA_CFILT1_SEL:
731 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
732 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
733 break;
734 case TABLA_CFILT2_SEL:
735 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
736 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
737 break;
738 case TABLA_CFILT3_SEL:
739 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
740 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
741 break;
742 default:
743 return; /* should not happen */
744 }
745
746 if (inc) {
747 if (!(*cfilt_cnt_ptr)++)
748 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
749 } else {
750 /* check if count not zero, decrement
751 * then check if zero, go ahead disable cfilter
752 */
753 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr))
754 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
755 }
756}
Bradley Rubin229c6a52011-07-12 16:18:48 -0700757
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700758static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
759{
760 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
761 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
762 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
763 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
764 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
765 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
766 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
767}
768
769static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
770{
771 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
772 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
773 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
774 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
775}
776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
778 struct snd_kcontrol *kcontrol, int event)
779{
780 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -0700781 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
782 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700783 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700784 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700785 char *internal1_text = "Internal1";
786 char *internal2_text = "Internal2";
787 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788
789 pr_debug("%s %d\n", __func__, event);
790 switch (w->reg) {
791 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700793 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700794 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795 break;
796 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700798 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700799 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 break;
801 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700803 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700804 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700805 break;
806 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700807 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700808 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700809 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 break;
811 default:
812 pr_err("%s: Error, invalid micbias register\n", __func__);
813 return -EINVAL;
814 }
815
816 switch (event) {
817 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700818 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -0700819 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700820
821 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700823 else if (strnstr(w->name, internal2_text, 30))
824 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
825 else if (strnstr(w->name, internal3_text, 30))
826 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700829 case SND_SOC_DAPM_POST_PMU:
830 if (tabla->mbhc_polling_active &&
831 (tabla->calibration->bias == micb_line)) {
832 tabla_codec_pause_hs_polling(codec);
833 tabla_codec_start_hs_polling(codec);
834 }
835 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700837 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700839 else if (strnstr(w->name, internal2_text, 30))
840 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
841 else if (strnstr(w->name, internal3_text, 30))
842 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
843
Patrick Lai3043fba2011-08-01 14:15:57 -0700844 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700845 break;
846 }
847
848 return 0;
849}
850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
852 struct snd_kcontrol *kcontrol, int event)
853{
854 struct snd_soc_codec *codec = w->codec;
855 u16 dec_reset_reg;
856
857 pr_debug("%s %d\n", __func__, event);
858
859 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
860 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
861 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
862 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
863 else {
864 pr_err("%s: Error, incorrect dec\n", __func__);
865 return -EINVAL;
866 }
867
868 switch (event) {
869 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
871 1 << w->shift);
872 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
873 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 }
875 return 0;
876}
877
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700878static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 struct snd_kcontrol *kcontrol, int event)
880{
881 struct snd_soc_codec *codec = w->codec;
882
883 switch (event) {
884 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700885 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
886 1 << w->shift, 1 << w->shift);
887 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
888 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 break;
890 }
891 return 0;
892}
893
Bradley Rubin229c6a52011-07-12 16:18:48 -0700894static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
895 struct snd_kcontrol *kcontrol, int event)
896{
897 switch (event) {
898 case SND_SOC_DAPM_POST_PMU:
899 case SND_SOC_DAPM_POST_PMD:
900 usleep_range(1000, 1000);
901 break;
902 }
903 return 0;
904}
905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
907 /*RX stuff */
908 SND_SOC_DAPM_OUTPUT("EAR"),
909
910 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
911 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
912 SND_SOC_DAPM_PRE_PMD),
913
914 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
915
Bradley Rubin229c6a52011-07-12 16:18:48 -0700916 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
917 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918
Bradley Rubin229c6a52011-07-12 16:18:48 -0700919 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
920 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921
922 /* Headphone */
923 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
924 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700925 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
926 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927
928 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700929 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
930 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931
932 /* Speaker */
933 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
936 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
937 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700938 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
939 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
940 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
942 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
943 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700944 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
945 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
946 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
947
Bradley Rubin229c6a52011-07-12 16:18:48 -0700948 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
949 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
950 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
951 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
952 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
953 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
954 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
955 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700956
Bradley Rubin229c6a52011-07-12 16:18:48 -0700957 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
958 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
959 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
960 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
961 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
962 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
963 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
964 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
965 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
966 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
967 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
968 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700969
Bradley Rubin229c6a52011-07-12 16:18:48 -0700970 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
971 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
972
973 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
974 &rx_mix1_inp1_mux),
975 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
976 &rx_mix1_inp2_mux),
977 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
978 &rx2_mix1_inp1_mux),
979 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
980 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700981 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
982 &rx3_mix1_inp1_mux),
983 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
984 &rx3_mix1_inp2_mux),
985 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
986 &rx4_mix1_inp1_mux),
987 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
988 &rx4_mix1_inp2_mux),
989 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
990 &rx5_mix1_inp1_mux),
991 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
992 &rx5_mix1_inp2_mux),
993 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
994 &rx6_mix1_inp1_mux),
995 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
996 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997
Bradley Rubin229c6a52011-07-12 16:18:48 -0700998 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
999 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1000 SND_SOC_DAPM_PRE_PMD),
1001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001003
Bradley Rubine1d08622011-07-20 18:01:35 -07001004 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1005 0),
1006
Bradley Rubin229c6a52011-07-12 16:18:48 -07001007 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
1008 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 SND_SOC_DAPM_INPUT("AMIC1"),
1011 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
1012 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001013 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001014 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
1015 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001016 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001017 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001019 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
1021 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1022 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1023
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001024 SND_SOC_DAPM_INPUT("AMIC3"),
1025 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
1026 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1027 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1028
1029 SND_SOC_DAPM_INPUT("AMIC4"),
1030 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1031 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1032 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1033
1034 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1035 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001036 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001037
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001038 SND_SOC_DAPM_INPUT("AMIC5"),
1039 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
1040 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1041
1042 SND_SOC_DAPM_INPUT("AMIC6"),
1043 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
1044 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 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 -07001047 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001049 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 -07001050 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001051
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001052 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 -07001053 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001054
1055 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 -07001056 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 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 -07001059 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060
1061 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 -07001062 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063
1064 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 -07001065 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001067 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 -07001068 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001069
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001070 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 -07001071 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001072
1073 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 -07001074 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001075
Bradley Rubin229c6a52011-07-12 16:18:48 -07001076 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1077 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1078
1079 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1080 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1081 SND_SOC_DAPM_POST_PMD),
1082
1083 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 SND_SOC_DAPM_INPUT("AMIC2"),
1086 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
1087 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001088 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001089 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
1090 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001091 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001092 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
1093 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001094 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001095 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001097 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
1099 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001100 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001101 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
1102 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001103 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001104 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001106 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1108 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1109 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1110
1111 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1112 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1113 0, 0),
1114
1115 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1116 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1117 4, 0),
1118
1119 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1120 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1121 5, 0),
1122
1123 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1124 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1125 0, 0),
1126
1127 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1128 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1129 0, 0),
1130
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001131 /* Digital Mic Inputs */
1132 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic),
1133 SND_SOC_DAPM_MIC("DMIC2", &tabla_codec_enable_dmic),
1134 SND_SOC_DAPM_MIC("DMIC3", &tabla_codec_enable_dmic),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135
1136 /* Sidetone */
1137 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1138 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1139};
1140
1141static const struct snd_soc_dapm_route audio_map[] = {
1142 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143
1144 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1145 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1146
1147 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1148 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1149
1150 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1151 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1152
1153 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1154 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001155 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001156 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1157 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1159 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001160 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1161 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001162 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1163 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164
1165 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001166 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1167 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1168 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1170 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1171
1172 /* Earpiece (RX MIX1) */
1173 {"EAR", NULL, "EAR PA"},
1174 {"EAR PA", NULL, "EAR PA Input"},
1175 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001176 {"DAC1", NULL, "CP"},
1177
1178 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1179 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1180 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181
1182 /* Headset (RX MIX1 and RX MIX2) */
1183 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001185
1186 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001188
1189 {"HPHL DAC", NULL, "CP"},
1190 {"HPHR DAC", NULL, "CP"},
1191
1192 {"ANC", NULL, "ANC1 MUX"},
1193 {"ANC", NULL, "ANC2 MUX"},
1194 {"ANC1 MUX", "ADC1", "ADC1"},
1195 {"ANC1 MUX", "ADC2", "ADC2"},
1196 {"ANC1 MUX", "ADC3", "ADC3"},
1197 {"ANC1 MUX", "ADC4", "ADC4"},
1198 {"ANC2 MUX", "ADC1", "ADC1"},
1199 {"ANC2 MUX", "ADC2", "ADC2"},
1200 {"ANC2 MUX", "ADC3", "ADC3"},
1201 {"ANC2 MUX", "ADC4", "ADC4"},
1202
Bradley Rubine1d08622011-07-20 18:01:35 -07001203 {"ANC", NULL, "CDC_CONN"},
1204
Bradley Rubin229c6a52011-07-12 16:18:48 -07001205 {"DAC1", "Switch", "RX1 CHAIN"},
1206 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1207 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001210 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001212 {"LINEOUT", NULL, "LINEOUT4"},
1213
1214 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1215 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001217 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
1218
Bradley Rubin229c6a52011-07-12 16:18:48 -07001219 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1220 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1221 {"RX1 CHAIN", NULL, "ANC"},
1222 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001223 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1224 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
Kiran Kandied246a92011-08-12 14:03:44 -07001225 {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
1226 {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001227
Bradley Rubin229c6a52011-07-12 16:18:48 -07001228 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1229 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1230 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1231 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001232 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1233 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1234 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1235 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1236 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1237 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1238 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1239 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
1240
Bradley Rubin229c6a52011-07-12 16:18:48 -07001241 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1242 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1243 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1244 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1245 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1246 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1247 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1248 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1249 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1250 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1251 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1252 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1253 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1254 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1255 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1256 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1257 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1258 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1259 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1260 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1261 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1262 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1263 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1264 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1265 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1266 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001268 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001269 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001270 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001271 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001272 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001273 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001274 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001275 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001276 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001277 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001278 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001279 {"DEC4 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001281 {"DEC5 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001283 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001284 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001285 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001286 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001287 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001288 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001289 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001290 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001291 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001292 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001293
1294 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 {"ADC1", NULL, "AMIC1"},
1296 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001297 {"ADC3", NULL, "AMIC3"},
1298 {"ADC4", NULL, "AMIC4"},
1299 {"ADC5", NULL, "AMIC5"},
1300 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 {"IIR1", NULL, "IIR1 INP1 MUX"},
1303 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001304
1305 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1306 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1307 {"MIC BIAS1 External", NULL, "LDO_H"},
1308 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1309 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1310 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1311 {"MIC BIAS2 External", NULL, "LDO_H"},
1312 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1313 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1314 {"MIC BIAS3 External", NULL, "LDO_H"},
1315 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316};
1317
1318static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1319{
1320 return tabla_reg_readable[reg];
1321}
1322
1323static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1324{
1325 /* Registers lower than 0x100 are top level registers which can be
1326 * written by the Tabla core driver.
1327 */
1328
1329 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1330 return 1;
1331
1332 return 0;
1333}
1334
1335#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1336static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1337 unsigned int value)
1338{
1339 int ret;
1340 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1341
1342 BUG_ON(reg > TABLA_MAX_REGISTER);
1343
1344 if (!tabla_volatile(codec, reg)) {
1345 pr_debug("writing to cache\n");
1346 ret = snd_soc_cache_write(codec, reg, value);
1347 if (ret != 0)
1348 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1349 reg, ret);
1350 }
1351
1352 return tabla_reg_write(codec->control_data, reg, value);
1353}
1354static unsigned int tabla_read(struct snd_soc_codec *codec,
1355 unsigned int reg)
1356{
1357 unsigned int val;
1358 int ret;
1359
1360 BUG_ON(reg > TABLA_MAX_REGISTER);
1361
1362 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1363 reg < codec->driver->reg_cache_size) {
1364 pr_debug("reading from cache\n");
1365 ret = snd_soc_cache_read(codec, reg, &val);
1366 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001367 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 return val;
1369 } else
1370 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1371 reg, ret);
1372 }
1373
1374 val = tabla_reg_read(codec->control_data, reg);
1375 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1376 return val;
1377}
1378
1379static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1380{
1381 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1382 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1383 0x80);
1384 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1385 0x04);
1386 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1387 0x01);
1388 usleep_range(1000, 1000);
1389 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1390 0x00);
1391}
1392
1393static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1394 enum tabla_bandgap_type choice)
1395{
1396 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1397
1398 /* TODO lock resources accessed by audio streams and threaded
1399 * interrupt handlers
1400 */
1401
1402 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1403 tabla->bandgap_type);
1404
1405 if (tabla->bandgap_type == choice)
1406 return;
1407
1408 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1409 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1410 tabla_codec_enable_audio_mode_bandgap(codec);
1411 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1412 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1413 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1414 0x2);
1415 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1416 0x80);
1417 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1418 0x4);
1419 usleep_range(1000, 1000);
1420 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1421 0x00);
1422 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1423 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1424 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1425 usleep_range(100, 100);
1426 tabla_codec_enable_audio_mode_bandgap(codec);
1427 } else if (choice == TABLA_BANDGAP_OFF) {
1428 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1429 } else {
1430 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1431 }
1432 tabla->bandgap_type = choice;
1433}
1434
1435static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1436 int enable)
1437{
1438 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1439
1440 if (enable) {
1441 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1442 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1443 usleep_range(5, 5);
1444 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1445 0x80);
1446 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1447 0x80);
1448 usleep_range(10, 10);
1449 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1450 usleep_range(20, 20);
1451 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1452 } else {
1453 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1454 0);
1455 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1456 }
1457 tabla->config_mode_active = enable ? true : false;
1458
1459 return 0;
1460}
1461
1462static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1463 int config_mode)
1464{
1465 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1466
1467 pr_debug("%s\n", __func__);
1468
1469 if (config_mode) {
1470 tabla_codec_enable_config_mode(codec, 1);
1471 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1472 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1473 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1474 usleep_range(1000, 1000);
1475 } else
1476 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1477
1478 if (!config_mode && tabla->mbhc_polling_active) {
1479 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1480 tabla_codec_enable_config_mode(codec, 0);
1481
1482 }
1483
1484 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1485 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1486 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1487 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1488 usleep_range(50, 50);
1489 tabla->clock_active = true;
1490 return 0;
1491}
1492static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1493{
1494 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1495 pr_debug("%s\n", __func__);
1496 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1497 ndelay(160);
1498 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1499 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1500 tabla->clock_active = false;
1501}
1502
Bradley Rubincb1e2732011-06-23 16:49:20 -07001503static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1504{
1505 /* TODO store register values in calibration */
1506
1507 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1508 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1509
1510 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1511 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1512 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1513 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1514
1515 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1516 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1517 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1518 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1519 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1520 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1521}
1522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523static int tabla_startup(struct snd_pcm_substream *substream,
1524 struct snd_soc_dai *dai)
1525{
1526 struct snd_soc_codec *codec = dai->codec;
1527 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1528 int ret = 0;
1529
1530 pr_debug("%s()\n", __func__);
1531
1532 if (!codec) {
1533 pr_err("Error, no codec found\n");
1534 return -EINVAL;
1535 }
1536 tabla->ref_cnt++;
1537
Patrick Lai3043fba2011-08-01 14:15:57 -07001538 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001539 tabla->rx_count++;
1540 if (tabla->rx_count == 1)
1541 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1542 0x80);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 }
1544
1545 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001546 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1548 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001549 tabla_codec_calibrate_hs_polling(codec);
1550 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 }
1552
1553 return ret;
1554}
1555
1556static void tabla_shutdown(struct snd_pcm_substream *substream,
1557 struct snd_soc_dai *dai)
1558{
1559 struct snd_soc_codec *codec = dai->codec;
1560 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1561
1562 pr_debug("%s()\n", __func__);
1563
1564 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1565 /* Disable LDO */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001566 } else {
1567 tabla->rx_count--;
1568 if (!tabla->rx_count)
1569 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1570 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 }
1572
1573 if (!tabla->ref_cnt) {
1574 pr_err("Error, trying to shutdown codec when already down\n");
1575 return;
1576 }
1577 tabla->ref_cnt--;
1578
1579 if (tabla->mbhc_polling_active) {
1580 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001581 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582 tabla_codec_enable_bandgap(codec,
1583 TABLA_BANDGAP_MBHC_MODE);
1584 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1585 0x80);
1586 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001587 tabla_codec_calibrate_hs_polling(codec);
1588 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 }
1590 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1591 }
1592}
1593
1594static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1595{
1596 struct snd_soc_codec *codec = codec_dai->codec;
1597
1598 pr_debug("%s %d\n", __func__, mute);
1599
1600 /* TODO mute TX */
1601 if (mute)
1602 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1603 else
1604 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1605
1606 return 0;
1607}
1608
1609static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1610 int clk_id, unsigned int freq, int dir)
1611{
1612 pr_debug("%s\n", __func__);
1613 return 0;
1614}
1615
1616static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1617{
1618 pr_debug("%s\n", __func__);
1619 return 0;
1620}
1621
1622static int tabla_hw_params(struct snd_pcm_substream *substream,
1623 struct snd_pcm_hw_params *params,
1624 struct snd_soc_dai *dai)
1625{
1626 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1627 return 0;
1628}
1629
1630static struct snd_soc_dai_ops tabla_dai_ops = {
1631 .startup = tabla_startup,
1632 .shutdown = tabla_shutdown,
1633 .hw_params = tabla_hw_params,
1634 .set_sysclk = tabla_set_dai_sysclk,
1635 .set_fmt = tabla_set_dai_fmt,
1636 .digital_mute = tabla_digital_mute,
1637};
1638
1639static struct snd_soc_dai_driver tabla_dai[] = {
1640 {
1641 .name = "tabla_rx1",
1642 .id = 1,
1643 .playback = {
1644 .stream_name = "AIF1 Playback",
1645 .rates = SNDRV_PCM_RATE_8000_48000,
1646 .formats = TABLA_FORMATS,
1647 .rate_max = 48000,
1648 .rate_min = 8000,
1649 .channels_min = 1,
1650 .channels_max = 2,
1651 },
1652 .ops = &tabla_dai_ops,
1653 },
1654 {
1655 .name = "tabla_tx1",
1656 .id = 2,
1657 .capture = {
1658 .stream_name = "AIF1 Capture",
1659 .rates = SNDRV_PCM_RATE_8000_48000,
1660 .formats = TABLA_FORMATS,
1661 .rate_max = 48000,
1662 .rate_min = 8000,
1663 .channels_min = 1,
1664 .channels_max = 2,
1665 },
1666 .ops = &tabla_dai_ops,
1667 },
1668};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001669static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07001670{
1671 u8 bias_msb, bias_lsb;
1672 short bias_value;
1673
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001674 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1675 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1676 bias_value = (bias_msb << 8) | bias_lsb;
1677 return bias_value;
1678}
1679
1680static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
1681{
1682 u8 bias_msb, bias_lsb;
1683 short bias_value;
1684
1685 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1686 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1687 bias_value = (bias_msb << 8) | bias_lsb;
1688 return bias_value;
1689}
1690
1691static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1692 int dce)
1693{
1694 short bias_value;
1695
Bradley Rubincb1e2732011-06-23 16:49:20 -07001696 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001697 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1698 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1699 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1700 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1701 usleep_range(60000, 60000);
1702 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001703 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001704 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001705 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1706 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001707 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001708 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001709 usleep_range(50, 50);
1710 bias_value = tabla_codec_read_sta_result(codec);
1711 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1712 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001713 }
1714
Bradley Rubincb1e2732011-06-23 16:49:20 -07001715 pr_debug("read microphone bias value %x\n", bias_value);
1716 return bias_value;
1717}
1718
1719static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720{
1721 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1722 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Patrick Lai3043fba2011-08-01 14:15:57 -07001723 int micbias_ctl_reg, micbias_cfilt_ctl_reg,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001724 micbias_mbhc_reg;
1725 short bias_value, threshold_no_mic;
Patrick Lai3043fba2011-08-01 14:15:57 -07001726 unsigned int cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727
1728 if (!calibration) {
1729 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001730 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 }
1732
1733 tabla->mbhc_polling_active = true;
1734
1735 if (!tabla->ref_cnt) {
1736 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1737 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1738 tabla_codec_enable_clock_block(codec, 1);
1739 }
1740
1741 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1744
Patrick Lai3043fba2011-08-01 14:15:57 -07001745 /* select cfilt separately from the micbias line in the platform data */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 switch (calibration->bias) {
1747 case TABLA_MICBIAS1:
1748 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001749 cfilt_sel = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001750 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 break;
1752 case TABLA_MICBIAS2:
1753 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001754 cfilt_sel = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001755 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756 break;
1757 case TABLA_MICBIAS3:
1758 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001759 cfilt_sel = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001760 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 break;
1762 case TABLA_MICBIAS4:
1763 pr_err("%s: Error, microphone bias 4 not supported\n",
1764 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001765 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 default:
1767 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001768 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 }
Patrick Lai3043fba2011-08-01 14:15:57 -07001770
1771 switch (cfilt_sel) {
1772 case TABLA_CFILT1_SEL:
1773 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1774 break;
1775 case TABLA_CFILT2_SEL:
1776 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1777 break;
1778 case TABLA_CFILT3_SEL:
1779 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1780 break;
1781 default: /* default should not happen as check should have been done */
1782 return -EINVAL;
1783 }
1784
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001785 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786
Bradley Rubincb1e2732011-06-23 16:49:20 -07001787 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788
1789 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001790 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791
1792 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1793 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1794 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1795
1796 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001797 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1798 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799
Bradley Rubincb1e2732011-06-23 16:49:20 -07001800 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1802
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001803 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001804 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1805
1806 tabla_codec_calibrate_hs_polling(codec);
1807
1808 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001809 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1810 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001811 threshold_no_mic = 0xF7F6;
1812
1813 if (bias_value < threshold_no_mic) {
1814 pr_debug("headphone detected, micbias %x\n", bias_value);
1815 return 0;
1816 } else {
1817 pr_debug("headset detected, micbias %x\n", bias_value);
1818 return 1;
1819 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820}
1821
1822static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1823 int insertion)
1824{
1825 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1826 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1827 int central_bias_enabled = 0;
1828 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1829
1830 if (!calibration) {
1831 pr_err("Error, no tabla calibration\n");
1832 return -EINVAL;
1833 }
1834
1835 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1836
1837 if (insertion)
1838 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1839 else
1840 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1841
1842 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1843 if (!(tabla->clock_active)) {
1844 tabla_codec_enable_config_mode(codec, 1);
1845 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001846 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847 usleep_range(calibration->shutdown_plug_removal,
1848 calibration->shutdown_plug_removal);
1849 tabla_codec_enable_config_mode(codec, 0);
1850 } else
1851 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001852 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 }
1854
1855 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1856 calibration->hph_current << 2);
1857
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001858 /* Turn off HPH PAs during insertion detection to avoid false
1859 * insertion interrupts
1860 */
1861 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1863
1864 switch (calibration->bias) {
1865 case TABLA_MICBIAS1:
1866 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1867 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1868 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1869 break;
1870 case TABLA_MICBIAS2:
1871 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1872 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1873 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1874 break;
1875 case TABLA_MICBIAS3:
1876 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1877 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1878 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1879 break;
1880 case TABLA_MICBIAS4:
1881 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1882 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1883 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1884 break;
1885 default:
1886 pr_err("Error, invalid mic bias line\n");
1887 return -EINVAL;
1888 }
1889 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1890 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1891
1892 /* If central bandgap disabled */
1893 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1894 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1895 usleep_range(calibration->bg_fast_settle,
1896 calibration->bg_fast_settle);
1897 central_bias_enabled = 1;
1898 }
1899
1900 /* If LDO_H disabled */
1901 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1902 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1903 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1904 usleep_range(calibration->tldoh, calibration->tldoh);
1905 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1906
1907 if (central_bias_enabled)
1908 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1909 }
1910 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1911 calibration->mic_current << 5);
1912 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1913 usleep_range(calibration->mic_pid, calibration->mic_pid);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1916
1917 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1918
1919 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1920 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1921 return 0;
1922}
1923
Bradley Rubincb1e2732011-06-23 16:49:20 -07001924int tabla_hs_detect(struct snd_soc_codec *codec,
1925 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 struct tabla_mbhc_calibration *calibration)
1927{
1928 struct tabla_priv *tabla;
1929 if (!codec || !calibration) {
1930 pr_err("Error: no codec or calibration\n");
1931 return -EINVAL;
1932 }
1933 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001934 tabla->headset_jack = headset_jack;
1935 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001936 tabla->calibration = calibration;
1937
1938 return tabla_codec_enable_hs_detect(codec, 1);
1939}
1940EXPORT_SYMBOL_GPL(tabla_hs_detect);
1941
Bradley Rubin688c66a2011-08-16 12:25:13 -07001942#define TABLA_BUTTON_MARGIN_ERROR 4
Bradley Rubincb1e2732011-06-23 16:49:20 -07001943static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944{
1945 struct tabla_priv *priv = data;
1946 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin688c66a2011-08-16 12:25:13 -07001947 short bias_value, bias_value2;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001948
1949 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1950 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1951
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001952 bias_value = tabla_codec_read_dce_result(codec);
1953 pr_debug("button press interrupt, bias value is %d\n", bias_value);
1954
Bradley Rubin688c66a2011-08-16 12:25:13 -07001955 /* Do another DCE to make sure button voltage is the same */
1956 bias_value2 = tabla_codec_measure_micbias_voltage(codec, 1);
1957 pr_debug("button press part 2, bias value is %d\n", bias_value2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001958
Bradley Rubin688c66a2011-08-16 12:25:13 -07001959 if (abs(bias_value - bias_value2) < TABLA_BUTTON_MARGIN_ERROR) {
1960 if (priv->button_jack)
1961 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1962 SND_JACK_BTN_0);
1963
1964 priv->buttons_pressed |= SND_JACK_BTN_0;
1965 }
1966 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x09);
1967 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969 return IRQ_HANDLED;
1970}
1971
Bradley Rubincb1e2732011-06-23 16:49:20 -07001972static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973{
1974 struct tabla_priv *priv = data;
1975 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001976 pr_debug("%s\n", __func__);
1977 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001978 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1979 pr_debug("%s: Button released\n", __func__);
1980 if (priv->button_jack)
1981 snd_soc_jack_report(priv->button_jack, 0,
1982 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983
Bradley Rubincb1e2732011-06-23 16:49:20 -07001984 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986
Bradley Rubin688c66a2011-08-16 12:25:13 -07001987 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1988 tabla_codec_start_hs_polling(codec);
1989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990 return IRQ_HANDLED;
1991}
1992
Bradley Rubincb1e2732011-06-23 16:49:20 -07001993static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1994{
1995 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1996 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1997 int micbias_mbhc_reg;
1998
1999 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2000 tabla_codec_enable_config_mode(codec, 1);
2001
2002 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2003 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002004
2005 switch (calibration->bias) {
2006 case TABLA_MICBIAS1:
2007 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
2008 break;
2009 case TABLA_MICBIAS2:
2010 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
2011 break;
2012 case TABLA_MICBIAS3:
2013 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
2014 break;
2015 case TABLA_MICBIAS4:
2016 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
2017 break;
2018 default:
2019 pr_err("Error, invalid mic bias line\n");
2020 return;
2021 }
2022 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002023 usleep_range(calibration->shutdown_plug_removal,
2024 calibration->shutdown_plug_removal);
2025
2026 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
2027 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2028 tabla_codec_enable_config_mode(codec, 0);
2029
2030 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
2031}
2032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
2034{
2035 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002036
2037 tabla_codec_shutdown_hs_removal_detect(codec);
2038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039 if (!tabla->ref_cnt) {
2040 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
2041 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2042 tabla_codec_enable_clock_block(codec, 0);
2043 }
2044
2045 tabla->mbhc_polling_active = false;
2046}
2047
Bradley Rubincb1e2732011-06-23 16:49:20 -07002048static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
2049{
2050 struct tabla_priv *priv = data;
2051 struct snd_soc_codec *codec = priv->codec;
2052 int microphone_present;
2053
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002054 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002055 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2056
2057 usleep_range(priv->calibration->setup_plug_removal_delay,
2058 priv->calibration->setup_plug_removal_delay);
2059
2060 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
2061 if (priv->headset_jack) {
2062 pr_debug("%s: Reporting removal\n", __func__);
2063 snd_soc_jack_report(priv->headset_jack, 0,
2064 SND_JACK_HEADSET);
2065 }
2066 tabla_codec_shutdown_hs_removal_detect(codec);
2067 tabla_codec_enable_hs_detect(codec, 1);
2068 return IRQ_HANDLED;
2069 }
2070
2071 microphone_present = tabla_codec_setup_hs_polling(codec);
2072
2073 if (microphone_present == 0) {
2074 if (priv->headset_jack) {
2075 pr_debug("%s: Reporting insertion %d\n", __func__,
2076 SND_JACK_HEADPHONE);
2077 snd_soc_jack_report(priv->headset_jack,
2078 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
2079 }
2080 tabla_codec_shutdown_hs_polling(codec);
2081 tabla_codec_enable_hs_detect(codec, 0);
2082 } else if (microphone_present == 1) {
2083 if (priv->headset_jack) {
2084 pr_debug("%s: Reporting insertion %d\n", __func__,
2085 SND_JACK_HEADSET);
2086 snd_soc_jack_report(priv->headset_jack,
2087 SND_JACK_HEADSET, SND_JACK_HEADSET);
2088 }
2089 tabla_codec_start_hs_polling(codec);
2090 }
2091
2092 return IRQ_HANDLED;
2093}
2094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
2096{
2097 struct tabla_priv *priv = data;
2098 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002099 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100
2101 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2102 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002103 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104
2105 usleep_range(priv->calibration->shutdown_plug_removal,
2106 priv->calibration->shutdown_plug_removal);
2107
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002108 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
2109 pr_debug("removal interrupt, bias value is %d\n", bias_value);
2110
2111 if (bias_value < -90) {
2112 pr_debug("False alarm, headset not actually removed\n");
2113 tabla_codec_start_hs_polling(codec);
2114 } else {
2115 if (priv->headset_jack) {
2116 pr_debug("%s: Reporting removal\n", __func__);
2117 snd_soc_jack_report(priv->headset_jack, 0,
2118 SND_JACK_HEADSET);
2119 }
2120 tabla_codec_shutdown_hs_polling(codec);
2121
2122 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002123 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124 return IRQ_HANDLED;
2125}
2126
2127static unsigned long slimbus_value;
2128
2129static irqreturn_t tabla_slimbus_irq(int irq, void *data)
2130{
2131 struct tabla_priv *priv = data;
2132 struct snd_soc_codec *codec = priv->codec;
2133 int i, j;
2134 u8 val;
2135
2136 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
2137 slimbus_value = tabla_interface_reg_read(codec->control_data,
2138 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
2139 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
2140 val = tabla_interface_reg_read(codec->control_data,
2141 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
2142 if (val & 0x1)
2143 pr_err_ratelimited("overflow error on port %x,"
2144 " value %x\n", i*8 + j, val);
2145 if (val & 0x2)
2146 pr_err_ratelimited("underflow error on port %x,"
2147 " value %x\n", i*8 + j, val);
2148 }
2149 tabla_interface_reg_write(codec->control_data,
2150 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2151 }
2152
2153 return IRQ_HANDLED;
2154}
2155
Patrick Lai3043fba2011-08-01 14:15:57 -07002156static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2157{
2158 int rc = -EINVAL;
2159 unsigned min_mv, max_mv;
2160
2161 switch (ldoh_v) {
2162 case TABLA_LDOH_1P95_V:
2163 min_mv = 160;
2164 max_mv = 1800;
2165 break;
2166 case TABLA_LDOH_2P35_V:
2167 min_mv = 200;
2168 max_mv = 2200;
2169 break;
2170 case TABLA_LDOH_2P75_V:
2171 min_mv = 240;
2172 max_mv = 2600;
2173 break;
2174 case TABLA_LDOH_2P85_V:
2175 min_mv = 250;
2176 max_mv = 2700;
2177 break;
2178 default:
2179 goto done;
2180 }
2181
2182 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2183 goto done;
2184
2185 for (rc = 4; rc <= 44; rc++) {
2186 min_mv = max_mv * (rc) / 44;
2187 if (min_mv >= cfilt_mv) {
2188 rc -= 4;
2189 break;
2190 }
2191 }
2192done:
2193 return rc;
2194}
2195
2196static int tabla_handle_pdata(struct tabla_priv *tabla)
2197{
2198 struct snd_soc_codec *codec = tabla->codec;
2199 struct tabla_pdata *pdata = tabla->pdata;
2200 int k1, k2, k3, rc = 0;
2201
2202 if (!pdata) {
2203 rc = -ENODEV;
2204 goto done;
2205 }
2206
2207 /* Make sure settings are correct */
2208 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
2209 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
2210 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
2211 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
2212 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
2213 rc = -EINVAL;
2214 goto done;
2215 }
2216
2217 /* figure out k value */
2218 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
2219 pdata->micbias.cfilt1_mv);
2220 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
2221 pdata->micbias.cfilt2_mv);
2222 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
2223 pdata->micbias.cfilt3_mv);
2224
2225 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
2226 rc = -EINVAL;
2227 goto done;
2228 }
2229
2230 /* Set voltage level and always use LDO */
2231 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
2232 (pdata->micbias.ldoh_v << 2));
2233
2234 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
2235 (k1 << 2));
2236 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
2237 (k2 << 2));
2238 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
2239 (k3 << 2));
2240
2241 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
2242 (pdata->micbias.bias1_cfilt_sel << 5));
2243 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
2244 (pdata->micbias.bias2_cfilt_sel << 5));
2245 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
2246 (pdata->micbias.bias3_cfilt_sel << 5));
2247 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
2248 (pdata->micbias.bias4_cfilt_sel << 5));
2249
2250done:
2251 return rc;
2252}
2253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254static int tabla_codec_probe(struct snd_soc_codec *codec)
2255{
2256 struct tabla *control;
2257 struct tabla_priv *tabla;
2258 struct snd_soc_dapm_context *dapm = &codec->dapm;
2259 int ret = 0;
2260 int i;
2261 int tx_channel;
2262
2263 codec->control_data = dev_get_drvdata(codec->dev->parent);
2264 control = codec->control_data;
2265
2266 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2267 if (!tabla) {
2268 dev_err(codec->dev, "Failed to allocate private data\n");
2269 return -ENOMEM;
2270 }
2271
2272 snd_soc_codec_set_drvdata(codec, tabla);
2273
2274 tabla->ref_cnt = 0;
2275 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2276 tabla->clock_active = false;
2277 tabla->config_mode_active = false;
2278 tabla->mbhc_polling_active = false;
2279 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002280 tabla->pdata = dev_get_platdata(codec->dev->parent);
2281
2282 ret = tabla_handle_pdata(tabla);
2283
2284 if (IS_ERR_VALUE(ret)) {
2285 pr_err("%s: bad pdata\n", __func__);
2286 goto err_pdata;
2287 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288
2289 /* TODO only enable bandgap when necessary in order to save power */
2290 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2291 tabla_codec_enable_clock_block(codec, 0);
2292
2293 /* Initialize gain registers to use register gain */
2294 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
2295 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
2296 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002297 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002299 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300
2301 /* Initialize mic biases to differential mode */
2302 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
2303 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
2304 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
2305 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
2306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
2308
2309 /* Use 16 bit sample size for now */
2310 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
2311 snd_soc_update_bits(codec,
2312 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
2313 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002314 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315
2316 }
2317 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
2318 snd_soc_update_bits(codec,
2319 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
2320 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002321 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 }
2323 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
2324 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
2325
2326 snd_soc_add_controls(codec, tabla_snd_controls,
2327 ARRAY_SIZE(tabla_snd_controls));
2328 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2329 ARRAY_SIZE(tabla_dapm_widgets));
2330 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2331 snd_soc_dapm_sync(dapm);
2332
2333 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2334 tabla_hs_insert_irq, "Headset insert detect", tabla);
2335 if (ret) {
2336 pr_err("%s: Failed to request irq %d\n", __func__,
2337 TABLA_IRQ_MBHC_INSERTION);
2338 goto err_insert_irq;
2339 }
2340 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2341
2342 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2343 tabla_hs_remove_irq, "Headset remove detect", tabla);
2344 if (ret) {
2345 pr_err("%s: Failed to request irq %d\n", __func__,
2346 TABLA_IRQ_MBHC_REMOVAL);
2347 goto err_remove_irq;
2348 }
2349 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2350
2351 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002352 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 if (ret) {
2354 pr_err("%s: Failed to request irq %d\n", __func__,
2355 TABLA_IRQ_MBHC_POTENTIAL);
2356 goto err_potential_irq;
2357 }
2358 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2359
Bradley Rubincb1e2732011-06-23 16:49:20 -07002360 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2361 tabla_release_handler, "Button Release detect", tabla);
2362 if (ret) {
2363 pr_err("%s: Failed to request irq %d\n", __func__,
2364 TABLA_IRQ_MBHC_RELEASE);
2365 goto err_release_irq;
2366 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002367 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2370 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2371 if (ret) {
2372 pr_err("%s: Failed to request irq %d\n", __func__,
2373 TABLA_IRQ_SLIMBUS);
2374 goto err_slimbus_irq;
2375 }
2376
2377 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2378 tabla_interface_reg_write(codec->control_data,
2379 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2380
2381 return ret;
2382
2383err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002384 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2385err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2387err_potential_irq:
2388 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2389err_remove_irq:
2390 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2391err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07002392err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 kfree(tabla);
2394 return ret;
2395}
2396static int tabla_codec_remove(struct snd_soc_codec *codec)
2397{
2398 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2399 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002400 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2402 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2403 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2404 tabla_codec_disable_clock_block(codec);
2405 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2406 kfree(tabla);
2407 return 0;
2408}
2409static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2410 .probe = tabla_codec_probe,
2411 .remove = tabla_codec_remove,
2412 .read = tabla_read,
2413 .write = tabla_write,
2414
2415 .readable_register = tabla_readable,
2416 .volatile_register = tabla_volatile,
2417
2418 .reg_cache_size = TABLA_CACHE_SIZE,
2419 .reg_cache_default = tabla_reg_defaults,
2420 .reg_word_size = 1,
2421};
2422static int __devinit tabla_probe(struct platform_device *pdev)
2423{
2424 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2425 tabla_dai, ARRAY_SIZE(tabla_dai));
2426}
2427static int __devexit tabla_remove(struct platform_device *pdev)
2428{
2429 snd_soc_unregister_codec(&pdev->dev);
2430 return 0;
2431}
2432static struct platform_driver tabla_codec_driver = {
2433 .probe = tabla_probe,
2434 .remove = tabla_remove,
2435 .driver = {
2436 .name = "tabla_codec",
2437 .owner = THIS_MODULE,
2438 },
2439};
2440
2441static int __init tabla_codec_init(void)
2442{
2443 return platform_driver_register(&tabla_codec_driver);
2444}
2445
2446static void __exit tabla_codec_exit(void)
2447{
2448 platform_driver_unregister(&tabla_codec_driver);
2449}
2450
2451module_init(tabla_codec_init);
2452module_exit(tabla_codec_exit);
2453
2454MODULE_DESCRIPTION("Tabla codec driver");
2455MODULE_VERSION("1.0");
2456MODULE_LICENSE("GPL v2");