blob: e93087c97448a459d67b4e8f954f9b08abb1a5c5 [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
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070030#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
31 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
32
33#define NUM_DECIMATORS 10
34#define NUM_INTERPOLATORS 7
35#define BITS_PER_REG 8
36#define TABLA_RX_DAI_ID 1
37#define TABLA_TX_DAI_ID 2
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
40static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
41static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
42
43enum tabla_bandgap_type {
44 TABLA_BANDGAP_OFF = 0,
45 TABLA_BANDGAP_AUDIO_MODE,
46 TABLA_BANDGAP_MBHC_MODE,
47};
48
Bradley Rubin229c6a52011-07-12 16:18:48 -070049struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050 struct snd_soc_codec *codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -070052 u32 cfilt1_cnt;
53 u32 cfilt2_cnt;
54 u32 cfilt3_cnt;
Kiran Kandi3a30bda2011-08-15 10:36:42 -070055 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056 enum tabla_bandgap_type bandgap_type;
Kiran Kandi3a30bda2011-08-15 10:36:42 -070057 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058 bool clock_active;
59 bool config_mode_active;
60 bool mbhc_polling_active;
Bradley Rubincb1e2732011-06-23 16:49:20 -070061 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062
63 struct tabla_mbhc_calibration *calibration;
64
Bradley Rubincb1e2732011-06-23 16:49:20 -070065 struct snd_soc_jack *headset_jack;
66 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -070067
Patrick Lai3043fba2011-08-01 14:15:57 -070068 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -070069 u32 anc_slot;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070};
71
72static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
73 struct snd_kcontrol *kcontrol, int event)
74{
75 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076
77 pr_debug("%s %d\n", __func__, event);
78 switch (event) {
79 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070080 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
81 0x01);
82 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
83 usleep_range(200, 200);
84 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
85 break;
86 case SND_SOC_DAPM_PRE_PMD:
87 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
88 0x10);
89 usleep_range(20, 20);
90 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
91 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
92 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
93 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
94 0x00);
95 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096 break;
97 }
98 return 0;
99}
100
Bradley Rubina7096d02011-08-03 18:29:02 -0700101static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
102 struct snd_ctl_elem_value *ucontrol)
103{
104 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
105 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
106 ucontrol->value.integer.value[0] = tabla->anc_slot;
107 return 0;
108}
109
110static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
111 struct snd_ctl_elem_value *ucontrol)
112{
113 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
114 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
115 tabla->anc_slot = ucontrol->value.integer.value[0];
116 return 0;
117}
118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119static const struct snd_kcontrol_new tabla_snd_controls[] = {
120 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
121 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700122 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
123 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
125 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700126 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
127 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700128 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
129 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700130
131 SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
132 SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
133 SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
134 SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
135 SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
136 SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
139 line_gain),
140 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
141 line_gain),
142
Bradley Rubin410383f2011-07-22 13:44:23 -0700143 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
144 -84, 40, digital_gain),
145 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
146 -84, 40, digital_gain),
147 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
148 -84, 40, digital_gain),
149 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
150 -84, 40, digital_gain),
151 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
152 -84, 40, digital_gain),
153 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
154 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155
Bradley Rubin410383f2011-07-22 13:44:23 -0700156 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700158 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700160 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
161 digital_gain),
162 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
163 digital_gain),
164 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
165 digital_gain),
166 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
167 digital_gain),
168 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
169 digital_gain),
170 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
171 digital_gain),
172 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
173 digital_gain),
174 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
175 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700177 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
178 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700179 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
180 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700181 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
182 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183
184 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700185 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
186 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700187
188 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
189 tabla_put_anc_slot),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190};
191
192static const char *rx_mix1_text[] = {
193 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
194 "RX5", "RX6", "RX7"
195};
196
197static const char *sb_tx1_mux_text[] = {
198 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
199 "DEC1"
200};
201
202static const char *sb_tx5_mux_text[] = {
203 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
204 "DEC5"
205};
206
207static const char *sb_tx6_mux_text[] = {
208 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
209 "DEC6"
210};
211
212static const char const *sb_tx7_to_tx10_mux_text[] = {
213 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
214 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
215 "DEC9", "DEC10"
216};
217
218static const char *dec1_mux_text[] = {
219 "ZERO", "DMIC1", "ADC6",
220};
221
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700222static const char *dec2_mux_text[] = {
223 "ZERO", "DMIC2", "ADC5",
224};
225
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700226static const char *dec3_mux_text[] = {
227 "ZERO", "DMIC3", "ADC4",
228};
229
230static const char *dec4_mux_text[] = {
231 "ZERO", "DMIC4", "ADC3",
232};
233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234static const char *dec5_mux_text[] = {
235 "ZERO", "DMIC5", "ADC2",
236};
237
238static const char *dec6_mux_text[] = {
239 "ZERO", "DMIC6", "ADC1",
240};
241
242static const char const *dec7_mux_text[] = {
243 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
244};
245
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700246static const char *dec8_mux_text[] = {
247 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
248};
249
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700250static const char *dec9_mux_text[] = {
251 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
252};
253
254static const char *dec10_mux_text[] = {
255 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
256};
257
Bradley Rubin229c6a52011-07-12 16:18:48 -0700258static const char const *anc_mux_text[] = {
259 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
260 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
261};
262
263static const char const *anc1_fb_mux_text[] = {
264 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
265};
266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267static const char *iir1_inp1_text[] = {
268 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
269 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
270};
271
272static const struct soc_enum rx_mix1_inp1_chain_enum =
273 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
274
Bradley Rubin229c6a52011-07-12 16:18:48 -0700275static const struct soc_enum rx_mix1_inp2_chain_enum =
276 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278static const struct soc_enum rx2_mix1_inp1_chain_enum =
279 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
280
Bradley Rubin229c6a52011-07-12 16:18:48 -0700281static const struct soc_enum rx2_mix1_inp2_chain_enum =
282 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284static const struct soc_enum rx3_mix1_inp1_chain_enum =
285 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
286
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700287static const struct soc_enum rx3_mix1_inp2_chain_enum =
288 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290static const struct soc_enum rx4_mix1_inp1_chain_enum =
291 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
292
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700293static const struct soc_enum rx4_mix1_inp2_chain_enum =
294 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296static const struct soc_enum rx5_mix1_inp1_chain_enum =
297 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
298
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700299static const struct soc_enum rx5_mix1_inp2_chain_enum =
300 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
301
302static const struct soc_enum rx6_mix1_inp1_chain_enum =
303 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
304
305static const struct soc_enum rx6_mix1_inp2_chain_enum =
306 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
307
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700308static const struct soc_enum rx7_mix1_inp1_chain_enum =
309 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
310
311static const struct soc_enum rx7_mix1_inp2_chain_enum =
312 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314static const struct soc_enum sb_tx5_mux_enum =
315 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
316
317static const struct soc_enum sb_tx6_mux_enum =
318 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
319
320static const struct soc_enum sb_tx7_mux_enum =
321 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
322 sb_tx7_to_tx10_mux_text);
323
324static const struct soc_enum sb_tx8_mux_enum =
325 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
326 sb_tx7_to_tx10_mux_text);
327
328static const struct soc_enum sb_tx1_mux_enum =
329 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
330
331static const struct soc_enum dec1_mux_enum =
332 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
333
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700334static const struct soc_enum dec2_mux_enum =
335 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
336
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700337static const struct soc_enum dec3_mux_enum =
338 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
339
340static const struct soc_enum dec4_mux_enum =
341 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343static const struct soc_enum dec5_mux_enum =
344 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
345
346static const struct soc_enum dec6_mux_enum =
347 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
348
349static const struct soc_enum dec7_mux_enum =
350 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
351
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700352static const struct soc_enum dec8_mux_enum =
353 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
354
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700355static const struct soc_enum dec9_mux_enum =
356 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
357
358static const struct soc_enum dec10_mux_enum =
359 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
360
Bradley Rubin229c6a52011-07-12 16:18:48 -0700361static const struct soc_enum anc1_mux_enum =
362 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
363
364static const struct soc_enum anc2_mux_enum =
365 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
366
367static const struct soc_enum anc1_fb_mux_enum =
368 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370static const struct soc_enum iir1_inp1_mux_enum =
371 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
372
373static const struct snd_kcontrol_new rx_mix1_inp1_mux =
374 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
375
Bradley Rubin229c6a52011-07-12 16:18:48 -0700376static const struct snd_kcontrol_new rx_mix1_inp2_mux =
377 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
380 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
381
Bradley Rubin229c6a52011-07-12 16:18:48 -0700382static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
383 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
384
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
386 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
387
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700388static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
389 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
392 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
393
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700394static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
395 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
398 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
399
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700400static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
401 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
402
403static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
404 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
405
406static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
407 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
408
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700409static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
410 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
411
412static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
413 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415static const struct snd_kcontrol_new sb_tx5_mux =
416 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
417
418static const struct snd_kcontrol_new sb_tx6_mux =
419 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
420
421static const struct snd_kcontrol_new sb_tx7_mux =
422 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
423
424static const struct snd_kcontrol_new sb_tx8_mux =
425 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
426
427static const struct snd_kcontrol_new sb_tx1_mux =
428 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
429
430static const struct snd_kcontrol_new dec1_mux =
431 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
432
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700433static const struct snd_kcontrol_new dec2_mux =
434 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
435
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700436static const struct snd_kcontrol_new dec3_mux =
437 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
438
439static const struct snd_kcontrol_new dec4_mux =
440 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442static const struct snd_kcontrol_new dec5_mux =
443 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
444
445static const struct snd_kcontrol_new dec6_mux =
446 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
447
448static const struct snd_kcontrol_new dec7_mux =
449 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
450
Bradley Rubin229c6a52011-07-12 16:18:48 -0700451static const struct snd_kcontrol_new anc1_mux =
452 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700453static const struct snd_kcontrol_new dec8_mux =
454 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
455
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700456static const struct snd_kcontrol_new dec9_mux =
457 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
458
459static const struct snd_kcontrol_new dec10_mux =
460 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462static const struct snd_kcontrol_new iir1_inp1_mux =
463 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
464
Bradley Rubin229c6a52011-07-12 16:18:48 -0700465static const struct snd_kcontrol_new anc2_mux =
466 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467
Bradley Rubin229c6a52011-07-12 16:18:48 -0700468static const struct snd_kcontrol_new anc1_fb_mux =
469 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470
Bradley Rubin229c6a52011-07-12 16:18:48 -0700471static const struct snd_kcontrol_new dac1_switch[] = {
472 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
473};
474static const struct snd_kcontrol_new hphl_switch[] = {
475 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
476};
477static const struct snd_kcontrol_new hphr_switch[] = {
478 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
479};
480static const struct snd_kcontrol_new lineout1_switch[] = {
481 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
482};
483static const struct snd_kcontrol_new lineout2_switch[] = {
484 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
485};
486static const struct snd_kcontrol_new lineout3_switch[] = {
487 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
488};
489static const struct snd_kcontrol_new lineout4_switch[] = {
490 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
491};
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700492static const struct snd_kcontrol_new lineout5_switch[] = {
493 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_5_DAC_CTL, 6, 1, 0)
494};
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
497 int enable)
498{
499 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
500
501 pr_debug("%s %d\n", __func__, enable);
502
503 if (enable) {
504 tabla->adc_count++;
505 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
506 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
507 } else {
508 tabla->adc_count--;
509 if (!tabla->adc_count) {
510 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
511 0x2, 0x0);
512 if (!tabla->mbhc_polling_active)
513 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
514 0xE0, 0x0);
515 }
516 }
517}
518
519static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
520 struct snd_kcontrol *kcontrol, int event)
521{
522 struct snd_soc_codec *codec = w->codec;
523 u16 adc_reg;
524
525 pr_debug("%s %d\n", __func__, event);
526
527 if (w->reg == TABLA_A_TX_1_2_EN)
528 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
529 else if (w->reg == TABLA_A_TX_3_4_EN)
530 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
531 else if (w->reg == TABLA_A_TX_5_6_EN)
532 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
533 else {
534 pr_err("%s: Error, invalid adc register\n", __func__);
535 return -EINVAL;
536 }
537
538 switch (event) {
539 case SND_SOC_DAPM_PRE_PMU:
540 tabla_codec_enable_adc_block(codec, 1);
541 break;
542 case SND_SOC_DAPM_POST_PMU:
543 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
544 1 << w->shift);
545 usleep_range(1000, 1000);
546 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
547 usleep_range(1000, 1000);
548 break;
549 case SND_SOC_DAPM_POST_PMD:
550 tabla_codec_enable_adc_block(codec, 0);
551 break;
552 }
553 return 0;
554}
555
556static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
557 struct snd_kcontrol *kcontrol, int event)
558{
559 struct snd_soc_codec *codec = w->codec;
560
561 pr_debug("%s %d\n", __func__, event);
562 switch (event) {
563 case SND_SOC_DAPM_PRE_PMU:
564 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
565 break;
566 case SND_SOC_DAPM_POST_PMD:
567 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
568 break;
569 }
570 return 0;
571}
572
573static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
574 struct snd_kcontrol *kcontrol, int event)
575{
576 struct snd_soc_codec *codec = w->codec;
577 u16 lineout_gain_reg;
578
579 pr_debug("%s %d\n", __func__, event);
580
581 switch (w->shift) {
582 case 0:
583 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
584 break;
585 case 1:
586 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
587 break;
588 case 2:
589 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
590 break;
591 case 3:
592 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
593 break;
594 case 4:
595 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
596 break;
597 default:
598 pr_err("%s: Error, incorrect lineout register value\n",
599 __func__);
600 return -EINVAL;
601 }
602
603 switch (event) {
604 case SND_SOC_DAPM_PRE_PMU:
605 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
606 break;
607 case SND_SOC_DAPM_POST_PMU:
608 usleep_range(40000, 40000);
609 break;
610 case SND_SOC_DAPM_POST_PMD:
611 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
612 break;
613 }
614 return 0;
615}
616
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700617
618static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 struct snd_kcontrol *kcontrol, int event)
620{
621 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700622 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
623 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -0700624 unsigned int dmic;
625 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700626
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -0700627 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
628 if (ret < 0) {
629 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700630 return -EINVAL;
631 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -0700633 switch (dmic) {
634 case 1:
635 case 2:
636 dmic_clk_sel = 0x02;
637 dmic_clk_en = 0x01;
638 break;
639
640 case 3:
641 case 4:
642 dmic_clk_sel = 0x08;
643 dmic_clk_en = 0x04;
644 break;
645
646 case 5:
647 case 6:
648 dmic_clk_sel = 0x20;
649 dmic_clk_en = 0x10;
650 break;
651
652 default:
653 pr_err("%s: Invalid DMIC Selection\n", __func__);
654 return -EINVAL;
655 }
656
657 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
658 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662 switch (event) {
663 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700664 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
665
666 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
667 dmic_clk_sel, dmic_clk_sel);
668
669 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
670
671 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
672 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673 break;
674 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -0700675 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
676 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 break;
678 }
679 return 0;
680}
681
Bradley Rubin229c6a52011-07-12 16:18:48 -0700682static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
683 struct snd_kcontrol *kcontrol, int event)
684{
685 struct snd_soc_codec *codec = w->codec;
686 const char *filename;
687 const struct firmware *fw;
688 int i;
689 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -0700690 int num_anc_slots;
691 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700692 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -0700693 u32 anc_writes_size = 0;
694 int anc_size_remaining;
695 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700696 u16 reg;
697 u8 mask, val, old_val;
698
699 pr_debug("%s %d\n", __func__, event);
700 switch (event) {
701 case SND_SOC_DAPM_PRE_PMU:
702
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700703 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -0700704
705 ret = request_firmware(&fw, filename, codec->dev);
706 if (ret != 0) {
707 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
708 ret);
709 return -ENODEV;
710 }
711
Bradley Rubina7096d02011-08-03 18:29:02 -0700712 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -0700713 dev_err(codec->dev, "Not enough data\n");
714 release_firmware(fw);
715 return -ENOMEM;
716 }
717
718 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -0700719 anc_head = (struct anc_header *)(fw->data);
720 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
721 anc_size_remaining = fw->size - sizeof(struct anc_header);
722 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700723
Bradley Rubina7096d02011-08-03 18:29:02 -0700724 if (tabla->anc_slot >= num_anc_slots) {
725 dev_err(codec->dev, "Invalid ANC slot selected\n");
726 release_firmware(fw);
727 return -EINVAL;
728 }
729
730 for (i = 0; i < num_anc_slots; i++) {
731
732 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
733 dev_err(codec->dev, "Invalid register format\n");
734 release_firmware(fw);
735 return -EINVAL;
736 }
737 anc_writes_size = (u32)(*anc_ptr);
738 anc_size_remaining -= sizeof(u32);
739 anc_ptr += 1;
740
741 if (anc_writes_size * TABLA_PACKED_REG_SIZE
742 > anc_size_remaining) {
743 dev_err(codec->dev, "Invalid register format\n");
744 release_firmware(fw);
745 return -ENOMEM;
746 }
747
748 if (tabla->anc_slot == i)
749 break;
750
751 anc_size_remaining -= (anc_writes_size *
752 TABLA_PACKED_REG_SIZE);
753 anc_ptr += (anc_writes_size *
754 TABLA_PACKED_REG_SIZE);
755 }
756 if (i == num_anc_slots) {
757 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -0700758 release_firmware(fw);
759 return -ENOMEM;
760 }
761
Bradley Rubina7096d02011-08-03 18:29:02 -0700762 for (i = 0; i < anc_writes_size; i++) {
763 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -0700764 mask, val);
765 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -0700766 snd_soc_write(codec, reg, (old_val & ~mask) |
767 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -0700768 }
769 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700770
771 break;
772 case SND_SOC_DAPM_POST_PMD:
773 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
774 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
775 break;
776 }
777 return 0;
778}
779
Patrick Lai3043fba2011-08-01 14:15:57 -0700780static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
781 u8 cfilt_sel, int inc)
782{
783 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
784 u32 *cfilt_cnt_ptr = NULL;
785 u16 micb_cfilt_reg;
786
787 switch (cfilt_sel) {
788 case TABLA_CFILT1_SEL:
789 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
790 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
791 break;
792 case TABLA_CFILT2_SEL:
793 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
794 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
795 break;
796 case TABLA_CFILT3_SEL:
797 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
798 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
799 break;
800 default:
801 return; /* should not happen */
802 }
803
804 if (inc) {
805 if (!(*cfilt_cnt_ptr)++)
806 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
807 } else {
808 /* check if count not zero, decrement
809 * then check if zero, go ahead disable cfilter
810 */
811 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr))
812 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
813 }
814}
Bradley Rubin229c6a52011-07-12 16:18:48 -0700815
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700816static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
817{
818 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
819 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
820 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
821 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
822 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
823 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
824 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
825}
826
827static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
828{
829 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
830 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
831 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
832 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
833}
834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
836 struct snd_kcontrol *kcontrol, int event)
837{
838 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -0700839 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
840 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700841 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700842 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700843 char *internal1_text = "Internal1";
844 char *internal2_text = "Internal2";
845 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846
847 pr_debug("%s %d\n", __func__, event);
848 switch (w->reg) {
849 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700851 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700852 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853 break;
854 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700856 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700857 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858 break;
859 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700861 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700862 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700863 break;
864 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700865 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -0700866 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700867 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868 break;
869 default:
870 pr_err("%s: Error, invalid micbias register\n", __func__);
871 return -EINVAL;
872 }
873
874 switch (event) {
875 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700876 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -0700877 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700878
879 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700881 else if (strnstr(w->name, internal2_text, 30))
882 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
883 else if (strnstr(w->name, internal3_text, 30))
884 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -0700887 case SND_SOC_DAPM_POST_PMU:
888 if (tabla->mbhc_polling_active &&
889 (tabla->calibration->bias == micb_line)) {
890 tabla_codec_pause_hs_polling(codec);
891 tabla_codec_start_hs_polling(codec);
892 }
893 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 case SND_SOC_DAPM_POST_PMD:
Bradley Rubin229c6a52011-07-12 16:18:48 -0700895 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -0700897 else if (strnstr(w->name, internal2_text, 30))
898 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
899 else if (strnstr(w->name, internal3_text, 30))
900 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
901
Patrick Lai3043fba2011-08-01 14:15:57 -0700902 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 break;
904 }
905
906 return 0;
907}
908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
910 struct snd_kcontrol *kcontrol, int event)
911{
912 struct snd_soc_codec *codec = w->codec;
913 u16 dec_reset_reg;
914
915 pr_debug("%s %d\n", __func__, event);
916
917 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
918 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
919 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
920 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
921 else {
922 pr_err("%s: Error, incorrect dec\n", __func__);
923 return -EINVAL;
924 }
925
926 switch (event) {
927 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
929 1 << w->shift);
930 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
931 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 }
933 return 0;
934}
935
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700936static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937 struct snd_kcontrol *kcontrol, int event)
938{
939 struct snd_soc_codec *codec = w->codec;
940
941 switch (event) {
942 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700943 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
944 1 << w->shift, 1 << w->shift);
945 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
946 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 break;
948 }
949 return 0;
950}
951
Bradley Rubin229c6a52011-07-12 16:18:48 -0700952static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
953 struct snd_kcontrol *kcontrol, int event)
954{
955 switch (event) {
956 case SND_SOC_DAPM_POST_PMU:
957 case SND_SOC_DAPM_POST_PMD:
958 usleep_range(1000, 1000);
959 break;
960 }
961 return 0;
962}
963
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700964
965static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
966{
967 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
968
969 if (enable) {
970 tabla->rx_bias_count++;
971 if (tabla->rx_bias_count == 1)
972 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
973 0x80, 0x80);
974 } else {
975 tabla->rx_bias_count--;
976 if (!tabla->rx_bias_count)
977 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
978 0x80, 0x00);
979 }
980}
981
982static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
983 struct snd_kcontrol *kcontrol, int event)
984{
985 struct snd_soc_codec *codec = w->codec;
986
987 pr_debug("%s %d\n", __func__, event);
988
989 switch (event) {
990 case SND_SOC_DAPM_PRE_PMU:
991 tabla_enable_rx_bias(codec, 1);
992 break;
993 case SND_SOC_DAPM_POST_PMD:
994 tabla_enable_rx_bias(codec, 0);
995 break;
996 }
997 return 0;
998}
999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
1001 /*RX stuff */
1002 SND_SOC_DAPM_OUTPUT("EAR"),
1003
1004 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
1005 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
1006 SND_SOC_DAPM_PRE_PMD),
1007
1008 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
1009
Bradley Rubin229c6a52011-07-12 16:18:48 -07001010 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
1011 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012
Bradley Rubin229c6a52011-07-12 16:18:48 -07001013 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1014 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015
1016 /* Headphone */
1017 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
1018 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001019 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
1020 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021
1022 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001023 SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
1024 hphr_switch, ARRAY_SIZE(hphr_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025
1026 /* Speaker */
1027 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
1030 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1031 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001032 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
1033 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1034 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
1036 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1037 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001038 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
1039 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1040 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001041 SND_SOC_DAPM_PGA_E("LINEOUT5", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
1042 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1043 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001044
Bradley Rubin229c6a52011-07-12 16:18:48 -07001045 SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
1046 lineout1_switch, ARRAY_SIZE(lineout1_switch)),
1047 SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
1048 lineout2_switch, ARRAY_SIZE(lineout2_switch)),
1049 SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
1050 lineout3_switch, ARRAY_SIZE(lineout3_switch)),
1051 SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
1052 lineout4_switch, ARRAY_SIZE(lineout4_switch)),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001053 SND_SOC_DAPM_MIXER("LINEOUT5 DAC", TABLA_A_RX_LINE_5_DAC_CTL, 7, 0,
1054 lineout5_switch, ARRAY_SIZE(lineout5_switch)),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001055
Bradley Rubin229c6a52011-07-12 16:18:48 -07001056 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1057 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1058 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1059 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1060 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1061 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1062 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
1063 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1064 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
1065 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1066 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1067 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001068 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
1069 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001070
Bradley Rubin229c6a52011-07-12 16:18:48 -07001071 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1072 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1073
1074 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1075 &rx_mix1_inp1_mux),
1076 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1077 &rx_mix1_inp2_mux),
1078 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1079 &rx2_mix1_inp1_mux),
1080 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1081 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001082 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1083 &rx3_mix1_inp1_mux),
1084 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1085 &rx3_mix1_inp2_mux),
1086 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1087 &rx4_mix1_inp1_mux),
1088 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1089 &rx4_mix1_inp2_mux),
1090 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1091 &rx5_mix1_inp1_mux),
1092 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1093 &rx5_mix1_inp2_mux),
1094 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1095 &rx6_mix1_inp1_mux),
1096 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1097 &rx6_mix1_inp2_mux),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001098 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1099 &rx7_mix1_inp1_mux),
1100 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1101 &rx7_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102
Bradley Rubin229c6a52011-07-12 16:18:48 -07001103 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
1104 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1105 SND_SOC_DAPM_PRE_PMD),
1106
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001107 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
1108 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
1109 SND_SOC_DAPM_POST_PMD),
1110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001112
Bradley Rubine1d08622011-07-20 18:01:35 -07001113 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1114 0),
1115
Bradley Rubin229c6a52011-07-12 16:18:48 -07001116 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
1117 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 SND_SOC_DAPM_INPUT("AMIC1"),
1120 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
1121 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001122 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001123 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
1124 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001125 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001126 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001128 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
1130 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1131 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1132
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001133 SND_SOC_DAPM_INPUT("AMIC3"),
1134 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
1135 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1136 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1137
1138 SND_SOC_DAPM_INPUT("AMIC4"),
1139 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1140 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1141 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1142
1143 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1144 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001145 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001146
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001147 SND_SOC_DAPM_INPUT("AMIC5"),
1148 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
1149 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1150
1151 SND_SOC_DAPM_INPUT("AMIC6"),
1152 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
1153 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 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 -07001156 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001158 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 -07001159 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001160
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001161 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 -07001162 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001163
1164 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 -07001165 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 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 -07001168 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169
1170 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 -07001171 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172
1173 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 -07001174 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001176 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 -07001177 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001178
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001179 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 -07001180 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001181
1182 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 -07001183 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001184
Bradley Rubin229c6a52011-07-12 16:18:48 -07001185 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1186 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1187
1188 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1189 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1190 SND_SOC_DAPM_POST_PMD),
1191
1192 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 SND_SOC_DAPM_INPUT("AMIC2"),
1195 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
1196 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001197 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001198 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
1199 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001200 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001201 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
1202 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001203 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001204 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001206 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
1208 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001209 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001210 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
1211 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001212 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001213 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001215 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
1217 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1218 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1219
1220 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1221 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
1222 0, 0),
1223
1224 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
1225 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
1226 4, 0),
1227
1228 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
1229 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
1230 5, 0),
1231
1232 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
1233 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
1234 0, 0),
1235
1236 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
1237 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
1238 0, 0),
1239
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001240 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001241 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
1242 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1243 SND_SOC_DAPM_POST_PMD),
1244
1245 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
1246 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1247 SND_SOC_DAPM_POST_PMD),
1248
1249 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
1250 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1251 SND_SOC_DAPM_POST_PMD),
1252
1253 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
1254 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1255 SND_SOC_DAPM_POST_PMD),
1256
1257 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
1258 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1259 SND_SOC_DAPM_POST_PMD),
1260
1261 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
1262 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1263 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264
1265 /* Sidetone */
1266 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1267 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1268};
1269
1270static const struct snd_soc_dapm_route audio_map[] = {
1271 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272
1273 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1274 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1275
1276 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1277 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1278
1279 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1280 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1281
1282 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1283 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001284 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001285 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1286 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1288 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001289 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1290 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001291 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1292 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293
1294 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001295 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1296 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1297 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1299 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1300
1301 /* Earpiece (RX MIX1) */
1302 {"EAR", NULL, "EAR PA"},
1303 {"EAR PA", NULL, "EAR PA Input"},
1304 {"EAR PA Input", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001305 {"DAC1", NULL, "CP"},
1306
1307 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
1308 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
1309 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310
1311 /* Headset (RX MIX1 and RX MIX2) */
1312 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001314
1315 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001317
1318 {"HPHL DAC", NULL, "CP"},
1319 {"HPHR DAC", NULL, "CP"},
1320
1321 {"ANC", NULL, "ANC1 MUX"},
1322 {"ANC", NULL, "ANC2 MUX"},
1323 {"ANC1 MUX", "ADC1", "ADC1"},
1324 {"ANC1 MUX", "ADC2", "ADC2"},
1325 {"ANC1 MUX", "ADC3", "ADC3"},
1326 {"ANC1 MUX", "ADC4", "ADC4"},
1327 {"ANC2 MUX", "ADC1", "ADC1"},
1328 {"ANC2 MUX", "ADC2", "ADC2"},
1329 {"ANC2 MUX", "ADC3", "ADC3"},
1330 {"ANC2 MUX", "ADC4", "ADC4"},
1331
Bradley Rubine1d08622011-07-20 18:01:35 -07001332 {"ANC", NULL, "CDC_CONN"},
1333
Bradley Rubin229c6a52011-07-12 16:18:48 -07001334 {"DAC1", "Switch", "RX1 CHAIN"},
1335 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1336 {"HPHR DAC", "Switch", "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001339 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001341 {"LINEOUT", NULL, "LINEOUT4"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001342 {"LINEOUT", NULL, "LINEOUT5"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001343
1344 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
1345 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001347 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001348 {"LINEOUT5", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001349
Bradley Rubin229c6a52011-07-12 16:18:48 -07001350 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1351 {"RX2 CHAIN", NULL, "RX2 MIX1"},
1352 {"RX1 CHAIN", NULL, "ANC"},
1353 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001354 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
1355 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
Kiran Kandied246a92011-08-12 14:03:44 -07001356 {"LINEOUT3 DAC", "Switch", "RX3 MIX1"},
1357 {"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001358 {"LINEOUT5 DAC", "Switch", "RX7 MIX1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001359
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001360 {"DAC1", NULL, "RX_BIAS"},
1361 {"HPHL DAC", NULL, "RX_BIAS"},
1362 {"HPHR DAC", NULL, "RX_BIAS"},
1363 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
1364 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
1365 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
1366 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
1367
Bradley Rubin229c6a52011-07-12 16:18:48 -07001368 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1369 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1370 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1371 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001372 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1373 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1374 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
1375 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
1376 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
1377 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
1378 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
1379 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001380 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
1381 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001382
Bradley Rubin229c6a52011-07-12 16:18:48 -07001383 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1384 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1385 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1386 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1387 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1388 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1389 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1390 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1391 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1392 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1393 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1394 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1395 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1396 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1397 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
1398 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
1399 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
1400 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
1401 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
1402 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
1403 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
1404 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
1405 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
1406 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
1407 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
1408 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001409 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
1410 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
1411 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
1412 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001414 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001415 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001416 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001417 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001418 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001419 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001420 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001421 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001422 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001423 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001424 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001425 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001426 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001427 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001429 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001430 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001432 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001433 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001434 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001435 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001436 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001437 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001438 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001439 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001440 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07001441 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001442
1443 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 {"ADC1", NULL, "AMIC1"},
1445 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001446 {"ADC3", NULL, "AMIC3"},
1447 {"ADC4", NULL, "AMIC4"},
1448 {"ADC5", NULL, "AMIC5"},
1449 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 {"IIR1", NULL, "IIR1 INP1 MUX"},
1452 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07001453
1454 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1455 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
1456 {"MIC BIAS1 External", NULL, "LDO_H"},
1457 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1458 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
1459 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
1460 {"MIC BIAS2 External", NULL, "LDO_H"},
1461 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
1462 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
1463 {"MIC BIAS3 External", NULL, "LDO_H"},
1464 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465};
1466
1467static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
1468{
1469 return tabla_reg_readable[reg];
1470}
1471
1472static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1473{
1474 /* Registers lower than 0x100 are top level registers which can be
1475 * written by the Tabla core driver.
1476 */
1477
1478 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1479 return 1;
1480
1481 return 0;
1482}
1483
1484#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1485static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
1486 unsigned int value)
1487{
1488 int ret;
1489 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
1490
1491 BUG_ON(reg > TABLA_MAX_REGISTER);
1492
1493 if (!tabla_volatile(codec, reg)) {
1494 pr_debug("writing to cache\n");
1495 ret = snd_soc_cache_write(codec, reg, value);
1496 if (ret != 0)
1497 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1498 reg, ret);
1499 }
1500
1501 return tabla_reg_write(codec->control_data, reg, value);
1502}
1503static unsigned int tabla_read(struct snd_soc_codec *codec,
1504 unsigned int reg)
1505{
1506 unsigned int val;
1507 int ret;
1508
1509 BUG_ON(reg > TABLA_MAX_REGISTER);
1510
1511 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
1512 reg < codec->driver->reg_cache_size) {
1513 pr_debug("reading from cache\n");
1514 ret = snd_soc_cache_read(codec, reg, &val);
1515 if (ret >= 0) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001516 pr_debug("register %x, value %x\n", reg, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 return val;
1518 } else
1519 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1520 reg, ret);
1521 }
1522
1523 val = tabla_reg_read(codec->control_data, reg);
1524 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
1525 return val;
1526}
1527
1528static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1529{
1530 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1531 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1532 0x80);
1533 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1534 0x04);
1535 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1536 0x01);
1537 usleep_range(1000, 1000);
1538 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1539 0x00);
1540}
1541
1542static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1543 enum tabla_bandgap_type choice)
1544{
1545 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1546
1547 /* TODO lock resources accessed by audio streams and threaded
1548 * interrupt handlers
1549 */
1550
1551 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1552 tabla->bandgap_type);
1553
1554 if (tabla->bandgap_type == choice)
1555 return;
1556
1557 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1558 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1559 tabla_codec_enable_audio_mode_bandgap(codec);
1560 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
1561 (choice == TABLA_BANDGAP_MBHC_MODE)) {
1562 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1563 0x2);
1564 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1565 0x80);
1566 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1567 0x4);
1568 usleep_range(1000, 1000);
1569 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1570 0x00);
1571 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1572 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1573 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1574 usleep_range(100, 100);
1575 tabla_codec_enable_audio_mode_bandgap(codec);
1576 } else if (choice == TABLA_BANDGAP_OFF) {
1577 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1578 } else {
1579 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1580 }
1581 tabla->bandgap_type = choice;
1582}
1583
1584static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1585 int enable)
1586{
1587 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1588
1589 if (enable) {
1590 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1591 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1592 usleep_range(5, 5);
1593 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1594 0x80);
1595 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1596 0x80);
1597 usleep_range(10, 10);
1598 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1599 usleep_range(20, 20);
1600 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1601 } else {
1602 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1603 0);
1604 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1605 }
1606 tabla->config_mode_active = enable ? true : false;
1607
1608 return 0;
1609}
1610
1611static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1612 int config_mode)
1613{
1614 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1615
1616 pr_debug("%s\n", __func__);
1617
1618 if (config_mode) {
1619 tabla_codec_enable_config_mode(codec, 1);
1620 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1621 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1622 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1623 usleep_range(1000, 1000);
1624 } else
1625 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1626
1627 if (!config_mode && tabla->mbhc_polling_active) {
1628 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1629 tabla_codec_enable_config_mode(codec, 0);
1630
1631 }
1632
1633 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1634 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1635 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1636 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1637 usleep_range(50, 50);
1638 tabla->clock_active = true;
1639 return 0;
1640}
1641static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1642{
1643 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1644 pr_debug("%s\n", __func__);
1645 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1646 ndelay(160);
1647 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1648 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1649 tabla->clock_active = false;
1650}
1651
Bradley Rubincb1e2732011-06-23 16:49:20 -07001652static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1653{
1654 /* TODO store register values in calibration */
1655
1656 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1657 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1658
1659 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1660 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1661 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1662 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1663
1664 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1665 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1666 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1667 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1668 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1669 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1670}
1671
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672static int tabla_startup(struct snd_pcm_substream *substream,
1673 struct snd_soc_dai *dai)
1674{
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001675 pr_debug("%s() substream = %s\n", __func__, substream->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001677 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678}
1679
1680static void tabla_shutdown(struct snd_pcm_substream *substream,
1681 struct snd_soc_dai *dai)
1682{
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001683 pr_debug("%s() substream = %s\n", __func__, substream->name);
1684}
1685
1686
1687int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
1688{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1690
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001691 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001693 if (mclk_enable) {
1694 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001696 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001697 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 tabla_codec_enable_bandgap(codec,
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001699 TABLA_BANDGAP_AUDIO_MODE);
1700 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001701 tabla_codec_calibrate_hs_polling(codec);
1702 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 }
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001704 } else {
1705
1706 if (!tabla->mclk_enabled) {
1707 pr_err("Error, MCLK already diabled\n");
1708 return -EINVAL;
1709 }
1710 tabla->mclk_enabled = false;
1711
1712 if (tabla->mbhc_polling_active) {
1713 if (!tabla->mclk_enabled) {
1714 tabla_codec_pause_hs_polling(codec);
1715 tabla_codec_enable_bandgap(codec,
1716 TABLA_BANDGAP_MBHC_MODE);
1717 tabla_enable_rx_bias(codec, 1);
1718 tabla_codec_enable_clock_block(codec, 1);
1719 tabla_codec_calibrate_hs_polling(codec);
1720 tabla_codec_start_hs_polling(codec);
1721 }
1722 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
1723 0x05, 0x01);
1724 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 }
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001726 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727}
1728
1729static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1730{
1731 struct snd_soc_codec *codec = codec_dai->codec;
1732
1733 pr_debug("%s %d\n", __func__, mute);
1734
1735 /* TODO mute TX */
1736 if (mute)
1737 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1738 else
1739 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1740
1741 return 0;
1742}
1743
1744static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1745 int clk_id, unsigned int freq, int dir)
1746{
1747 pr_debug("%s\n", __func__);
1748 return 0;
1749}
1750
1751static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1752{
1753 pr_debug("%s\n", __func__);
1754 return 0;
1755}
1756
1757static int tabla_hw_params(struct snd_pcm_substream *substream,
1758 struct snd_pcm_hw_params *params,
1759 struct snd_soc_dai *dai)
1760{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07001761 struct snd_soc_codec *codec = dai->codec;
1762 u8 path, tx_fs_reg, rx_fs_reg, shift;
1763 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
1764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07001766
1767 switch (params_rate(params)) {
1768 case 8000:
1769 tx_fs_rate = 0x00;
1770 rx_fs_rate = 0x00;
1771 break;
1772 case 16000:
1773 tx_fs_rate = 0x01;
1774 rx_fs_rate = 0x20;
1775 break;
1776 case 32000:
1777 tx_fs_rate = 0x02;
1778 rx_fs_rate = 0x40;
1779 break;
1780 case 48000:
1781 tx_fs_rate = 0x03;
1782 rx_fs_rate = 0x60;
1783 break;
1784 default:
1785 pr_err("%s: Invalid sampling rate %d\n", __func__,
1786 params_rate(params));
1787 return -EINVAL;
1788 }
1789
1790
1791 /**
1792 * If current dai is a tx dai, set sample rate to
1793 * all the txfe paths that are currently not active
1794 */
1795 if (dai->id == TABLA_TX_DAI_ID) {
1796
1797 tx_state = snd_soc_read(codec,
1798 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
1799
1800 for (path = 1, shift = 0;
1801 path <= NUM_DECIMATORS; path++, shift++) {
1802
1803 if (path == BITS_PER_REG + 1) {
1804 shift = 0;
1805 tx_state = snd_soc_read(codec,
1806 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
1807 }
1808
1809 if (!(tx_state & (1 << shift))) {
1810 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
1811 + (BITS_PER_REG*(path-1));
1812 snd_soc_update_bits(codec, tx_fs_reg,
1813 0x03, tx_fs_rate);
1814 }
1815 }
1816 }
1817
1818 /**
1819 * TODO: Need to handle case where same RX chain takes 2 or more inputs
1820 * with varying sample rates
1821 */
1822
1823 /**
1824 * If current dai is a rx dai, set sample rate to
1825 * all the rx paths that are currently not active
1826 */
1827 if (dai->id == TABLA_RX_DAI_ID) {
1828
1829 rx_state = snd_soc_read(codec,
1830 TABLA_A_CDC_CLK_RX_B1_CTL);
1831
1832 for (path = 1, shift = 0;
1833 path <= NUM_INTERPOLATORS; path++, shift++) {
1834
1835 if (!(rx_state & (1 << shift))) {
1836 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
1837 + (BITS_PER_REG*(path-1));
1838 snd_soc_update_bits(codec, rx_fs_reg,
1839 0xE0, rx_fs_rate);
1840 }
1841 }
1842 }
1843
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 return 0;
1845}
1846
1847static struct snd_soc_dai_ops tabla_dai_ops = {
1848 .startup = tabla_startup,
1849 .shutdown = tabla_shutdown,
1850 .hw_params = tabla_hw_params,
1851 .set_sysclk = tabla_set_dai_sysclk,
1852 .set_fmt = tabla_set_dai_fmt,
1853 .digital_mute = tabla_digital_mute,
1854};
1855
1856static struct snd_soc_dai_driver tabla_dai[] = {
1857 {
1858 .name = "tabla_rx1",
1859 .id = 1,
1860 .playback = {
1861 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07001862 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 .formats = TABLA_FORMATS,
1864 .rate_max = 48000,
1865 .rate_min = 8000,
1866 .channels_min = 1,
1867 .channels_max = 2,
1868 },
1869 .ops = &tabla_dai_ops,
1870 },
1871 {
1872 .name = "tabla_tx1",
1873 .id = 2,
1874 .capture = {
1875 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07001876 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877 .formats = TABLA_FORMATS,
1878 .rate_max = 48000,
1879 .rate_min = 8000,
1880 .channels_min = 1,
1881 .channels_max = 2,
1882 },
1883 .ops = &tabla_dai_ops,
1884 },
1885};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001886static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07001887{
1888 u8 bias_msb, bias_lsb;
1889 short bias_value;
1890
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001891 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1892 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1893 bias_value = (bias_msb << 8) | bias_lsb;
1894 return bias_value;
1895}
1896
1897static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
1898{
1899 u8 bias_msb, bias_lsb;
1900 short bias_value;
1901
1902 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1903 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1904 bias_value = (bias_msb << 8) | bias_lsb;
1905 return bias_value;
1906}
1907
1908static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1909 int dce)
1910{
1911 short bias_value;
1912
Bradley Rubincb1e2732011-06-23 16:49:20 -07001913 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001914 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1915 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1916 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1917 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
1918 usleep_range(60000, 60000);
1919 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001920 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001921 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001922 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1923 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001924 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001925 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07001926 usleep_range(50, 50);
1927 bias_value = tabla_codec_read_sta_result(codec);
1928 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1929 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001930 }
1931
Bradley Rubincb1e2732011-06-23 16:49:20 -07001932 pr_debug("read microphone bias value %x\n", bias_value);
1933 return bias_value;
1934}
1935
1936static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001937{
1938 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1939 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Patrick Lai3043fba2011-08-01 14:15:57 -07001940 int micbias_ctl_reg, micbias_cfilt_ctl_reg,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001941 micbias_mbhc_reg;
1942 short bias_value, threshold_no_mic;
Patrick Lai3043fba2011-08-01 14:15:57 -07001943 unsigned int cfilt_sel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944
1945 if (!calibration) {
1946 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001947 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 }
1949
1950 tabla->mbhc_polling_active = true;
1951
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001952 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi3a30bda2011-08-15 10:36:42 -07001954 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955 tabla_codec_enable_clock_block(codec, 1);
1956 }
1957
1958 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1961
Patrick Lai3043fba2011-08-01 14:15:57 -07001962 /* select cfilt separately from the micbias line in the platform data */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 switch (calibration->bias) {
1964 case TABLA_MICBIAS1:
1965 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001966 cfilt_sel = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001967 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001968 break;
1969 case TABLA_MICBIAS2:
1970 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001971 cfilt_sel = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001972 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973 break;
1974 case TABLA_MICBIAS3:
1975 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
Patrick Lai3043fba2011-08-01 14:15:57 -07001976 cfilt_sel = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001977 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978 break;
1979 case TABLA_MICBIAS4:
1980 pr_err("%s: Error, microphone bias 4 not supported\n",
1981 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001982 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 default:
1984 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001985 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 }
Patrick Lai3043fba2011-08-01 14:15:57 -07001987
1988 switch (cfilt_sel) {
1989 case TABLA_CFILT1_SEL:
1990 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1991 break;
1992 case TABLA_CFILT2_SEL:
1993 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1994 break;
1995 case TABLA_CFILT3_SEL:
1996 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1997 break;
1998 default: /* default should not happen as check should have been done */
1999 return -EINVAL;
2000 }
2001
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002002 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003
Bradley Rubincb1e2732011-06-23 16:49:20 -07002004 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005
2006 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002007 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008
2009 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
2010 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
2011 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
2012
2013 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002014 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2015 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016
Bradley Rubincb1e2732011-06-23 16:49:20 -07002017 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2019
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002020 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002021 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
2022
2023 tabla_codec_calibrate_hs_polling(codec);
2024
2025 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002026 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
2027 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002028 threshold_no_mic = 0xF7F6;
2029
2030 if (bias_value < threshold_no_mic) {
2031 pr_debug("headphone detected, micbias %x\n", bias_value);
2032 return 0;
2033 } else {
2034 pr_debug("headset detected, micbias %x\n", bias_value);
2035 return 1;
2036 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037}
2038
2039static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
2040 int insertion)
2041{
2042 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2043 struct tabla_mbhc_calibration *calibration = tabla->calibration;
2044 int central_bias_enabled = 0;
2045 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
2046
2047 if (!calibration) {
2048 pr_err("Error, no tabla calibration\n");
2049 return -EINVAL;
2050 }
2051
2052 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
2053
2054 if (insertion)
2055 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
2056 else
2057 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
2058
2059 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
2060 if (!(tabla->clock_active)) {
2061 tabla_codec_enable_config_mode(codec, 1);
2062 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002063 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 usleep_range(calibration->shutdown_plug_removal,
2065 calibration->shutdown_plug_removal);
2066 tabla_codec_enable_config_mode(codec, 0);
2067 } else
2068 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002069 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070 }
2071
2072 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
2073 calibration->hph_current << 2);
2074
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002075 /* Turn off HPH PAs during insertion detection to avoid false
2076 * insertion interrupts
2077 */
2078 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
2080
2081 switch (calibration->bias) {
2082 case TABLA_MICBIAS1:
2083 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
2084 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
2085 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
2086 break;
2087 case TABLA_MICBIAS2:
2088 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
2089 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
2090 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
2091 break;
2092 case TABLA_MICBIAS3:
2093 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
2094 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
2095 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
2096 break;
2097 case TABLA_MICBIAS4:
2098 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
2099 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
2100 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
2101 break;
2102 default:
2103 pr_err("Error, invalid mic bias line\n");
2104 return -EINVAL;
2105 }
2106 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
2107 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
2108
2109 /* If central bandgap disabled */
2110 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
2111 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
2112 usleep_range(calibration->bg_fast_settle,
2113 calibration->bg_fast_settle);
2114 central_bias_enabled = 1;
2115 }
2116
2117 /* If LDO_H disabled */
2118 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
2119 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
2120 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
2121 usleep_range(calibration->tldoh, calibration->tldoh);
2122 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
2123
2124 if (central_bias_enabled)
2125 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
2126 }
2127 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
2128 calibration->mic_current << 5);
2129 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
2130 usleep_range(calibration->mic_pid, calibration->mic_pid);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002132 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
2133
2134 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
2135
2136 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2137 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
2138 return 0;
2139}
2140
Bradley Rubincb1e2732011-06-23 16:49:20 -07002141int tabla_hs_detect(struct snd_soc_codec *codec,
2142 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143 struct tabla_mbhc_calibration *calibration)
2144{
2145 struct tabla_priv *tabla;
2146 if (!codec || !calibration) {
2147 pr_err("Error: no codec or calibration\n");
2148 return -EINVAL;
2149 }
2150 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002151 tabla->headset_jack = headset_jack;
2152 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 tabla->calibration = calibration;
2154
2155 return tabla_codec_enable_hs_detect(codec, 1);
2156}
2157EXPORT_SYMBOL_GPL(tabla_hs_detect);
2158
Bradley Rubin688c66a2011-08-16 12:25:13 -07002159#define TABLA_BUTTON_MARGIN_ERROR 4
Bradley Rubincb1e2732011-06-23 16:49:20 -07002160static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161{
2162 struct tabla_priv *priv = data;
2163 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin688c66a2011-08-16 12:25:13 -07002164 short bias_value, bias_value2;
Bradley Rubincb1e2732011-06-23 16:49:20 -07002165
2166 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2167 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2168
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002169 bias_value = tabla_codec_read_dce_result(codec);
2170 pr_debug("button press interrupt, bias value is %d\n", bias_value);
2171
Bradley Rubin688c66a2011-08-16 12:25:13 -07002172 /* Do another DCE to make sure button voltage is the same */
2173 bias_value2 = tabla_codec_measure_micbias_voltage(codec, 1);
2174 pr_debug("button press part 2, bias value is %d\n", bias_value2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002175
Bradley Rubin688c66a2011-08-16 12:25:13 -07002176 if (abs(bias_value - bias_value2) < TABLA_BUTTON_MARGIN_ERROR) {
2177 if (priv->button_jack)
2178 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
2179 SND_JACK_BTN_0);
2180
2181 priv->buttons_pressed |= SND_JACK_BTN_0;
2182 }
2183 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x09);
2184 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 return IRQ_HANDLED;
2187}
2188
Bradley Rubincb1e2732011-06-23 16:49:20 -07002189static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002190{
2191 struct tabla_priv *priv = data;
2192 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002193 pr_debug("%s\n", __func__);
2194 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002195 if (priv->buttons_pressed & SND_JACK_BTN_0) {
2196 pr_debug("%s: Button released\n", __func__);
2197 if (priv->button_jack)
2198 snd_soc_jack_report(priv->button_jack, 0,
2199 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002200
Bradley Rubincb1e2732011-06-23 16:49:20 -07002201 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002203
Bradley Rubin688c66a2011-08-16 12:25:13 -07002204 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
2205 tabla_codec_start_hs_polling(codec);
2206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002207 return IRQ_HANDLED;
2208}
2209
Bradley Rubincb1e2732011-06-23 16:49:20 -07002210static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
2211{
2212 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2213 struct tabla_mbhc_calibration *calibration = tabla->calibration;
2214 int micbias_mbhc_reg;
2215
Kiran Kandi3a30bda2011-08-15 10:36:42 -07002216 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07002217 tabla_codec_enable_config_mode(codec, 1);
2218
2219 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2220 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002221
2222 switch (calibration->bias) {
2223 case TABLA_MICBIAS1:
2224 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
2225 break;
2226 case TABLA_MICBIAS2:
2227 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
2228 break;
2229 case TABLA_MICBIAS3:
2230 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
2231 break;
2232 case TABLA_MICBIAS4:
2233 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
2234 break;
2235 default:
2236 pr_err("Error, invalid mic bias line\n");
2237 return;
2238 }
2239 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002240 usleep_range(calibration->shutdown_plug_removal,
2241 calibration->shutdown_plug_removal);
2242
2243 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi3a30bda2011-08-15 10:36:42 -07002244 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07002245 tabla_codec_enable_config_mode(codec, 0);
2246
2247 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
2248}
2249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
2251{
2252 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002253
2254 tabla_codec_shutdown_hs_removal_detect(codec);
2255
Kiran Kandi3a30bda2011-08-15 10:36:42 -07002256 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
2258 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2259 tabla_codec_enable_clock_block(codec, 0);
2260 }
2261
2262 tabla->mbhc_polling_active = false;
2263}
2264
Bradley Rubincb1e2732011-06-23 16:49:20 -07002265static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
2266{
2267 struct tabla_priv *priv = data;
2268 struct snd_soc_codec *codec = priv->codec;
2269 int microphone_present;
2270
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002271 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002272 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2273
2274 usleep_range(priv->calibration->setup_plug_removal_delay,
2275 priv->calibration->setup_plug_removal_delay);
2276
2277 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
2278 if (priv->headset_jack) {
2279 pr_debug("%s: Reporting removal\n", __func__);
2280 snd_soc_jack_report(priv->headset_jack, 0,
2281 SND_JACK_HEADSET);
2282 }
2283 tabla_codec_shutdown_hs_removal_detect(codec);
2284 tabla_codec_enable_hs_detect(codec, 1);
2285 return IRQ_HANDLED;
2286 }
2287
2288 microphone_present = tabla_codec_setup_hs_polling(codec);
2289
2290 if (microphone_present == 0) {
2291 if (priv->headset_jack) {
2292 pr_debug("%s: Reporting insertion %d\n", __func__,
2293 SND_JACK_HEADPHONE);
2294 snd_soc_jack_report(priv->headset_jack,
2295 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
2296 }
2297 tabla_codec_shutdown_hs_polling(codec);
2298 tabla_codec_enable_hs_detect(codec, 0);
2299 } else if (microphone_present == 1) {
2300 if (priv->headset_jack) {
2301 pr_debug("%s: Reporting insertion %d\n", __func__,
2302 SND_JACK_HEADSET);
2303 snd_soc_jack_report(priv->headset_jack,
2304 SND_JACK_HEADSET, SND_JACK_HEADSET);
2305 }
2306 tabla_codec_start_hs_polling(codec);
2307 }
2308
2309 return IRQ_HANDLED;
2310}
2311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
2313{
2314 struct tabla_priv *priv = data;
2315 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002316 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317
2318 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2319 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002320 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321
2322 usleep_range(priv->calibration->shutdown_plug_removal,
2323 priv->calibration->shutdown_plug_removal);
2324
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002325 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
2326 pr_debug("removal interrupt, bias value is %d\n", bias_value);
2327
2328 if (bias_value < -90) {
2329 pr_debug("False alarm, headset not actually removed\n");
2330 tabla_codec_start_hs_polling(codec);
2331 } else {
2332 if (priv->headset_jack) {
2333 pr_debug("%s: Reporting removal\n", __func__);
2334 snd_soc_jack_report(priv->headset_jack, 0,
2335 SND_JACK_HEADSET);
2336 }
2337 tabla_codec_shutdown_hs_polling(codec);
2338
2339 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 return IRQ_HANDLED;
2342}
2343
2344static unsigned long slimbus_value;
2345
2346static irqreturn_t tabla_slimbus_irq(int irq, void *data)
2347{
2348 struct tabla_priv *priv = data;
2349 struct snd_soc_codec *codec = priv->codec;
2350 int i, j;
2351 u8 val;
2352
2353 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
2354 slimbus_value = tabla_interface_reg_read(codec->control_data,
2355 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
2356 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
2357 val = tabla_interface_reg_read(codec->control_data,
2358 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
2359 if (val & 0x1)
2360 pr_err_ratelimited("overflow error on port %x,"
2361 " value %x\n", i*8 + j, val);
2362 if (val & 0x2)
2363 pr_err_ratelimited("underflow error on port %x,"
2364 " value %x\n", i*8 + j, val);
2365 }
2366 tabla_interface_reg_write(codec->control_data,
2367 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
2368 }
2369
2370 return IRQ_HANDLED;
2371}
2372
Patrick Lai3043fba2011-08-01 14:15:57 -07002373static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2374{
2375 int rc = -EINVAL;
2376 unsigned min_mv, max_mv;
2377
2378 switch (ldoh_v) {
2379 case TABLA_LDOH_1P95_V:
2380 min_mv = 160;
2381 max_mv = 1800;
2382 break;
2383 case TABLA_LDOH_2P35_V:
2384 min_mv = 200;
2385 max_mv = 2200;
2386 break;
2387 case TABLA_LDOH_2P75_V:
2388 min_mv = 240;
2389 max_mv = 2600;
2390 break;
2391 case TABLA_LDOH_2P85_V:
2392 min_mv = 250;
2393 max_mv = 2700;
2394 break;
2395 default:
2396 goto done;
2397 }
2398
2399 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2400 goto done;
2401
2402 for (rc = 4; rc <= 44; rc++) {
2403 min_mv = max_mv * (rc) / 44;
2404 if (min_mv >= cfilt_mv) {
2405 rc -= 4;
2406 break;
2407 }
2408 }
2409done:
2410 return rc;
2411}
2412
2413static int tabla_handle_pdata(struct tabla_priv *tabla)
2414{
2415 struct snd_soc_codec *codec = tabla->codec;
2416 struct tabla_pdata *pdata = tabla->pdata;
2417 int k1, k2, k3, rc = 0;
2418
2419 if (!pdata) {
2420 rc = -ENODEV;
2421 goto done;
2422 }
2423
2424 /* Make sure settings are correct */
2425 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
2426 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
2427 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
2428 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
2429 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
2430 rc = -EINVAL;
2431 goto done;
2432 }
2433
2434 /* figure out k value */
2435 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
2436 pdata->micbias.cfilt1_mv);
2437 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
2438 pdata->micbias.cfilt2_mv);
2439 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
2440 pdata->micbias.cfilt3_mv);
2441
2442 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
2443 rc = -EINVAL;
2444 goto done;
2445 }
2446
2447 /* Set voltage level and always use LDO */
2448 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
2449 (pdata->micbias.ldoh_v << 2));
2450
2451 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
2452 (k1 << 2));
2453 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
2454 (k2 << 2));
2455 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
2456 (k3 << 2));
2457
2458 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
2459 (pdata->micbias.bias1_cfilt_sel << 5));
2460 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
2461 (pdata->micbias.bias2_cfilt_sel << 5));
2462 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
2463 (pdata->micbias.bias3_cfilt_sel << 5));
2464 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
2465 (pdata->micbias.bias4_cfilt_sel << 5));
2466
2467done:
2468 return rc;
2469}
2470
Kiran Kandi1f6fd722011-08-11 10:36:11 -07002471static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
2472
2473 /* Tabla 1.1 MICBIAS changes */
2474 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
2475 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
2476 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
2477 TABLA_REG_VAL(TABLA_A_MICB_4_INT_RBIAS, 0x24),
2478
2479 /* Tabla 1.1 HPH changes */
2480 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
2481 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
2482
2483 /* Tabla 1.1 EAR PA changes */
2484 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
2485 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
2486 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
2487
2488 /* Tabla 1.1 Lineout_5 Changes */
2489 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
2490
2491 /* Tabla 1.1 RX Changes */
2492 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
2493 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
2494 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
2495 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
2496 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
2497 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
2498 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
2499
2500 /* Tabla 1.1 RX1 and RX2 Changes */
2501 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
2502 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
2503
2504 /* Tabla 1.1 RX3 to RX7 Changes */
2505 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
2506 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
2507 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
2508 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
2509 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
2510
2511 /* Tabla 1.1 CLASSG Changes */
2512 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
2513};
2514
2515static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
2516
2517 /* Tabla 2.0 MICBIAS changes */
2518 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
2519};
2520
2521static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
2522{
2523 u32 i;
2524
2525 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
2526 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
2527 tabla_1_1_reg_defaults[i].val);
2528
2529 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
2530 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
2531 tabla_2_0_reg_defaults[i].val);
2532}
2533
2534static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
2535
2536 /* Initialize gain registers to use register gain */
2537 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
2538 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
2539 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
2540 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
2541 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
2542 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
2543
2544 /* Initialize mic biases to differential mode */
2545 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
2546 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
2547 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
2548 {TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24},
2549
2550 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
2551
2552 /* Use 16 bit sample size for TX1 to TX6 */
2553 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
2554 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
2555 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
2556 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
2557 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
2558 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
2559
2560 /* Use 16 bit sample size for TX7 to TX10 */
2561 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
2562 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
2563 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
2564 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
2565
2566 /* Use 16 bit sample size for RX */
2567 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
2568 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
2569
2570 /*enable HPF filter for TX paths */
2571 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2572 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2573 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
2574 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
2575 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
2576 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
2577 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
2578 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
2579 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
2580 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
2581};
2582
2583static void tabla_codec_init_reg(struct snd_soc_codec *codec)
2584{
2585 u32 i;
2586
2587 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
2588 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
2589 tabla_codec_reg_init_val[i].mask,
2590 tabla_codec_reg_init_val[i].val);
2591}
2592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593static int tabla_codec_probe(struct snd_soc_codec *codec)
2594{
2595 struct tabla *control;
2596 struct tabla_priv *tabla;
2597 struct snd_soc_dapm_context *dapm = &codec->dapm;
2598 int ret = 0;
2599 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600
2601 codec->control_data = dev_get_drvdata(codec->dev->parent);
2602 control = codec->control_data;
2603
2604 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
2605 if (!tabla) {
2606 dev_err(codec->dev, "Failed to allocate private data\n");
2607 return -ENOMEM;
2608 }
2609
2610 snd_soc_codec_set_drvdata(codec, tabla);
2611
Kiran Kandi3a30bda2011-08-15 10:36:42 -07002612 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002613 tabla->bandgap_type = TABLA_BANDGAP_OFF;
2614 tabla->clock_active = false;
2615 tabla->config_mode_active = false;
2616 tabla->mbhc_polling_active = false;
2617 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002618 tabla->pdata = dev_get_platdata(codec->dev->parent);
2619
2620 ret = tabla_handle_pdata(tabla);
2621
2622 if (IS_ERR_VALUE(ret)) {
2623 pr_err("%s: bad pdata\n", __func__);
2624 goto err_pdata;
2625 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626
Kiran Kandi1f6fd722011-08-11 10:36:11 -07002627 tabla_update_reg_defaults(codec);
2628 tabla_codec_init_reg(codec);
2629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 /* TODO only enable bandgap when necessary in order to save power */
2631 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
2632 tabla_codec_enable_clock_block(codec, 0);
2633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002634 snd_soc_add_controls(codec, tabla_snd_controls,
2635 ARRAY_SIZE(tabla_snd_controls));
2636 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
2637 ARRAY_SIZE(tabla_dapm_widgets));
2638 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
2639 snd_soc_dapm_sync(dapm);
2640
2641 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
2642 tabla_hs_insert_irq, "Headset insert detect", tabla);
2643 if (ret) {
2644 pr_err("%s: Failed to request irq %d\n", __func__,
2645 TABLA_IRQ_MBHC_INSERTION);
2646 goto err_insert_irq;
2647 }
2648 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
2649
2650 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
2651 tabla_hs_remove_irq, "Headset remove detect", tabla);
2652 if (ret) {
2653 pr_err("%s: Failed to request irq %d\n", __func__,
2654 TABLA_IRQ_MBHC_REMOVAL);
2655 goto err_remove_irq;
2656 }
2657 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
2658
2659 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07002660 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002661 if (ret) {
2662 pr_err("%s: Failed to request irq %d\n", __func__,
2663 TABLA_IRQ_MBHC_POTENTIAL);
2664 goto err_potential_irq;
2665 }
2666 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
2667
Bradley Rubincb1e2732011-06-23 16:49:20 -07002668 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
2669 tabla_release_handler, "Button Release detect", tabla);
2670 if (ret) {
2671 pr_err("%s: Failed to request irq %d\n", __func__,
2672 TABLA_IRQ_MBHC_RELEASE);
2673 goto err_release_irq;
2674 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002675 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
2678 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
2679 if (ret) {
2680 pr_err("%s: Failed to request irq %d\n", __func__,
2681 TABLA_IRQ_SLIMBUS);
2682 goto err_slimbus_irq;
2683 }
2684
2685 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
2686 tabla_interface_reg_write(codec->control_data,
2687 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
2688
2689 return ret;
2690
2691err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07002692 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
2693err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2695err_potential_irq:
2696 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2697err_remove_irq:
2698 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2699err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07002700err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 kfree(tabla);
2702 return ret;
2703}
2704static int tabla_codec_remove(struct snd_soc_codec *codec)
2705{
2706 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2707 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002708 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
2710 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
2711 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
2712 tabla_codec_disable_clock_block(codec);
2713 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
2714 kfree(tabla);
2715 return 0;
2716}
2717static struct snd_soc_codec_driver soc_codec_dev_tabla = {
2718 .probe = tabla_codec_probe,
2719 .remove = tabla_codec_remove,
2720 .read = tabla_read,
2721 .write = tabla_write,
2722
2723 .readable_register = tabla_readable,
2724 .volatile_register = tabla_volatile,
2725
2726 .reg_cache_size = TABLA_CACHE_SIZE,
2727 .reg_cache_default = tabla_reg_defaults,
2728 .reg_word_size = 1,
2729};
2730static int __devinit tabla_probe(struct platform_device *pdev)
2731{
2732 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
2733 tabla_dai, ARRAY_SIZE(tabla_dai));
2734}
2735static int __devexit tabla_remove(struct platform_device *pdev)
2736{
2737 snd_soc_unregister_codec(&pdev->dev);
2738 return 0;
2739}
2740static struct platform_driver tabla_codec_driver = {
2741 .probe = tabla_probe,
2742 .remove = tabla_remove,
2743 .driver = {
2744 .name = "tabla_codec",
2745 .owner = THIS_MODULE,
2746 },
2747};
2748
2749static int __init tabla_codec_init(void)
2750{
2751 return platform_driver_register(&tabla_codec_driver);
2752}
2753
2754static void __exit tabla_codec_exit(void)
2755{
2756 platform_driver_unregister(&tabla_codec_driver);
2757}
2758
2759module_init(tabla_codec_init);
2760module_exit(tabla_codec_exit);
2761
2762MODULE_DESCRIPTION("Tabla codec driver");
2763MODULE_VERSION("1.0");
2764MODULE_LICENSE("GPL v2");