blob: 56de124678075b6194b3d5f7316189dae6db0456 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
759 struct snd_kcontrol *kcontrol, int event)
760{
761 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -0700762 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
763 u16 micb_int_reg;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700764 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700765 char *internal1_text = "Internal1";
766 char *internal2_text = "Internal2";
767 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768
769 pr_debug("%s %d\n", __func__, event);
770 switch (w->reg) {
771 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700773 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774 break;
775 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700777 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 break;
779 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700781 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700782 break;
783 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700784 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700785 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786 break;
787 default:
788 pr_err("%s: Error, invalid micbias register\n", __func__);
789 return -EINVAL;
790 }
791
792 switch (event) {
793 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700794 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -0700795 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700796
797 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700799 else if (strnstr(w->name, internal2_text, 30))
800 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
801 else if (strnstr(w->name, internal3_text, 30))
802 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 break;
805 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700806 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700808 else if (strnstr(w->name, internal2_text, 30))
809 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
810 else if (strnstr(w->name, internal3_text, 30))
811 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
812
Patrick Lai3043fba2011-08-01 14:15:57 -0700813 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814 break;
815 }
816
817 return 0;
818}
819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
821 struct snd_kcontrol *kcontrol, int event)
822{
823 struct snd_soc_codec *codec = w->codec;
824 u16 dec_reset_reg;
825
826 pr_debug("%s %d\n", __func__, event);
827
828 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
829 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
830 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
831 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
832 else {
833 pr_err("%s: Error, incorrect dec\n", __func__);
834 return -EINVAL;
835 }
836
837 switch (event) {
838 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
840 1 << w->shift);
841 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
842 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843 }
844 return 0;
845}
846
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700847static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 struct snd_kcontrol *kcontrol, int event)
849{
850 struct snd_soc_codec *codec = w->codec;
851
852 switch (event) {
853 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700854 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
855 1 << w->shift, 1 << w->shift);
856 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
857 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858 break;
859 }
860 return 0;
861}
862
Bradley Rubin229c6a52011-07-12 16:18:48 -0700863static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
864 struct snd_kcontrol *kcontrol, int event)
865{
866 switch (event) {
867 case SND_SOC_DAPM_POST_PMU:
868 case SND_SOC_DAPM_POST_PMD:
869 usleep_range(1000, 1000);
870 break;
871 }
872 return 0;
873}
874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
876 /*RX stuff */
877 SND_SOC_DAPM_OUTPUT("EAR"),
878
879 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
880 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
881 SND_SOC_DAPM_PRE_PMD),
882
883 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
884
Bradley Rubin229c6a52011-07-12 16:18:48 -0700885 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
886 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887
Bradley Rubin229c6a52011-07-12 16:18:48 -0700888 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
889 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890
891 /* Headphone */
892 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
893 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700894 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
895 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896
897 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700898 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
899 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900
901 /* Speaker */
902 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
905 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
906 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700907 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
908 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
909 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
911 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
912 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700913 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
914 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
915 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
916
Bradley Rubin229c6a52011-07-12 16:18:48 -0700917 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
918 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
919 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
920 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
921 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
922 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
923 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
924 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700925
Bradley Rubin229c6a52011-07-12 16:18:48 -0700926 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
927 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
928 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
929 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
930 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
931 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
932 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
933 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
934 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
935 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
936 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
937 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700938
Bradley Rubin229c6a52011-07-12 16:18:48 -0700939 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
940 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
941
942 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
943 &rx_mix1_inp1_mux),
944 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
945 &rx_mix1_inp2_mux),
946 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
947 &rx2_mix1_inp1_mux),
948 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
949 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700950 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
951 &rx3_mix1_inp1_mux),
952 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
953 &rx3_mix1_inp2_mux),
954 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
955 &rx4_mix1_inp1_mux),
956 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
957 &rx4_mix1_inp2_mux),
958 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
959 &rx5_mix1_inp1_mux),
960 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
961 &rx5_mix1_inp2_mux),
962 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
963 &rx6_mix1_inp1_mux),
964 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
965 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966
Bradley Rubin229c6a52011-07-12 16:18:48 -0700967 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
968 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
969 SND_SOC_DAPM_PRE_PMD),
970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700972
Bradley Rubine1d08622011-07-20 18:01:35 -0700973 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
974 0),
975
Bradley Rubin229c6a52011-07-12 16:18:48 -0700976 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
977 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 SND_SOC_DAPM_INPUT("AMIC1"),
980 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
981 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
982 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700983 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
984 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
985 SND_SOC_DAPM_POST_PMD),
986 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
988 SND_SOC_DAPM_POST_PMD),
989 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
990 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
991 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
992
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700993 SND_SOC_DAPM_INPUT("AMIC3"),
994 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
995 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
996 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
997
998 SND_SOC_DAPM_INPUT("AMIC4"),
999 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1000 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1001 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1002
1003 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1004 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1005 SND_SOC_DAPM_POST_PMD),
1006
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001007 SND_SOC_DAPM_INPUT("AMIC5"),
1008 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
1009 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1010
1011 SND_SOC_DAPM_INPUT("AMIC6"),
1012 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
1013 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1014
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 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 -07001016 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001018 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 -07001019 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001020
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001021 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 -07001022 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001023
1024 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 -07001025 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 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 -07001028 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029
1030 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 -07001031 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032
1033 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 -07001034 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001036 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 -07001037 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001038
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001039 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 -07001040 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001041
1042 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 -07001043 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001044
Bradley Rubin229c6a52011-07-12 16:18:48 -07001045 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1046 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1047
1048 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1049 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1050 SND_SOC_DAPM_POST_PMD),
1051
1052 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054 SND_SOC_DAPM_INPUT("AMIC2"),
1055 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
1056 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1057 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001058 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
1059 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1060 SND_SOC_DAPM_POST_PMD),
1061 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
1062 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1063 SND_SOC_DAPM_POST_PMD),
1064 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1066 SND_SOC_DAPM_POST_PMD),
1067 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
1068 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1069 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001070 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
1071 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1072 SND_SOC_DAPM_POST_PMD),
1073 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1075 SND_SOC_DAPM_POST_PMD),
1076 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1077 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1078 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1079
1080 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1081 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1082 0, 0),
1083
1084 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1085 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1086 4, 0),
1087
1088 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1089 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1090 5, 0),
1091
1092 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1093 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1094 0, 0),
1095
1096 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1097 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1098 0, 0),
1099
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001100 /* Digital Mic Inputs */
1101 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic),
1102 SND_SOC_DAPM_MIC("DMIC2", &tabla_codec_enable_dmic),
1103 SND_SOC_DAPM_MIC("DMIC3", &tabla_codec_enable_dmic),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104
1105 /* Sidetone */
1106 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1107 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1108};
1109
1110static const struct snd_soc_dapm_route audio_map[] = {
1111 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112
1113 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1114 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1115
1116 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1117 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1118
1119 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1120 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1121
1122 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1123 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001124 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001125 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1126 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1128 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001129 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1130 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001131 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1132 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133
1134 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001135 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1136 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1137 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1139 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1140
1141 /* Earpiece (RX MIX1) */
1142 {"EAR", NULL, "EAR PA"},
1143 {"EAR PA", NULL, "EAR PA Input"},
1144 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001145 {"DAC1", NULL, "CP"},
1146
1147 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1148 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1149 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150
1151 /* Headset (RX MIX1 and RX MIX2) */
1152 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001154
1155 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001157
1158 {"HPHL DAC", NULL, "CP"},
1159 {"HPHR DAC", NULL, "CP"},
1160
1161 {"ANC", NULL, "ANC1 MUX"},
1162 {"ANC", NULL, "ANC2 MUX"},
1163 {"ANC1 MUX", "ADC1", "ADC1"},
1164 {"ANC1 MUX", "ADC2", "ADC2"},
1165 {"ANC1 MUX", "ADC3", "ADC3"},
1166 {"ANC1 MUX", "ADC4", "ADC4"},
1167 {"ANC2 MUX", "ADC1", "ADC1"},
1168 {"ANC2 MUX", "ADC2", "ADC2"},
1169 {"ANC2 MUX", "ADC3", "ADC3"},
1170 {"ANC2 MUX", "ADC4", "ADC4"},
1171
Bradley Rubine1d08622011-07-20 18:01:35 -07001172 {"ANC", NULL, "CDC_CONN"},
1173
Bradley Rubin229c6a52011-07-12 16:18:48 -07001174 {"DAC1", "Switch", "RX1 CHAIN"},
1175 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1176 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001179 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001181 {"LINEOUT", NULL, "LINEOUT4"},
1182
1183 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1184 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001186 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
1187
Bradley Rubin229c6a52011-07-12 16:18:48 -07001188 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1189 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1190 {"RX1 CHAIN", NULL, "ANC"},
1191 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001192 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1193 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
Kiran Kandied246a92011-08-12 14:03:44 -07001194 {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
1195 {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001196
Bradley Rubin229c6a52011-07-12 16:18:48 -07001197 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1198 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1199 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1200 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001201 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1202 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1203 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1204 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1205 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1206 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1207 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1208 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
1209
Bradley Rubin229c6a52011-07-12 16:18:48 -07001210 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1211 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1212 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1213 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1214 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1215 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1216 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1217 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1218 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1219 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1220 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1221 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1222 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1223 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1224 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1225 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1226 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1227 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1228 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1229 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1230 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1231 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1232 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1233 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1234 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1235 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001237 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001238 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001239 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001240 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001241 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001242 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001243 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001244 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001245 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001246 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001247 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001248 {"DEC4 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001250 {"DEC5 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001252 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001253 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001254 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001255 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001256 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001257 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001258 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001259 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001260 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001261 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001262
1263 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 {"ADC1", NULL, "AMIC1"},
1265 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001266 {"ADC3", NULL, "AMIC3"},
1267 {"ADC4", NULL, "AMIC4"},
1268 {"ADC5", NULL, "AMIC5"},
1269 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 {"IIR1", NULL, "IIR1 INP1 MUX"},
1272 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001273
1274 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1275 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1276 {"MIC BIAS1 External", NULL, "LDO_H"},
1277 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1278 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1279 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1280 {"MIC BIAS2 External", NULL, "LDO_H"},
1281 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1282 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1283 {"MIC BIAS3 External", NULL, "LDO_H"},
1284 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285};
1286
1287static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1288{
1289 return tabla_reg_readable[reg];
1290}
1291
1292static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1293{
1294 /* Registers lower than 0x100 are top level registers which can be
1295 * written by the Tabla core driver.
1296 */
1297
1298 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1299 return 1;
1300
1301 return 0;
1302}
1303
1304#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1305static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1306 unsigned int value)
1307{
1308 int ret;
1309 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1310
1311 BUG_ON(reg > TABLA_MAX_REGISTER);
1312
1313 if (!tabla_volatile(codec, reg)) {
1314 pr_debug("writing to cache\n");
1315 ret = snd_soc_cache_write(codec, reg, value);
1316 if (ret != 0)
1317 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1318 reg, ret);
1319 }
1320
1321 return tabla_reg_write(codec->control_data, reg, value);
1322}
1323static unsigned int tabla_read(struct snd_soc_codec *codec,
1324 unsigned int reg)
1325{
1326 unsigned int val;
1327 int ret;
1328
1329 BUG_ON(reg > TABLA_MAX_REGISTER);
1330
1331 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1332 reg < codec->driver->reg_cache_size) {
1333 pr_debug("reading from cache\n");
1334 ret = snd_soc_cache_read(codec, reg, &val);
1335 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001336 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337 return val;
1338 } else
1339 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1340 reg, ret);
1341 }
1342
1343 val = tabla_reg_read(codec->control_data, reg);
1344 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1345 return val;
1346}
1347
1348static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1349{
1350 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1351 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1352 0x80);
1353 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1354 0x04);
1355 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1356 0x01);
1357 usleep_range(1000, 1000);
1358 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1359 0x00);
1360}
1361
1362static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1363 enum tabla_bandgap_type choice)
1364{
1365 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1366
1367 /* TODO lock resources accessed by audio streams and threaded
1368 * interrupt handlers
1369 */
1370
1371 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1372 tabla->bandgap_type);
1373
1374 if (tabla->bandgap_type == choice)
1375 return;
1376
1377 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1378 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1379 tabla_codec_enable_audio_mode_bandgap(codec);
1380 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1381 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1382 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1383 0x2);
1384 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1385 0x80);
1386 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1387 0x4);
1388 usleep_range(1000, 1000);
1389 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1390 0x00);
1391 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1392 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1393 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1394 usleep_range(100, 100);
1395 tabla_codec_enable_audio_mode_bandgap(codec);
1396 } else if (choice == TABLA_BANDGAP_OFF) {
1397 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1398 } else {
1399 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1400 }
1401 tabla->bandgap_type = choice;
1402}
1403
1404static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1405 int enable)
1406{
1407 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1408
1409 if (enable) {
1410 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1411 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1412 usleep_range(5, 5);
1413 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1414 0x80);
1415 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1416 0x80);
1417 usleep_range(10, 10);
1418 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1419 usleep_range(20, 20);
1420 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1421 } else {
1422 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1423 0);
1424 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1425 }
1426 tabla->config_mode_active = enable ? true : false;
1427
1428 return 0;
1429}
1430
1431static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1432 int config_mode)
1433{
1434 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1435
1436 pr_debug("%s\n", __func__);
1437
1438 if (config_mode) {
1439 tabla_codec_enable_config_mode(codec, 1);
1440 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1441 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1442 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1443 usleep_range(1000, 1000);
1444 } else
1445 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1446
1447 if (!config_mode && tabla->mbhc_polling_active) {
1448 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1449 tabla_codec_enable_config_mode(codec, 0);
1450
1451 }
1452
1453 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1454 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1455 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1456 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1457 usleep_range(50, 50);
1458 tabla->clock_active = true;
1459 return 0;
1460}
1461static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1462{
1463 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1464 pr_debug("%s\n", __func__);
1465 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1466 ndelay(160);
1467 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1468 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1469 tabla->clock_active = false;
1470}
1471
Bradley Rubincb1e2732011-06-23 16:49:20 -07001472static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1473{
1474 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
1475 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1476 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1477 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1478 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1479 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1480}
1481
1482static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1483{
1484 /* TODO store register values in calibration */
1485
1486 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1487 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1488
1489 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1490 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1491 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1492 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1493
1494 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1495 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1496 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1497 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1498 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1499 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1500}
1501
1502static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1503{
1504 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1505 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1506 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1507}
1508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509static int tabla_startup(struct snd_pcm_substream *substream,
1510 struct snd_soc_dai *dai)
1511{
1512 struct snd_soc_codec *codec = dai->codec;
1513 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1514 int ret = 0;
1515
1516 pr_debug("%s()\n", __func__);
1517
1518 if (!codec) {
1519 pr_err("Error, no codec found\n");
1520 return -EINVAL;
1521 }
1522 tabla->ref_cnt++;
1523
Patrick Lai3043fba2011-08-01 14:15:57 -07001524 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001525 tabla->rx_count++;
1526 if (tabla->rx_count == 1)
1527 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1528 0x80);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 }
1530
1531 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001532 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1534 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001535 tabla_codec_calibrate_hs_polling(codec);
1536 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 }
1538
1539 return ret;
1540}
1541
1542static void tabla_shutdown(struct snd_pcm_substream *substream,
1543 struct snd_soc_dai *dai)
1544{
1545 struct snd_soc_codec *codec = dai->codec;
1546 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1547
1548 pr_debug("%s()\n", __func__);
1549
1550 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1551 /* Disable LDO */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001552 } else {
1553 tabla->rx_count--;
1554 if (!tabla->rx_count)
1555 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1556 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 }
1558
1559 if (!tabla->ref_cnt) {
1560 pr_err("Error, trying to shutdown codec when already down\n");
1561 return;
1562 }
1563 tabla->ref_cnt--;
1564
1565 if (tabla->mbhc_polling_active) {
1566 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001567 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 tabla_codec_enable_bandgap(codec,
1569 TABLA_BANDGAP_MBHC_MODE);
1570 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1571 0x80);
1572 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001573 tabla_codec_calibrate_hs_polling(codec);
1574 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 }
1576 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1577 }
1578}
1579
1580static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1581{
1582 struct snd_soc_codec *codec = codec_dai->codec;
1583
1584 pr_debug("%s %d\n", __func__, mute);
1585
1586 /* TODO mute TX */
1587 if (mute)
1588 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1589 else
1590 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1591
1592 return 0;
1593}
1594
1595static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1596 int clk_id, unsigned int freq, int dir)
1597{
1598 pr_debug("%s\n", __func__);
1599 return 0;
1600}
1601
1602static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1603{
1604 pr_debug("%s\n", __func__);
1605 return 0;
1606}
1607
1608static int tabla_hw_params(struct snd_pcm_substream *substream,
1609 struct snd_pcm_hw_params *params,
1610 struct snd_soc_dai *dai)
1611{
1612 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1613 return 0;
1614}
1615
1616static struct snd_soc_dai_ops tabla_dai_ops = {
1617 .startup = tabla_startup,
1618 .shutdown = tabla_shutdown,
1619 .hw_params = tabla_hw_params,
1620 .set_sysclk = tabla_set_dai_sysclk,
1621 .set_fmt = tabla_set_dai_fmt,
1622 .digital_mute = tabla_digital_mute,
1623};
1624
1625static struct snd_soc_dai_driver tabla_dai[] = {
1626 {
1627 .name = "tabla_rx1",
1628 .id = 1,
1629 .playback = {
1630 .stream_name = "AIF1 Playback",
1631 .rates = SNDRV_PCM_RATE_8000_48000,
1632 .formats = TABLA_FORMATS,
1633 .rate_max = 48000,
1634 .rate_min = 8000,
1635 .channels_min = 1,
1636 .channels_max = 2,
1637 },
1638 .ops = &tabla_dai_ops,
1639 },
1640 {
1641 .name = "tabla_tx1",
1642 .id = 2,
1643 .capture = {
1644 .stream_name = "AIF1 Capture",
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};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001655static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07001656{
1657 u8 bias_msb, bias_lsb;
1658 short bias_value;
1659
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001660 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1661 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1662 bias_value = (bias_msb << 8) | bias_lsb;
1663 return bias_value;
1664}
1665
1666static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
1667{
1668 u8 bias_msb, bias_lsb;
1669 short bias_value;
1670
1671 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1672 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1673 bias_value = (bias_msb << 8) | bias_lsb;
1674 return bias_value;
1675}
1676
1677static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1678 int dce)
1679{
1680 short bias_value;
1681
Bradley Rubincb1e2732011-06-23 16:49:20 -07001682 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001683 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1684 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1685 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1686 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1687 usleep_range(60000, 60000);
1688 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001689 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001690 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001691 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1692 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001693 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001694 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001695 usleep_range(50, 50);
1696 bias_value = tabla_codec_read_sta_result(codec);
1697 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1698 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001699 }
1700
Bradley Rubincb1e2732011-06-23 16:49:20 -07001701 pr_debug("read microphone bias value %x\n", bias_value);
1702 return bias_value;
1703}
1704
1705static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706{
1707 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1708 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Patrick Lai3043fba2011-08-01 14:15:57 -07001709 int micbias_ctl_reg, micbias_cfilt_ctl_reg,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001710 micbias_mbhc_reg;
1711 short bias_value, threshold_no_mic;
Patrick Lai3043fba2011-08-01 14:15:57 -07001712 unsigned int cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713
1714 if (!calibration) {
1715 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001716 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717 }
1718
1719 tabla->mbhc_polling_active = true;
1720
1721 if (!tabla->ref_cnt) {
1722 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1723 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1724 tabla_codec_enable_clock_block(codec, 1);
1725 }
1726
1727 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1730
Patrick Lai3043fba2011-08-01 14:15:57 -07001731 /* select cfilt separately from the micbias line in the platform data */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 switch (calibration->bias) {
1733 case TABLA_MICBIAS1:
1734 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001735 cfilt_sel = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001736 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 break;
1738 case TABLA_MICBIAS2:
1739 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001740 cfilt_sel = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001741 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 break;
1743 case TABLA_MICBIAS3:
1744 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001745 cfilt_sel = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001746 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 break;
1748 case TABLA_MICBIAS4:
1749 pr_err("%s: Error, microphone bias 4 not supported\n",
1750 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001751 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 default:
1753 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001754 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 }
Patrick Lai3043fba2011-08-01 14:15:57 -07001756
1757 switch (cfilt_sel) {
1758 case TABLA_CFILT1_SEL:
1759 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1760 break;
1761 case TABLA_CFILT2_SEL:
1762 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1763 break;
1764 case TABLA_CFILT3_SEL:
1765 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1766 break;
1767 default: /* default should not happen as check should have been done */
1768 return -EINVAL;
1769 }
1770
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001771 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772
Bradley Rubincb1e2732011-06-23 16:49:20 -07001773 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774
1775 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001776 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777
1778 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1779 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1780 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1781
1782 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001783 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1784 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785
Bradley Rubincb1e2732011-06-23 16:49:20 -07001786 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1788
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001789 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001790 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1791
1792 tabla_codec_calibrate_hs_polling(codec);
1793
1794 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001795 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1796 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001797 threshold_no_mic = 0xF7F6;
1798
1799 if (bias_value < threshold_no_mic) {
1800 pr_debug("headphone detected, micbias %x\n", bias_value);
1801 return 0;
1802 } else {
1803 pr_debug("headset detected, micbias %x\n", bias_value);
1804 return 1;
1805 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806}
1807
1808static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1809 int insertion)
1810{
1811 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1812 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1813 int central_bias_enabled = 0;
1814 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1815
1816 if (!calibration) {
1817 pr_err("Error, no tabla calibration\n");
1818 return -EINVAL;
1819 }
1820
1821 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1822
1823 if (insertion)
1824 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1825 else
1826 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1827
1828 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1829 if (!(tabla->clock_active)) {
1830 tabla_codec_enable_config_mode(codec, 1);
1831 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001832 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 usleep_range(calibration->shutdown_plug_removal,
1834 calibration->shutdown_plug_removal);
1835 tabla_codec_enable_config_mode(codec, 0);
1836 } else
1837 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001838 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 }
1840
1841 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1842 calibration->hph_current << 2);
1843
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001844 /* Turn off HPH PAs during insertion detection to avoid false
1845 * insertion interrupts
1846 */
1847 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1849
1850 switch (calibration->bias) {
1851 case TABLA_MICBIAS1:
1852 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1853 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1854 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1855 break;
1856 case TABLA_MICBIAS2:
1857 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1858 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1859 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1860 break;
1861 case TABLA_MICBIAS3:
1862 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1863 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1864 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1865 break;
1866 case TABLA_MICBIAS4:
1867 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1868 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1869 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1870 break;
1871 default:
1872 pr_err("Error, invalid mic bias line\n");
1873 return -EINVAL;
1874 }
1875 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1876 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1877
1878 /* If central bandgap disabled */
1879 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1880 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1881 usleep_range(calibration->bg_fast_settle,
1882 calibration->bg_fast_settle);
1883 central_bias_enabled = 1;
1884 }
1885
1886 /* If LDO_H disabled */
1887 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1888 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1889 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1890 usleep_range(calibration->tldoh, calibration->tldoh);
1891 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1892
1893 if (central_bias_enabled)
1894 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1895 }
1896 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1897 calibration->mic_current << 5);
1898 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1899 usleep_range(calibration->mic_pid, calibration->mic_pid);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1902
1903 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1904
1905 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1906 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1907 return 0;
1908}
1909
Bradley Rubincb1e2732011-06-23 16:49:20 -07001910int tabla_hs_detect(struct snd_soc_codec *codec,
1911 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 struct tabla_mbhc_calibration *calibration)
1913{
1914 struct tabla_priv *tabla;
1915 if (!codec || !calibration) {
1916 pr_err("Error: no codec or calibration\n");
1917 return -EINVAL;
1918 }
1919 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001920 tabla->headset_jack = headset_jack;
1921 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001922 tabla->calibration = calibration;
1923
1924 return tabla_codec_enable_hs_detect(codec, 1);
1925}
1926EXPORT_SYMBOL_GPL(tabla_hs_detect);
1927
Bradley Rubincb1e2732011-06-23 16:49:20 -07001928static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929{
1930 struct tabla_priv *priv = data;
1931 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001932 short bias_value;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001933
1934 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1935 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1936
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001937 bias_value = tabla_codec_read_dce_result(codec);
1938 pr_debug("button press interrupt, bias value is %d\n", bias_value);
1939
Bradley Rubincb1e2732011-06-23 16:49:20 -07001940 if (priv->button_jack)
1941 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1942 SND_JACK_BTN_0);
1943
1944 priv->buttons_pressed |= SND_JACK_BTN_0;
1945 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1946 0x09);
1947 usleep_range(100000, 100000);
1948
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001949 return IRQ_HANDLED;
1950}
1951
Bradley Rubincb1e2732011-06-23 16:49:20 -07001952static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953{
1954 struct tabla_priv *priv = data;
1955 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001956 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1957 pr_debug("%s: Button released\n", __func__);
1958 if (priv->button_jack)
1959 snd_soc_jack_report(priv->button_jack, 0,
1960 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961
Bradley Rubincb1e2732011-06-23 16:49:20 -07001962 priv->buttons_pressed &= ~SND_JACK_BTN_0;
1963 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1964 0x08);
1965 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967
1968 return IRQ_HANDLED;
1969}
1970
Bradley Rubincb1e2732011-06-23 16:49:20 -07001971static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1972{
1973 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1974 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1975 int micbias_mbhc_reg;
1976
1977 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1978 tabla_codec_enable_config_mode(codec, 1);
1979
1980 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1981 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001982
1983 switch (calibration->bias) {
1984 case TABLA_MICBIAS1:
1985 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1986 break;
1987 case TABLA_MICBIAS2:
1988 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1989 break;
1990 case TABLA_MICBIAS3:
1991 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1992 break;
1993 case TABLA_MICBIAS4:
1994 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1995 break;
1996 default:
1997 pr_err("Error, invalid mic bias line\n");
1998 return;
1999 }
2000 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002001 usleep_range(calibration->shutdown_plug_removal,
2002 calibration->shutdown_plug_removal);
2003
2004 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
2005 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
2006 tabla_codec_enable_config_mode(codec, 0);
2007
2008 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
2009}
2010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
2012{
2013 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002014
2015 tabla_codec_shutdown_hs_removal_detect(codec);
2016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 if (!tabla->ref_cnt) {
2018 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
2019 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2020 tabla_codec_enable_clock_block(codec, 0);
2021 }
2022
2023 tabla->mbhc_polling_active = false;
2024}
2025
Bradley Rubincb1e2732011-06-23 16:49:20 -07002026static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
2027{
2028 struct tabla_priv *priv = data;
2029 struct snd_soc_codec *codec = priv->codec;
2030 int microphone_present;
2031
2032 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2033
2034 usleep_range(priv->calibration->setup_plug_removal_delay,
2035 priv->calibration->setup_plug_removal_delay);
2036
2037 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
2038 if (priv->headset_jack) {
2039 pr_debug("%s: Reporting removal\n", __func__);
2040 snd_soc_jack_report(priv->headset_jack, 0,
2041 SND_JACK_HEADSET);
2042 }
2043 tabla_codec_shutdown_hs_removal_detect(codec);
2044 tabla_codec_enable_hs_detect(codec, 1);
2045 return IRQ_HANDLED;
2046 }
2047
2048 microphone_present = tabla_codec_setup_hs_polling(codec);
2049
2050 if (microphone_present == 0) {
2051 if (priv->headset_jack) {
2052 pr_debug("%s: Reporting insertion %d\n", __func__,
2053 SND_JACK_HEADPHONE);
2054 snd_soc_jack_report(priv->headset_jack,
2055 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
2056 }
2057 tabla_codec_shutdown_hs_polling(codec);
2058 tabla_codec_enable_hs_detect(codec, 0);
2059 } else if (microphone_present == 1) {
2060 if (priv->headset_jack) {
2061 pr_debug("%s: Reporting insertion %d\n", __func__,
2062 SND_JACK_HEADSET);
2063 snd_soc_jack_report(priv->headset_jack,
2064 SND_JACK_HEADSET, SND_JACK_HEADSET);
2065 }
2066 tabla_codec_start_hs_polling(codec);
2067 }
2068
2069 return IRQ_HANDLED;
2070}
2071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
2073{
2074 struct tabla_priv *priv = data;
2075 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002076 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077
2078 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2079 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2080
2081 usleep_range(priv->calibration->shutdown_plug_removal,
2082 priv->calibration->shutdown_plug_removal);
2083
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002084 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
2085 pr_debug("removal interrupt, bias value is %d\n", bias_value);
2086
2087 if (bias_value < -90) {
2088 pr_debug("False alarm, headset not actually removed\n");
2089 tabla_codec_start_hs_polling(codec);
2090 } else {
2091 if (priv->headset_jack) {
2092 pr_debug("%s: Reporting removal\n", __func__);
2093 snd_soc_jack_report(priv->headset_jack, 0,
2094 SND_JACK_HEADSET);
2095 }
2096 tabla_codec_shutdown_hs_polling(codec);
2097
2098 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002099 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 return IRQ_HANDLED;
2101}
2102
2103static unsigned long slimbus_value;
2104
2105static irqreturn_t tabla_slimbus_irq(int irq, void *data)
2106{
2107 struct tabla_priv *priv = data;
2108 struct snd_soc_codec *codec = priv->codec;
2109 int i, j;
2110 u8 val;
2111
2112 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
2113 slimbus_value = tabla_interface_reg_read(codec->control_data,
2114 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
2115 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
2116 val = tabla_interface_reg_read(codec->control_data,
2117 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
2118 if (val & 0x1)
2119 pr_err_ratelimited("overflow error on port %x,"
2120 " value %x\n", i*8 + j, val);
2121 if (val & 0x2)
2122 pr_err_ratelimited("underflow error on port %x,"
2123 " value %x\n", i*8 + j, val);
2124 }
2125 tabla_interface_reg_write(codec->control_data,
2126 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2127 }
2128
2129 return IRQ_HANDLED;
2130}
2131
Patrick Lai3043fba2011-08-01 14:15:57 -07002132static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2133{
2134 int rc = -EINVAL;
2135 unsigned min_mv, max_mv;
2136
2137 switch (ldoh_v) {
2138 case TABLA_LDOH_1P95_V:
2139 min_mv = 160;
2140 max_mv = 1800;
2141 break;
2142 case TABLA_LDOH_2P35_V:
2143 min_mv = 200;
2144 max_mv = 2200;
2145 break;
2146 case TABLA_LDOH_2P75_V:
2147 min_mv = 240;
2148 max_mv = 2600;
2149 break;
2150 case TABLA_LDOH_2P85_V:
2151 min_mv = 250;
2152 max_mv = 2700;
2153 break;
2154 default:
2155 goto done;
2156 }
2157
2158 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2159 goto done;
2160
2161 for (rc = 4; rc <= 44; rc++) {
2162 min_mv = max_mv * (rc) / 44;
2163 if (min_mv >= cfilt_mv) {
2164 rc -= 4;
2165 break;
2166 }
2167 }
2168done:
2169 return rc;
2170}
2171
2172static int tabla_handle_pdata(struct tabla_priv *tabla)
2173{
2174 struct snd_soc_codec *codec = tabla->codec;
2175 struct tabla_pdata *pdata = tabla->pdata;
2176 int k1, k2, k3, rc = 0;
2177
2178 if (!pdata) {
2179 rc = -ENODEV;
2180 goto done;
2181 }
2182
2183 /* Make sure settings are correct */
2184 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
2185 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
2186 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
2187 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
2188 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
2189 rc = -EINVAL;
2190 goto done;
2191 }
2192
2193 /* figure out k value */
2194 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
2195 pdata->micbias.cfilt1_mv);
2196 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
2197 pdata->micbias.cfilt2_mv);
2198 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
2199 pdata->micbias.cfilt3_mv);
2200
2201 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
2202 rc = -EINVAL;
2203 goto done;
2204 }
2205
2206 /* Set voltage level and always use LDO */
2207 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
2208 (pdata->micbias.ldoh_v << 2));
2209
2210 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
2211 (k1 << 2));
2212 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
2213 (k2 << 2));
2214 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
2215 (k3 << 2));
2216
2217 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
2218 (pdata->micbias.bias1_cfilt_sel << 5));
2219 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
2220 (pdata->micbias.bias2_cfilt_sel << 5));
2221 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
2222 (pdata->micbias.bias3_cfilt_sel << 5));
2223 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
2224 (pdata->micbias.bias4_cfilt_sel << 5));
2225
2226done:
2227 return rc;
2228}
2229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230static int tabla_codec_probe(struct snd_soc_codec *codec)
2231{
2232 struct tabla *control;
2233 struct tabla_priv *tabla;
2234 struct snd_soc_dapm_context *dapm = &codec->dapm;
2235 int ret = 0;
2236 int i;
2237 int tx_channel;
2238
2239 codec->control_data = dev_get_drvdata(codec->dev->parent);
2240 control = codec->control_data;
2241
2242 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2243 if (!tabla) {
2244 dev_err(codec->dev, "Failed to allocate private data\n");
2245 return -ENOMEM;
2246 }
2247
2248 snd_soc_codec_set_drvdata(codec, tabla);
2249
2250 tabla->ref_cnt = 0;
2251 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2252 tabla->clock_active = false;
2253 tabla->config_mode_active = false;
2254 tabla->mbhc_polling_active = false;
2255 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002256 tabla->pdata = dev_get_platdata(codec->dev->parent);
2257
2258 ret = tabla_handle_pdata(tabla);
2259
2260 if (IS_ERR_VALUE(ret)) {
2261 pr_err("%s: bad pdata\n", __func__);
2262 goto err_pdata;
2263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264
2265 /* TODO only enable bandgap when necessary in order to save power */
2266 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2267 tabla_codec_enable_clock_block(codec, 0);
2268
2269 /* Initialize gain registers to use register gain */
2270 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
2271 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
2272 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002273 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002275 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276
2277 /* Initialize mic biases to differential mode */
2278 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
2279 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
2280 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
2281 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
2282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
2284
2285 /* Use 16 bit sample size for now */
2286 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
2287 snd_soc_update_bits(codec,
2288 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
2289 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002290 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291
2292 }
2293 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
2294 snd_soc_update_bits(codec,
2295 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
2296 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002297 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 }
2299 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
2300 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
2301
2302 snd_soc_add_controls(codec, tabla_snd_controls,
2303 ARRAY_SIZE(tabla_snd_controls));
2304 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2305 ARRAY_SIZE(tabla_dapm_widgets));
2306 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2307 snd_soc_dapm_sync(dapm);
2308
2309 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2310 tabla_hs_insert_irq, "Headset insert detect", tabla);
2311 if (ret) {
2312 pr_err("%s: Failed to request irq %d\n", __func__,
2313 TABLA_IRQ_MBHC_INSERTION);
2314 goto err_insert_irq;
2315 }
2316 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2317
2318 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2319 tabla_hs_remove_irq, "Headset remove detect", tabla);
2320 if (ret) {
2321 pr_err("%s: Failed to request irq %d\n", __func__,
2322 TABLA_IRQ_MBHC_REMOVAL);
2323 goto err_remove_irq;
2324 }
2325 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2326
2327 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002328 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 if (ret) {
2330 pr_err("%s: Failed to request irq %d\n", __func__,
2331 TABLA_IRQ_MBHC_POTENTIAL);
2332 goto err_potential_irq;
2333 }
2334 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2335
Bradley Rubincb1e2732011-06-23 16:49:20 -07002336 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2337 tabla_release_handler, "Button Release detect", tabla);
2338 if (ret) {
2339 pr_err("%s: Failed to request irq %d\n", __func__,
2340 TABLA_IRQ_MBHC_RELEASE);
2341 goto err_release_irq;
2342 }
2343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2345 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2346 if (ret) {
2347 pr_err("%s: Failed to request irq %d\n", __func__,
2348 TABLA_IRQ_SLIMBUS);
2349 goto err_slimbus_irq;
2350 }
2351
2352 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2353 tabla_interface_reg_write(codec->control_data,
2354 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2355
2356 return ret;
2357
2358err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002359 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2360err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2362err_potential_irq:
2363 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2364err_remove_irq:
2365 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2366err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07002367err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 kfree(tabla);
2369 return ret;
2370}
2371static int tabla_codec_remove(struct snd_soc_codec *codec)
2372{
2373 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2374 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002375 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2377 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2378 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2379 tabla_codec_disable_clock_block(codec);
2380 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2381 kfree(tabla);
2382 return 0;
2383}
2384static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2385 .probe = tabla_codec_probe,
2386 .remove = tabla_codec_remove,
2387 .read = tabla_read,
2388 .write = tabla_write,
2389
2390 .readable_register = tabla_readable,
2391 .volatile_register = tabla_volatile,
2392
2393 .reg_cache_size = TABLA_CACHE_SIZE,
2394 .reg_cache_default = tabla_reg_defaults,
2395 .reg_word_size = 1,
2396};
2397static int __devinit tabla_probe(struct platform_device *pdev)
2398{
2399 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2400 tabla_dai, ARRAY_SIZE(tabla_dai));
2401}
2402static int __devexit tabla_remove(struct platform_device *pdev)
2403{
2404 snd_soc_unregister_codec(&pdev->dev);
2405 return 0;
2406}
2407static struct platform_driver tabla_codec_driver = {
2408 .probe = tabla_probe,
2409 .remove = tabla_remove,
2410 .driver = {
2411 .name = "tabla_codec",
2412 .owner = THIS_MODULE,
2413 },
2414};
2415
2416static int __init tabla_codec_init(void)
2417{
2418 return platform_driver_register(&tabla_codec_driver);
2419}
2420
2421static void __exit tabla_codec_exit(void)
2422{
2423 platform_driver_unregister(&tabla_codec_driver);
2424}
2425
2426module_init(tabla_codec_init);
2427module_exit(tabla_codec_exit);
2428
2429MODULE_DESCRIPTION("Tabla codec driver");
2430MODULE_VERSION("1.0");
2431MODULE_LICENSE("GPL v2");