blob: eec8b31ef168d90fc18077be9a63249bd4508b11 [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
60 u32 anc_writes_size;
61 u32 *anc_writes;
Patrick Lai3043fba2011-08-01 14:15:57 -070062 struct tabla_pdata *pdata;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063};
64
65static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
66 struct snd_kcontrol *kcontrol, int event)
67{
68 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069
70 pr_debug("%s %d\n", __func__, event);
71 switch (event) {
72 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
74 0x01);
75 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
76 usleep_range(200, 200);
77 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
78 break;
79 case SND_SOC_DAPM_PRE_PMD:
80 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
81 0x10);
82 usleep_range(20, 20);
83 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
84 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
85 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
86 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
87 0x00);
88 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 break;
90 }
91 return 0;
92}
93
94static const struct snd_kcontrol_new tabla_snd_controls[] = {
95 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
96 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -070097 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
98 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
100 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700101 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
102 line_gain),
103
104 SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
105 SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
106 SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
107 SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
108 SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
109 SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
112 line_gain),
113 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
114 line_gain),
115
116 SOC_SINGLE_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL, 0,
117 100, 0, digital_gain),
118 SOC_SINGLE_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL, 0,
119 100, 0, digital_gain),
120
121 SOC_SINGLE_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, 100, 0,
122 digital_gain),
123 SOC_SINGLE_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, 100, 0,
124 digital_gain),
125
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700126 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
127 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700128 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
129 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700130 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
131 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132
133 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700134 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
135 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136};
137
138static const char *rx_mix1_text[] = {
139 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
140 "RX5", "RX6", "RX7"
141};
142
143static const char *sb_tx1_mux_text[] = {
144 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
145 "DEC1"
146};
147
148static const char *sb_tx5_mux_text[] = {
149 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
150 "DEC5"
151};
152
153static const char *sb_tx6_mux_text[] = {
154 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
155 "DEC6"
156};
157
158static const char const *sb_tx7_to_tx10_mux_text[] = {
159 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
160 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
161 "DEC9", "DEC10"
162};
163
164static const char *dec1_mux_text[] = {
165 "ZERO", "DMIC1", "ADC6",
166};
167
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700168static const char *dec2_mux_text[] = {
169 "ZERO", "DMIC2", "ADC5",
170};
171
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700172static const char *dec3_mux_text[] = {
173 "ZERO", "DMIC3", "ADC4",
174};
175
176static const char *dec4_mux_text[] = {
177 "ZERO", "DMIC4", "ADC3",
178};
179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180static const char *dec5_mux_text[] = {
181 "ZERO", "DMIC5", "ADC2",
182};
183
184static const char *dec6_mux_text[] = {
185 "ZERO", "DMIC6", "ADC1",
186};
187
188static const char const *dec7_mux_text[] = {
189 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
190};
191
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700192static const char *dec8_mux_text[] = {
193 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
194};
195
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700196static const char *dec9_mux_text[] = {
197 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
198};
199
200static const char *dec10_mux_text[] = {
201 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
202};
203
Bradley Rubin229c6a52011-07-12 16:18:48 -0700204static const char const *anc_mux_text[] = {
205 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
206 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
207};
208
209static const char const *anc1_fb_mux_text[] = {
210 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
211};
212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213static const char *iir1_inp1_text[] = {
214 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
215 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
216};
217
218static const struct soc_enum rx_mix1_inp1_chain_enum =
219 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
220
Bradley Rubin229c6a52011-07-12 16:18:48 -0700221static const struct soc_enum rx_mix1_inp2_chain_enum =
222 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224static const struct soc_enum rx2_mix1_inp1_chain_enum =
225 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
226
Bradley Rubin229c6a52011-07-12 16:18:48 -0700227static const struct soc_enum rx2_mix1_inp2_chain_enum =
228 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230static const struct soc_enum rx3_mix1_inp1_chain_enum =
231 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
232
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700233static const struct soc_enum rx3_mix1_inp2_chain_enum =
234 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236static const struct soc_enum rx4_mix1_inp1_chain_enum =
237 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
238
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700239static const struct soc_enum rx4_mix1_inp2_chain_enum =
240 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242static const struct soc_enum rx5_mix1_inp1_chain_enum =
243 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
244
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700245static const struct soc_enum rx5_mix1_inp2_chain_enum =
246 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
247
248static const struct soc_enum rx6_mix1_inp1_chain_enum =
249 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
250
251static const struct soc_enum rx6_mix1_inp2_chain_enum =
252 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254static const struct soc_enum sb_tx5_mux_enum =
255 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
256
257static const struct soc_enum sb_tx6_mux_enum =
258 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
259
260static const struct soc_enum sb_tx7_mux_enum =
261 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
262 sb_tx7_to_tx10_mux_text);
263
264static const struct soc_enum sb_tx8_mux_enum =
265 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
266 sb_tx7_to_tx10_mux_text);
267
268static const struct soc_enum sb_tx1_mux_enum =
269 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
270
271static const struct soc_enum dec1_mux_enum =
272 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
273
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700274static const struct soc_enum dec2_mux_enum =
275 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
276
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700277static const struct soc_enum dec3_mux_enum =
278 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
279
280static const struct soc_enum dec4_mux_enum =
281 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283static const struct soc_enum dec5_mux_enum =
284 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
285
286static const struct soc_enum dec6_mux_enum =
287 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
288
289static const struct soc_enum dec7_mux_enum =
290 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
291
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700292static const struct soc_enum dec8_mux_enum =
293 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
294
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700295static const struct soc_enum dec9_mux_enum =
296 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
297
298static const struct soc_enum dec10_mux_enum =
299 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
300
Bradley Rubin229c6a52011-07-12 16:18:48 -0700301static const struct soc_enum anc1_mux_enum =
302 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
303
304static const struct soc_enum anc2_mux_enum =
305 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
306
307static const struct soc_enum anc1_fb_mux_enum =
308 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310static const struct soc_enum iir1_inp1_mux_enum =
311 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
312
313static const struct snd_kcontrol_new rx_mix1_inp1_mux =
314 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
315
Bradley Rubin229c6a52011-07-12 16:18:48 -0700316static const struct snd_kcontrol_new rx_mix1_inp2_mux =
317 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
320 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
321
Bradley Rubin229c6a52011-07-12 16:18:48 -0700322static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
323 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
326 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
327
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700328static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
329 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
332 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
333
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700334static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
335 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
338 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
339
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700340static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
341 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
342
343static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
344 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
345
346static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
347 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349static const struct snd_kcontrol_new sb_tx5_mux =
350 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
351
352static const struct snd_kcontrol_new sb_tx6_mux =
353 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
354
355static const struct snd_kcontrol_new sb_tx7_mux =
356 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
357
358static const struct snd_kcontrol_new sb_tx8_mux =
359 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
360
361static const struct snd_kcontrol_new sb_tx1_mux =
362 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
363
364static const struct snd_kcontrol_new dec1_mux =
365 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
366
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700367static const struct snd_kcontrol_new dec2_mux =
368 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
369
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700370static const struct snd_kcontrol_new dec3_mux =
371 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
372
373static const struct snd_kcontrol_new dec4_mux =
374 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
375
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376static const struct snd_kcontrol_new dec5_mux =
377 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
378
379static const struct snd_kcontrol_new dec6_mux =
380 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
381
382static const struct snd_kcontrol_new dec7_mux =
383 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
384
Bradley Rubin229c6a52011-07-12 16:18:48 -0700385static const struct snd_kcontrol_new anc1_mux =
386 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700387static const struct snd_kcontrol_new dec8_mux =
388 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
389
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700390static const struct snd_kcontrol_new dec9_mux =
391 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
392
393static const struct snd_kcontrol_new dec10_mux =
394 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396static const struct snd_kcontrol_new iir1_inp1_mux =
397 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
398
Bradley Rubin229c6a52011-07-12 16:18:48 -0700399static const struct snd_kcontrol_new anc2_mux =
400 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401
Bradley Rubin229c6a52011-07-12 16:18:48 -0700402static const struct snd_kcontrol_new anc1_fb_mux =
403 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404
Bradley Rubin229c6a52011-07-12 16:18:48 -0700405static const struct snd_kcontrol_new dac1_switch[] = {
406 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
407};
408static const struct snd_kcontrol_new hphl_switch[] = {
409 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
410};
411static const struct snd_kcontrol_new hphr_switch[] = {
412 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
413};
414static const struct snd_kcontrol_new lineout1_switch[] = {
415 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
416};
417static const struct snd_kcontrol_new lineout2_switch[] = {
418 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
419};
420static const struct snd_kcontrol_new lineout3_switch[] = {
421 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
422};
423static const struct snd_kcontrol_new lineout4_switch[] = {
424 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
425};
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
428 int enable)
429{
430 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
431
432 pr_debug("%s %d\n", __func__, enable);
433
434 if (enable) {
435 tabla->adc_count++;
436 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
437 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
438 } else {
439 tabla->adc_count--;
440 if (!tabla->adc_count) {
441 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
442 0x2, 0x0);
443 if (!tabla->mbhc_polling_active)
444 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
445 0xE0, 0x0);
446 }
447 }
448}
449
450static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
451 struct snd_kcontrol *kcontrol, int event)
452{
453 struct snd_soc_codec *codec = w->codec;
454 u16 adc_reg;
455
456 pr_debug("%s %d\n", __func__, event);
457
458 if (w->reg == TABLA_A_TX_1_2_EN)
459 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
460 else if (w->reg == TABLA_A_TX_3_4_EN)
461 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
462 else if (w->reg == TABLA_A_TX_5_6_EN)
463 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
464 else {
465 pr_err("%s: Error, invalid adc register\n", __func__);
466 return -EINVAL;
467 }
468
469 switch (event) {
470 case SND_SOC_DAPM_PRE_PMU:
471 tabla_codec_enable_adc_block(codec, 1);
472 break;
473 case SND_SOC_DAPM_POST_PMU:
474 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
475 1 << w->shift);
476 usleep_range(1000, 1000);
477 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
478 usleep_range(1000, 1000);
479 break;
480 case SND_SOC_DAPM_POST_PMD:
481 tabla_codec_enable_adc_block(codec, 0);
482 break;
483 }
484 return 0;
485}
486
487static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
488 struct snd_kcontrol *kcontrol, int event)
489{
490 struct snd_soc_codec *codec = w->codec;
491
492 pr_debug("%s %d\n", __func__, event);
493 switch (event) {
494 case SND_SOC_DAPM_PRE_PMU:
495 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
496 break;
497 case SND_SOC_DAPM_POST_PMD:
498 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
499 break;
500 }
501 return 0;
502}
503
504static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
505 struct snd_kcontrol *kcontrol, int event)
506{
507 struct snd_soc_codec *codec = w->codec;
508 u16 lineout_gain_reg;
509
510 pr_debug("%s %d\n", __func__, event);
511
512 switch (w->shift) {
513 case 0:
514 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
515 break;
516 case 1:
517 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
518 break;
519 case 2:
520 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
521 break;
522 case 3:
523 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
524 break;
525 case 4:
526 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
527 break;
528 default:
529 pr_err("%s: Error, incorrect lineout register value\n",
530 __func__);
531 return -EINVAL;
532 }
533
534 switch (event) {
535 case SND_SOC_DAPM_PRE_PMU:
536 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
537 break;
538 case SND_SOC_DAPM_POST_PMU:
539 usleep_range(40000, 40000);
540 break;
541 case SND_SOC_DAPM_POST_PMD:
542 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
543 break;
544 }
545 return 0;
546}
547
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700548
549static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 struct snd_kcontrol *kcontrol, int event)
551{
552 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700553 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
554 u8 dmic_clk_sel, dmic_clk_en;
555
556 if (!strncmp(w->name, "DMIC1", 5)) {
557
558 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL;
559 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL;
560 dmic_clk_sel = 0x2;
561 dmic_clk_en = 0x1;
562
563 } else if (!strncmp(w->name, "DMIC2", 5)) {
564
565 tx_mux_ctl_reg = TABLA_A_CDC_TX2_MUX_CTL;
566 tx_dmic_ctl_reg = TABLA_A_CDC_TX2_DMIC_CTL;
567 dmic_clk_sel = 0x2;
568 dmic_clk_en = 0x1;
569
570 } else if (!strncmp(w->name, "DMIC3", 5)) {
571
572 tx_mux_ctl_reg = TABLA_A_CDC_TX3_MUX_CTL;
573 tx_dmic_ctl_reg = TABLA_A_CDC_TX3_DMIC_CTL;
574 dmic_clk_sel = 0x8;
575 dmic_clk_en = 0x4;
576
577 } else {
578 pr_err("%s: Error, DMIC = %s\n", __func__, w->name);
579 return -EINVAL;
580 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581
582 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 switch (event) {
585 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700586 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
587
588 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
589 dmic_clk_sel, dmic_clk_sel);
590
591 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
592
593 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
594 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 break;
596 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700597 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
598 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 break;
600 }
601 return 0;
602}
603
Bradley Rubin229c6a52011-07-12 16:18:48 -0700604static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
605 struct snd_kcontrol *kcontrol, int event)
606{
607 struct snd_soc_codec *codec = w->codec;
608 const char *filename;
609 const struct firmware *fw;
610 int i;
611 int ret;
612 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
613 u16 reg;
614 u8 mask, val, old_val;
615
616 pr_debug("%s %d\n", __func__, event);
617 switch (event) {
618 case SND_SOC_DAPM_PRE_PMU:
619
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700620 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -0700621
622 ret = request_firmware(&fw, filename, codec->dev);
623 if (ret != 0) {
624 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
625 ret);
626 return -ENODEV;
627 }
628
629 if (fw->size < TABLA_PACKED_REG_SIZE) {
630 dev_err(codec->dev, "Not enough data\n");
631 release_firmware(fw);
632 return -ENOMEM;
633 }
634
635 /* First number is the number of register writes */
636 tabla->anc_writes_size = (u32)(*fw->data);
637
638 if (tabla->anc_writes_size >
639 ((fw->size/TABLA_PACKED_REG_SIZE) - 1)) {
640 dev_err(codec->dev, "Invalid register format\n");
641 release_firmware(fw);
642 return -ENOMEM;
643 }
644
645 tabla->anc_writes = (u32 *)(fw->data + TABLA_PACKED_REG_SIZE);
646
647 for (i = 0; i < tabla->anc_writes_size; i++) {
648 TABLA_CODEC_UNPACK_ENTRY(tabla->anc_writes[i], reg,
649 mask, val);
650 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700651 snd_soc_write(codec, reg, (old_val & ~mask) |
652 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -0700653 }
654 release_firmware(fw);
655 tabla->anc_writes = NULL;
656
657 break;
658 case SND_SOC_DAPM_POST_PMD:
659 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
660 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
661 break;
662 }
663 return 0;
664}
665
Patrick Lai3043fba2011-08-01 14:15:57 -0700666static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
667 u8 cfilt_sel, int inc)
668{
669 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
670 u32 *cfilt_cnt_ptr = NULL;
671 u16 micb_cfilt_reg;
672
673 switch (cfilt_sel) {
674 case TABLA_CFILT1_SEL:
675 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
676 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
677 break;
678 case TABLA_CFILT2_SEL:
679 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
680 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
681 break;
682 case TABLA_CFILT3_SEL:
683 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
684 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
685 break;
686 default:
687 return; /* should not happen */
688 }
689
690 if (inc) {
691 if (!(*cfilt_cnt_ptr)++)
692 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
693 } else {
694 /* check if count not zero, decrement
695 * then check if zero, go ahead disable cfilter
696 */
697 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr))
698 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
699 }
700}
Bradley Rubin229c6a52011-07-12 16:18:48 -0700701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
703 struct snd_kcontrol *kcontrol, int event)
704{
705 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -0700706 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
707 u16 micb_int_reg;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700708 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700709 char *internal1_text = "Internal1";
710 char *internal2_text = "Internal2";
711 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712
713 pr_debug("%s %d\n", __func__, event);
714 switch (w->reg) {
715 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700717 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 break;
719 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700721 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 break;
723 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700725 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700726 break;
727 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700728 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700729 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730 break;
731 default:
732 pr_err("%s: Error, invalid micbias register\n", __func__);
733 return -EINVAL;
734 }
735
736 switch (event) {
737 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700738 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -0700739 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700740
741 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700743 else if (strnstr(w->name, internal2_text, 30))
744 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
745 else if (strnstr(w->name, internal3_text, 30))
746 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 break;
749 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700750 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700752 else if (strnstr(w->name, internal2_text, 30))
753 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
754 else if (strnstr(w->name, internal3_text, 30))
755 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
756
Patrick Lai3043fba2011-08-01 14:15:57 -0700757 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 break;
759 }
760
761 return 0;
762}
763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
765 struct snd_kcontrol *kcontrol, int event)
766{
767 struct snd_soc_codec *codec = w->codec;
768 u16 dec_reset_reg;
769
770 pr_debug("%s %d\n", __func__, event);
771
772 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
773 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
774 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
775 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
776 else {
777 pr_err("%s: Error, incorrect dec\n", __func__);
778 return -EINVAL;
779 }
780
781 switch (event) {
782 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
784 1 << w->shift);
785 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
786 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 }
788 return 0;
789}
790
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700791static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 struct snd_kcontrol *kcontrol, int event)
793{
794 struct snd_soc_codec *codec = w->codec;
795
796 switch (event) {
797 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700798 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
799 1 << w->shift, 1 << w->shift);
800 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
801 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 break;
803 }
804 return 0;
805}
806
Bradley Rubin229c6a52011-07-12 16:18:48 -0700807static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
808 struct snd_kcontrol *kcontrol, int event)
809{
810 switch (event) {
811 case SND_SOC_DAPM_POST_PMU:
812 case SND_SOC_DAPM_POST_PMD:
813 usleep_range(1000, 1000);
814 break;
815 }
816 return 0;
817}
818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
820 /*RX stuff */
821 SND_SOC_DAPM_OUTPUT("EAR"),
822
823 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
824 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
825 SND_SOC_DAPM_PRE_PMD),
826
827 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
828
Bradley Rubin229c6a52011-07-12 16:18:48 -0700829 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
830 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831
Bradley Rubin229c6a52011-07-12 16:18:48 -0700832 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
833 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834
835 /* Headphone */
836 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
837 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700838 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
839 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700840
841 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700842 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
843 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844
845 /* Speaker */
846 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
849 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
850 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700851 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
852 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
853 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
855 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
856 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700857 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
858 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
859 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
860
Bradley Rubin229c6a52011-07-12 16:18:48 -0700861 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
862 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
863 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
864 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
865 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
866 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
867 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
868 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700869
Bradley Rubin229c6a52011-07-12 16:18:48 -0700870 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
871 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
872 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
873 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
874 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
875 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
876 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
877 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
878 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
879 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
880 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
881 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700882
Bradley Rubin229c6a52011-07-12 16:18:48 -0700883 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
884 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
885
886 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
887 &rx_mix1_inp1_mux),
888 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
889 &rx_mix1_inp2_mux),
890 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
891 &rx2_mix1_inp1_mux),
892 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
893 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700894 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
895 &rx3_mix1_inp1_mux),
896 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
897 &rx3_mix1_inp2_mux),
898 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
899 &rx4_mix1_inp1_mux),
900 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
901 &rx4_mix1_inp2_mux),
902 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
903 &rx5_mix1_inp1_mux),
904 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
905 &rx5_mix1_inp2_mux),
906 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
907 &rx6_mix1_inp1_mux),
908 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
909 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910
Bradley Rubin229c6a52011-07-12 16:18:48 -0700911 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
912 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
913 SND_SOC_DAPM_PRE_PMD),
914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700916
Bradley Rubine1d08622011-07-20 18:01:35 -0700917 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
918 0),
919
Bradley Rubin229c6a52011-07-12 16:18:48 -0700920 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
921 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
922
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 SND_SOC_DAPM_INPUT("AMIC1"),
924 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
925 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
926 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -0700927 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
928 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
929 SND_SOC_DAPM_POST_PMD),
930 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
932 SND_SOC_DAPM_POST_PMD),
933 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
934 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
935 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
936
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700937 SND_SOC_DAPM_INPUT("AMIC3"),
938 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
939 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
940 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
941
942 SND_SOC_DAPM_INPUT("AMIC4"),
943 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
944 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
945 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
946
947 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
948 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
949 SND_SOC_DAPM_POST_PMD),
950
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700951 SND_SOC_DAPM_INPUT("AMIC5"),
952 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
953 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
954
955 SND_SOC_DAPM_INPUT("AMIC6"),
956 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
957 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 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 -0700960 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700962 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 -0700963 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700964
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700965 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 -0700966 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700967
968 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 -0700969 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 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 -0700972 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973
974 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 -0700975 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976
977 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 -0700978 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700980 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 -0700981 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700982
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700983 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 -0700984 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700985
986 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 -0700987 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700988
Bradley Rubin229c6a52011-07-12 16:18:48 -0700989 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
990 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
991
992 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
993 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
994 SND_SOC_DAPM_POST_PMD),
995
996 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 SND_SOC_DAPM_INPUT("AMIC2"),
999 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
1000 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1001 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001002 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
1003 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1004 SND_SOC_DAPM_POST_PMD),
1005 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
1006 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1007 SND_SOC_DAPM_POST_PMD),
1008 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1010 SND_SOC_DAPM_POST_PMD),
1011 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
1012 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1013 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001014 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
1015 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1016 SND_SOC_DAPM_POST_PMD),
1017 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1019 SND_SOC_DAPM_POST_PMD),
1020 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1021 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1022 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1023
1024 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1025 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1026 0, 0),
1027
1028 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1029 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1030 4, 0),
1031
1032 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1033 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1034 5, 0),
1035
1036 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1037 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1038 0, 0),
1039
1040 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1041 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1042 0, 0),
1043
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001044 /* Digital Mic Inputs */
1045 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic),
1046 SND_SOC_DAPM_MIC("DMIC2", &tabla_codec_enable_dmic),
1047 SND_SOC_DAPM_MIC("DMIC3", &tabla_codec_enable_dmic),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048
1049 /* Sidetone */
1050 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1051 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1052};
1053
1054static const struct snd_soc_dapm_route audio_map[] = {
1055 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056
1057 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1058 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1059
1060 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1061 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1062
1063 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1064 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1065
1066 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1067 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001068 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001069 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1070 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1072 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001073 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1074 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001075 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1076 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077
1078 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001079 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1080 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1081 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1083 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1084
1085 /* Earpiece (RX MIX1) */
1086 {"EAR", NULL, "EAR PA"},
1087 {"EAR PA", NULL, "EAR PA Input"},
1088 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001089 {"DAC1", NULL, "CP"},
1090
1091 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1092 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1093 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094
1095 /* Headset (RX MIX1 and RX MIX2) */
1096 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001098
1099 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001101
1102 {"HPHL DAC", NULL, "CP"},
1103 {"HPHR DAC", NULL, "CP"},
1104
1105 {"ANC", NULL, "ANC1 MUX"},
1106 {"ANC", NULL, "ANC2 MUX"},
1107 {"ANC1 MUX", "ADC1", "ADC1"},
1108 {"ANC1 MUX", "ADC2", "ADC2"},
1109 {"ANC1 MUX", "ADC3", "ADC3"},
1110 {"ANC1 MUX", "ADC4", "ADC4"},
1111 {"ANC2 MUX", "ADC1", "ADC1"},
1112 {"ANC2 MUX", "ADC2", "ADC2"},
1113 {"ANC2 MUX", "ADC3", "ADC3"},
1114 {"ANC2 MUX", "ADC4", "ADC4"},
1115
Bradley Rubine1d08622011-07-20 18:01:35 -07001116 {"ANC", NULL, "CDC_CONN"},
1117
Bradley Rubin229c6a52011-07-12 16:18:48 -07001118 {"DAC1", "Switch", "RX1 CHAIN"},
1119 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1120 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001123 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001125 {"LINEOUT", NULL, "LINEOUT4"},
1126
1127 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1128 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001130 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
1131
Bradley Rubin229c6a52011-07-12 16:18:48 -07001132 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1133 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1134 {"RX1 CHAIN", NULL, "ANC"},
1135 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001136 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1137 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
Kiran Kandied246a92011-08-12 14:03:44 -07001138 {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
1139 {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001140
Bradley Rubin229c6a52011-07-12 16:18:48 -07001141 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1142 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1143 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1144 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001145 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1146 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1147 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1148 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1149 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1150 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1151 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1152 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
1153
Bradley Rubin229c6a52011-07-12 16:18:48 -07001154 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1155 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1156 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1157 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1158 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1159 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1160 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1161 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1162 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1163 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1164 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1165 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1166 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1167 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1168 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1169 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1170 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1171 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1172 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1173 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1174 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1175 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1176 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1177 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1178 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1179 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001181 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001182 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001183 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001184 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001185 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001186 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001187 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001188 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001189 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001190 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001191 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001192 {"DEC4 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001194 {"DEC5 MUX", NULL, "CDC_CONN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001196 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001197 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001198 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001199 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001200 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001201 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001202 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001203 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001204 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001205 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001206
1207 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 {"ADC1", NULL, "AMIC1"},
1209 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001210 {"ADC3", NULL, "AMIC3"},
1211 {"ADC4", NULL, "AMIC4"},
1212 {"ADC5", NULL, "AMIC5"},
1213 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 {"IIR1", NULL, "IIR1 INP1 MUX"},
1216 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001217
1218 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1219 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1220 {"MIC BIAS1 External", NULL, "LDO_H"},
1221 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1222 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1223 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1224 {"MIC BIAS2 External", NULL, "LDO_H"},
1225 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1226 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1227 {"MIC BIAS3 External", NULL, "LDO_H"},
1228 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001229};
1230
1231static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1232{
1233 return tabla_reg_readable[reg];
1234}
1235
1236static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1237{
1238 /* Registers lower than 0x100 are top level registers which can be
1239 * written by the Tabla core driver.
1240 */
1241
1242 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1243 return 1;
1244
1245 return 0;
1246}
1247
1248#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1249static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1250 unsigned int value)
1251{
1252 int ret;
1253 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1254
1255 BUG_ON(reg > TABLA_MAX_REGISTER);
1256
1257 if (!tabla_volatile(codec, reg)) {
1258 pr_debug("writing to cache\n");
1259 ret = snd_soc_cache_write(codec, reg, value);
1260 if (ret != 0)
1261 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1262 reg, ret);
1263 }
1264
1265 return tabla_reg_write(codec->control_data, reg, value);
1266}
1267static unsigned int tabla_read(struct snd_soc_codec *codec,
1268 unsigned int reg)
1269{
1270 unsigned int val;
1271 int ret;
1272
1273 BUG_ON(reg > TABLA_MAX_REGISTER);
1274
1275 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1276 reg < codec->driver->reg_cache_size) {
1277 pr_debug("reading from cache\n");
1278 ret = snd_soc_cache_read(codec, reg, &val);
1279 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001280 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 return val;
1282 } else
1283 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1284 reg, ret);
1285 }
1286
1287 val = tabla_reg_read(codec->control_data, reg);
1288 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1289 return val;
1290}
1291
1292static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1293{
1294 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1295 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1296 0x80);
1297 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1298 0x04);
1299 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1300 0x01);
1301 usleep_range(1000, 1000);
1302 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1303 0x00);
1304}
1305
1306static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1307 enum tabla_bandgap_type choice)
1308{
1309 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1310
1311 /* TODO lock resources accessed by audio streams and threaded
1312 * interrupt handlers
1313 */
1314
1315 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1316 tabla->bandgap_type);
1317
1318 if (tabla->bandgap_type == choice)
1319 return;
1320
1321 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1322 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1323 tabla_codec_enable_audio_mode_bandgap(codec);
1324 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1325 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1326 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1327 0x2);
1328 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1329 0x80);
1330 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1331 0x4);
1332 usleep_range(1000, 1000);
1333 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1334 0x00);
1335 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1336 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1337 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1338 usleep_range(100, 100);
1339 tabla_codec_enable_audio_mode_bandgap(codec);
1340 } else if (choice == TABLA_BANDGAP_OFF) {
1341 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1342 } else {
1343 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1344 }
1345 tabla->bandgap_type = choice;
1346}
1347
1348static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1349 int enable)
1350{
1351 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1352
1353 if (enable) {
1354 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1355 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1356 usleep_range(5, 5);
1357 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1358 0x80);
1359 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1360 0x80);
1361 usleep_range(10, 10);
1362 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1363 usleep_range(20, 20);
1364 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1365 } else {
1366 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1367 0);
1368 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1369 }
1370 tabla->config_mode_active = enable ? true : false;
1371
1372 return 0;
1373}
1374
1375static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1376 int config_mode)
1377{
1378 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1379
1380 pr_debug("%s\n", __func__);
1381
1382 if (config_mode) {
1383 tabla_codec_enable_config_mode(codec, 1);
1384 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1385 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1386 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1387 usleep_range(1000, 1000);
1388 } else
1389 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1390
1391 if (!config_mode && tabla->mbhc_polling_active) {
1392 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1393 tabla_codec_enable_config_mode(codec, 0);
1394
1395 }
1396
1397 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1398 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1399 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1400 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1401 usleep_range(50, 50);
1402 tabla->clock_active = true;
1403 return 0;
1404}
1405static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1406{
1407 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1408 pr_debug("%s\n", __func__);
1409 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1410 ndelay(160);
1411 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1412 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1413 tabla->clock_active = false;
1414}
1415
Bradley Rubincb1e2732011-06-23 16:49:20 -07001416static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1417{
1418 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
1419 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1420 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1421 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1422 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1423 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1424}
1425
1426static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1427{
1428 /* TODO store register values in calibration */
1429
1430 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1431 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1432
1433 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1434 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1435 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1436 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1437
1438 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1439 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1440 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1441 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1442 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1443 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1444}
1445
1446static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1447{
1448 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1449 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1450 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1451}
1452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453static int tabla_startup(struct snd_pcm_substream *substream,
1454 struct snd_soc_dai *dai)
1455{
1456 struct snd_soc_codec *codec = dai->codec;
1457 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1458 int ret = 0;
1459
1460 pr_debug("%s()\n", __func__);
1461
1462 if (!codec) {
1463 pr_err("Error, no codec found\n");
1464 return -EINVAL;
1465 }
1466 tabla->ref_cnt++;
1467
Patrick Lai3043fba2011-08-01 14:15:57 -07001468 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001469 tabla->rx_count++;
1470 if (tabla->rx_count == 1)
1471 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1472 0x80);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 }
1474
1475 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001476 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1478 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001479 tabla_codec_calibrate_hs_polling(codec);
1480 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 }
1482
1483 return ret;
1484}
1485
1486static void tabla_shutdown(struct snd_pcm_substream *substream,
1487 struct snd_soc_dai *dai)
1488{
1489 struct snd_soc_codec *codec = dai->codec;
1490 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1491
1492 pr_debug("%s()\n", __func__);
1493
1494 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1495 /* Disable LDO */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001496 } else {
1497 tabla->rx_count--;
1498 if (!tabla->rx_count)
1499 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1500 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 }
1502
1503 if (!tabla->ref_cnt) {
1504 pr_err("Error, trying to shutdown codec when already down\n");
1505 return;
1506 }
1507 tabla->ref_cnt--;
1508
1509 if (tabla->mbhc_polling_active) {
1510 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001511 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 tabla_codec_enable_bandgap(codec,
1513 TABLA_BANDGAP_MBHC_MODE);
1514 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1515 0x80);
1516 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001517 tabla_codec_calibrate_hs_polling(codec);
1518 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 }
1520 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1521 }
1522}
1523
1524static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1525{
1526 struct snd_soc_codec *codec = codec_dai->codec;
1527
1528 pr_debug("%s %d\n", __func__, mute);
1529
1530 /* TODO mute TX */
1531 if (mute)
1532 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1533 else
1534 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1535
1536 return 0;
1537}
1538
1539static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1540 int clk_id, unsigned int freq, int dir)
1541{
1542 pr_debug("%s\n", __func__);
1543 return 0;
1544}
1545
1546static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1547{
1548 pr_debug("%s\n", __func__);
1549 return 0;
1550}
1551
1552static int tabla_hw_params(struct snd_pcm_substream *substream,
1553 struct snd_pcm_hw_params *params,
1554 struct snd_soc_dai *dai)
1555{
1556 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1557 return 0;
1558}
1559
1560static struct snd_soc_dai_ops tabla_dai_ops = {
1561 .startup = tabla_startup,
1562 .shutdown = tabla_shutdown,
1563 .hw_params = tabla_hw_params,
1564 .set_sysclk = tabla_set_dai_sysclk,
1565 .set_fmt = tabla_set_dai_fmt,
1566 .digital_mute = tabla_digital_mute,
1567};
1568
1569static struct snd_soc_dai_driver tabla_dai[] = {
1570 {
1571 .name = "tabla_rx1",
1572 .id = 1,
1573 .playback = {
1574 .stream_name = "AIF1 Playback",
1575 .rates = SNDRV_PCM_RATE_8000_48000,
1576 .formats = TABLA_FORMATS,
1577 .rate_max = 48000,
1578 .rate_min = 8000,
1579 .channels_min = 1,
1580 .channels_max = 2,
1581 },
1582 .ops = &tabla_dai_ops,
1583 },
1584 {
1585 .name = "tabla_tx1",
1586 .id = 2,
1587 .capture = {
1588 .stream_name = "AIF1 Capture",
1589 .rates = SNDRV_PCM_RATE_8000_48000,
1590 .formats = TABLA_FORMATS,
1591 .rate_max = 48000,
1592 .rate_min = 8000,
1593 .channels_min = 1,
1594 .channels_max = 2,
1595 },
1596 .ops = &tabla_dai_ops,
1597 },
1598};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001599static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07001600{
1601 u8 bias_msb, bias_lsb;
1602 short bias_value;
1603
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001604 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1605 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1606 bias_value = (bias_msb << 8) | bias_lsb;
1607 return bias_value;
1608}
1609
1610static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
1611{
1612 u8 bias_msb, bias_lsb;
1613 short bias_value;
1614
1615 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1616 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1617 bias_value = (bias_msb << 8) | bias_lsb;
1618 return bias_value;
1619}
1620
1621static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1622 int dce)
1623{
1624 short bias_value;
1625
Bradley Rubincb1e2732011-06-23 16:49:20 -07001626 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001627 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1628 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1629 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1630 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1631 usleep_range(60000, 60000);
1632 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001633 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001634 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001635 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1636 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001637 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001638 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001639 usleep_range(50, 50);
1640 bias_value = tabla_codec_read_sta_result(codec);
1641 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1642 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001643 }
1644
Bradley Rubincb1e2732011-06-23 16:49:20 -07001645 pr_debug("read microphone bias value %x\n", bias_value);
1646 return bias_value;
1647}
1648
1649static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650{
1651 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1652 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Patrick Lai3043fba2011-08-01 14:15:57 -07001653 int micbias_ctl_reg, micbias_cfilt_ctl_reg,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001654 micbias_mbhc_reg;
1655 short bias_value, threshold_no_mic;
Patrick Lai3043fba2011-08-01 14:15:57 -07001656 unsigned int cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657
1658 if (!calibration) {
1659 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001660 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 }
1662
1663 tabla->mbhc_polling_active = true;
1664
1665 if (!tabla->ref_cnt) {
1666 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1667 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1668 tabla_codec_enable_clock_block(codec, 1);
1669 }
1670
1671 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1674
Patrick Lai3043fba2011-08-01 14:15:57 -07001675 /* select cfilt separately from the micbias line in the platform data */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 switch (calibration->bias) {
1677 case TABLA_MICBIAS1:
1678 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001679 cfilt_sel = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001680 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 break;
1682 case TABLA_MICBIAS2:
1683 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001684 cfilt_sel = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001685 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 break;
1687 case TABLA_MICBIAS3:
1688 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001689 cfilt_sel = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001690 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 break;
1692 case TABLA_MICBIAS4:
1693 pr_err("%s: Error, microphone bias 4 not supported\n",
1694 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001695 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 default:
1697 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001698 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 }
Patrick Lai3043fba2011-08-01 14:15:57 -07001700
1701 switch (cfilt_sel) {
1702 case TABLA_CFILT1_SEL:
1703 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1704 break;
1705 case TABLA_CFILT2_SEL:
1706 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1707 break;
1708 case TABLA_CFILT3_SEL:
1709 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1710 break;
1711 default: /* default should not happen as check should have been done */
1712 return -EINVAL;
1713 }
1714
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001715 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716
Bradley Rubincb1e2732011-06-23 16:49:20 -07001717 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718
1719 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001720 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721
1722 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1723 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1724 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1725
1726 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001727 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1728 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729
Bradley Rubincb1e2732011-06-23 16:49:20 -07001730 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1732
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001733 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001734 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1735
1736 tabla_codec_calibrate_hs_polling(codec);
1737
1738 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001739 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1740 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001741 threshold_no_mic = 0xF7F6;
1742
1743 if (bias_value < threshold_no_mic) {
1744 pr_debug("headphone detected, micbias %x\n", bias_value);
1745 return 0;
1746 } else {
1747 pr_debug("headset detected, micbias %x\n", bias_value);
1748 return 1;
1749 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750}
1751
1752static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1753 int insertion)
1754{
1755 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1756 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1757 int central_bias_enabled = 0;
1758 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1759
1760 if (!calibration) {
1761 pr_err("Error, no tabla calibration\n");
1762 return -EINVAL;
1763 }
1764
1765 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1766
1767 if (insertion)
1768 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1769 else
1770 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1771
1772 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1773 if (!(tabla->clock_active)) {
1774 tabla_codec_enable_config_mode(codec, 1);
1775 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001776 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 usleep_range(calibration->shutdown_plug_removal,
1778 calibration->shutdown_plug_removal);
1779 tabla_codec_enable_config_mode(codec, 0);
1780 } else
1781 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001782 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 }
1784
1785 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1786 calibration->hph_current << 2);
1787
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001788 /* Turn off HPH PAs during insertion detection to avoid false
1789 * insertion interrupts
1790 */
1791 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1793
1794 switch (calibration->bias) {
1795 case TABLA_MICBIAS1:
1796 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1797 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1798 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1799 break;
1800 case TABLA_MICBIAS2:
1801 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1802 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1803 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1804 break;
1805 case TABLA_MICBIAS3:
1806 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1807 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1808 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1809 break;
1810 case TABLA_MICBIAS4:
1811 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1812 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1813 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1814 break;
1815 default:
1816 pr_err("Error, invalid mic bias line\n");
1817 return -EINVAL;
1818 }
1819 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1820 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1821
1822 /* If central bandgap disabled */
1823 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1824 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1825 usleep_range(calibration->bg_fast_settle,
1826 calibration->bg_fast_settle);
1827 central_bias_enabled = 1;
1828 }
1829
1830 /* If LDO_H disabled */
1831 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1832 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1833 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1834 usleep_range(calibration->tldoh, calibration->tldoh);
1835 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1836
1837 if (central_bias_enabled)
1838 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1839 }
1840 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1841 calibration->mic_current << 5);
1842 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1843 usleep_range(calibration->mic_pid, calibration->mic_pid);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1846
1847 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1848
1849 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1850 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1851 return 0;
1852}
1853
Bradley Rubincb1e2732011-06-23 16:49:20 -07001854int tabla_hs_detect(struct snd_soc_codec *codec,
1855 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856 struct tabla_mbhc_calibration *calibration)
1857{
1858 struct tabla_priv *tabla;
1859 if (!codec || !calibration) {
1860 pr_err("Error: no codec or calibration\n");
1861 return -EINVAL;
1862 }
1863 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001864 tabla->headset_jack = headset_jack;
1865 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 tabla->calibration = calibration;
1867
1868 return tabla_codec_enable_hs_detect(codec, 1);
1869}
1870EXPORT_SYMBOL_GPL(tabla_hs_detect);
1871
Bradley Rubincb1e2732011-06-23 16:49:20 -07001872static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873{
1874 struct tabla_priv *priv = data;
1875 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001876 short bias_value;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001877
1878 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1879 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1880
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001881 bias_value = tabla_codec_read_dce_result(codec);
1882 pr_debug("button press interrupt, bias value is %d\n", bias_value);
1883
Bradley Rubincb1e2732011-06-23 16:49:20 -07001884 if (priv->button_jack)
1885 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1886 SND_JACK_BTN_0);
1887
1888 priv->buttons_pressed |= SND_JACK_BTN_0;
1889 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1890 0x09);
1891 usleep_range(100000, 100000);
1892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893 return IRQ_HANDLED;
1894}
1895
Bradley Rubincb1e2732011-06-23 16:49:20 -07001896static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001897{
1898 struct tabla_priv *priv = data;
1899 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001900 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1901 pr_debug("%s: Button released\n", __func__);
1902 if (priv->button_jack)
1903 snd_soc_jack_report(priv->button_jack, 0,
1904 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905
Bradley Rubincb1e2732011-06-23 16:49:20 -07001906 priv->buttons_pressed &= ~SND_JACK_BTN_0;
1907 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1908 0x08);
1909 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911
1912 return IRQ_HANDLED;
1913}
1914
Bradley Rubincb1e2732011-06-23 16:49:20 -07001915static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1916{
1917 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1918 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1919 int micbias_mbhc_reg;
1920
1921 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1922 tabla_codec_enable_config_mode(codec, 1);
1923
1924 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1925 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001926
1927 switch (calibration->bias) {
1928 case TABLA_MICBIAS1:
1929 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1930 break;
1931 case TABLA_MICBIAS2:
1932 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1933 break;
1934 case TABLA_MICBIAS3:
1935 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1936 break;
1937 case TABLA_MICBIAS4:
1938 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1939 break;
1940 default:
1941 pr_err("Error, invalid mic bias line\n");
1942 return;
1943 }
1944 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001945 usleep_range(calibration->shutdown_plug_removal,
1946 calibration->shutdown_plug_removal);
1947
1948 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1949 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1950 tabla_codec_enable_config_mode(codec, 0);
1951
1952 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
1953}
1954
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
1956{
1957 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001958
1959 tabla_codec_shutdown_hs_removal_detect(codec);
1960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 if (!tabla->ref_cnt) {
1962 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
1963 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1964 tabla_codec_enable_clock_block(codec, 0);
1965 }
1966
1967 tabla->mbhc_polling_active = false;
1968}
1969
Bradley Rubincb1e2732011-06-23 16:49:20 -07001970static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
1971{
1972 struct tabla_priv *priv = data;
1973 struct snd_soc_codec *codec = priv->codec;
1974 int microphone_present;
1975
1976 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1977
1978 usleep_range(priv->calibration->setup_plug_removal_delay,
1979 priv->calibration->setup_plug_removal_delay);
1980
1981 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
1982 if (priv->headset_jack) {
1983 pr_debug("%s: Reporting removal\n", __func__);
1984 snd_soc_jack_report(priv->headset_jack, 0,
1985 SND_JACK_HEADSET);
1986 }
1987 tabla_codec_shutdown_hs_removal_detect(codec);
1988 tabla_codec_enable_hs_detect(codec, 1);
1989 return IRQ_HANDLED;
1990 }
1991
1992 microphone_present = tabla_codec_setup_hs_polling(codec);
1993
1994 if (microphone_present == 0) {
1995 if (priv->headset_jack) {
1996 pr_debug("%s: Reporting insertion %d\n", __func__,
1997 SND_JACK_HEADPHONE);
1998 snd_soc_jack_report(priv->headset_jack,
1999 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
2000 }
2001 tabla_codec_shutdown_hs_polling(codec);
2002 tabla_codec_enable_hs_detect(codec, 0);
2003 } else if (microphone_present == 1) {
2004 if (priv->headset_jack) {
2005 pr_debug("%s: Reporting insertion %d\n", __func__,
2006 SND_JACK_HEADSET);
2007 snd_soc_jack_report(priv->headset_jack,
2008 SND_JACK_HEADSET, SND_JACK_HEADSET);
2009 }
2010 tabla_codec_start_hs_polling(codec);
2011 }
2012
2013 return IRQ_HANDLED;
2014}
2015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
2017{
2018 struct tabla_priv *priv = data;
2019 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002020 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021
2022 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2023 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2024
2025 usleep_range(priv->calibration->shutdown_plug_removal,
2026 priv->calibration->shutdown_plug_removal);
2027
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002028 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
2029 pr_debug("removal interrupt, bias value is %d\n", bias_value);
2030
2031 if (bias_value < -90) {
2032 pr_debug("False alarm, headset not actually removed\n");
2033 tabla_codec_start_hs_polling(codec);
2034 } else {
2035 if (priv->headset_jack) {
2036 pr_debug("%s: Reporting removal\n", __func__);
2037 snd_soc_jack_report(priv->headset_jack, 0,
2038 SND_JACK_HEADSET);
2039 }
2040 tabla_codec_shutdown_hs_polling(codec);
2041
2042 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 return IRQ_HANDLED;
2045}
2046
2047static unsigned long slimbus_value;
2048
2049static irqreturn_t tabla_slimbus_irq(int irq, void *data)
2050{
2051 struct tabla_priv *priv = data;
2052 struct snd_soc_codec *codec = priv->codec;
2053 int i, j;
2054 u8 val;
2055
2056 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
2057 slimbus_value = tabla_interface_reg_read(codec->control_data,
2058 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
2059 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
2060 val = tabla_interface_reg_read(codec->control_data,
2061 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
2062 if (val & 0x1)
2063 pr_err_ratelimited("overflow error on port %x,"
2064 " value %x\n", i*8 + j, val);
2065 if (val & 0x2)
2066 pr_err_ratelimited("underflow error on port %x,"
2067 " value %x\n", i*8 + j, val);
2068 }
2069 tabla_interface_reg_write(codec->control_data,
2070 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2071 }
2072
2073 return IRQ_HANDLED;
2074}
2075
Patrick Lai3043fba2011-08-01 14:15:57 -07002076static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2077{
2078 int rc = -EINVAL;
2079 unsigned min_mv, max_mv;
2080
2081 switch (ldoh_v) {
2082 case TABLA_LDOH_1P95_V:
2083 min_mv = 160;
2084 max_mv = 1800;
2085 break;
2086 case TABLA_LDOH_2P35_V:
2087 min_mv = 200;
2088 max_mv = 2200;
2089 break;
2090 case TABLA_LDOH_2P75_V:
2091 min_mv = 240;
2092 max_mv = 2600;
2093 break;
2094 case TABLA_LDOH_2P85_V:
2095 min_mv = 250;
2096 max_mv = 2700;
2097 break;
2098 default:
2099 goto done;
2100 }
2101
2102 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2103 goto done;
2104
2105 for (rc = 4; rc <= 44; rc++) {
2106 min_mv = max_mv * (rc) / 44;
2107 if (min_mv >= cfilt_mv) {
2108 rc -= 4;
2109 break;
2110 }
2111 }
2112done:
2113 return rc;
2114}
2115
2116static int tabla_handle_pdata(struct tabla_priv *tabla)
2117{
2118 struct snd_soc_codec *codec = tabla->codec;
2119 struct tabla_pdata *pdata = tabla->pdata;
2120 int k1, k2, k3, rc = 0;
2121
2122 if (!pdata) {
2123 rc = -ENODEV;
2124 goto done;
2125 }
2126
2127 /* Make sure settings are correct */
2128 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
2129 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
2130 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
2131 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
2132 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
2133 rc = -EINVAL;
2134 goto done;
2135 }
2136
2137 /* figure out k value */
2138 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
2139 pdata->micbias.cfilt1_mv);
2140 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
2141 pdata->micbias.cfilt2_mv);
2142 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
2143 pdata->micbias.cfilt3_mv);
2144
2145 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
2146 rc = -EINVAL;
2147 goto done;
2148 }
2149
2150 /* Set voltage level and always use LDO */
2151 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
2152 (pdata->micbias.ldoh_v << 2));
2153
2154 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
2155 (k1 << 2));
2156 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
2157 (k2 << 2));
2158 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
2159 (k3 << 2));
2160
2161 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
2162 (pdata->micbias.bias1_cfilt_sel << 5));
2163 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
2164 (pdata->micbias.bias2_cfilt_sel << 5));
2165 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
2166 (pdata->micbias.bias3_cfilt_sel << 5));
2167 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
2168 (pdata->micbias.bias4_cfilt_sel << 5));
2169
2170done:
2171 return rc;
2172}
2173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174static int tabla_codec_probe(struct snd_soc_codec *codec)
2175{
2176 struct tabla *control;
2177 struct tabla_priv *tabla;
2178 struct snd_soc_dapm_context *dapm = &codec->dapm;
2179 int ret = 0;
2180 int i;
2181 int tx_channel;
2182
2183 codec->control_data = dev_get_drvdata(codec->dev->parent);
2184 control = codec->control_data;
2185
2186 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2187 if (!tabla) {
2188 dev_err(codec->dev, "Failed to allocate private data\n");
2189 return -ENOMEM;
2190 }
2191
2192 snd_soc_codec_set_drvdata(codec, tabla);
2193
2194 tabla->ref_cnt = 0;
2195 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2196 tabla->clock_active = false;
2197 tabla->config_mode_active = false;
2198 tabla->mbhc_polling_active = false;
2199 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002200 tabla->pdata = dev_get_platdata(codec->dev->parent);
2201
2202 ret = tabla_handle_pdata(tabla);
2203
2204 if (IS_ERR_VALUE(ret)) {
2205 pr_err("%s: bad pdata\n", __func__);
2206 goto err_pdata;
2207 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208
2209 /* TODO only enable bandgap when necessary in order to save power */
2210 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2211 tabla_codec_enable_clock_block(codec, 0);
2212
2213 /* Initialize gain registers to use register gain */
2214 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
2215 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
2216 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002217 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
Bradley Rubine1d08622011-07-20 18:01:35 -07002219 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220
2221 /* Initialize mic biases to differential mode */
2222 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
2223 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
2224 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
2225 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
2226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
2228
2229 /* Use 16 bit sample size for now */
2230 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
2231 snd_soc_update_bits(codec,
2232 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
2233 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002234 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002235
2236 }
2237 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
2238 snd_soc_update_bits(codec,
2239 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
2240 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07002241 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 }
2243 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
2244 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
2245
2246 snd_soc_add_controls(codec, tabla_snd_controls,
2247 ARRAY_SIZE(tabla_snd_controls));
2248 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2249 ARRAY_SIZE(tabla_dapm_widgets));
2250 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2251 snd_soc_dapm_sync(dapm);
2252
2253 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2254 tabla_hs_insert_irq, "Headset insert detect", tabla);
2255 if (ret) {
2256 pr_err("%s: Failed to request irq %d\n", __func__,
2257 TABLA_IRQ_MBHC_INSERTION);
2258 goto err_insert_irq;
2259 }
2260 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2261
2262 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2263 tabla_hs_remove_irq, "Headset remove detect", tabla);
2264 if (ret) {
2265 pr_err("%s: Failed to request irq %d\n", __func__,
2266 TABLA_IRQ_MBHC_REMOVAL);
2267 goto err_remove_irq;
2268 }
2269 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2270
2271 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002272 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 if (ret) {
2274 pr_err("%s: Failed to request irq %d\n", __func__,
2275 TABLA_IRQ_MBHC_POTENTIAL);
2276 goto err_potential_irq;
2277 }
2278 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2279
Bradley Rubincb1e2732011-06-23 16:49:20 -07002280 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2281 tabla_release_handler, "Button Release detect", tabla);
2282 if (ret) {
2283 pr_err("%s: Failed to request irq %d\n", __func__,
2284 TABLA_IRQ_MBHC_RELEASE);
2285 goto err_release_irq;
2286 }
2287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2289 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2290 if (ret) {
2291 pr_err("%s: Failed to request irq %d\n", __func__,
2292 TABLA_IRQ_SLIMBUS);
2293 goto err_slimbus_irq;
2294 }
2295
2296 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2297 tabla_interface_reg_write(codec->control_data,
2298 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2299
2300 return ret;
2301
2302err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002303 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2304err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2306err_potential_irq:
2307 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2308err_remove_irq:
2309 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2310err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07002311err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312 kfree(tabla);
2313 return ret;
2314}
2315static int tabla_codec_remove(struct snd_soc_codec *codec)
2316{
2317 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2318 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002319 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2321 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2322 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2323 tabla_codec_disable_clock_block(codec);
2324 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2325 kfree(tabla);
2326 return 0;
2327}
2328static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2329 .probe = tabla_codec_probe,
2330 .remove = tabla_codec_remove,
2331 .read = tabla_read,
2332 .write = tabla_write,
2333
2334 .readable_register = tabla_readable,
2335 .volatile_register = tabla_volatile,
2336
2337 .reg_cache_size = TABLA_CACHE_SIZE,
2338 .reg_cache_default = tabla_reg_defaults,
2339 .reg_word_size = 1,
2340};
2341static int __devinit tabla_probe(struct platform_device *pdev)
2342{
2343 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2344 tabla_dai, ARRAY_SIZE(tabla_dai));
2345}
2346static int __devexit tabla_remove(struct platform_device *pdev)
2347{
2348 snd_soc_unregister_codec(&pdev->dev);
2349 return 0;
2350}
2351static struct platform_driver tabla_codec_driver = {
2352 .probe = tabla_probe,
2353 .remove = tabla_remove,
2354 .driver = {
2355 .name = "tabla_codec",
2356 .owner = THIS_MODULE,
2357 },
2358};
2359
2360static int __init tabla_codec_init(void)
2361{
2362 return platform_driver_register(&tabla_codec_driver);
2363}
2364
2365static void __exit tabla_codec_exit(void)
2366{
2367 platform_driver_unregister(&tabla_codec_driver);
2368}
2369
2370module_init(tabla_codec_init);
2371module_exit(tabla_codec_exit);
2372
2373MODULE_DESCRIPTION("Tabla codec driver");
2374MODULE_VERSION("1.0");
2375MODULE_LICENSE("GPL v2");