blob: 20cf7979c614cd564ef4308a40f2c3123cdf863c [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>
14#include <linux/slab.h>
15#include <linux/platform_device.h>
16#include <linux/printk.h>
17#include <linux/ratelimit.h>
18#include <linux/mfd/wcd9310/core.h>
19#include <linux/mfd/wcd9310/registers.h>
20#include <sound/jack.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <sound/tlv.h>
24#include <linux/bitops.h>
25#include <linux/delay.h>
26#include "wcd9310.h"
27
28static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
29static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
30static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
31
32enum tabla_bandgap_type {
33 TABLA_BANDGAP_OFF = 0,
34 TABLA_BANDGAP_AUDIO_MODE,
35 TABLA_BANDGAP_MBHC_MODE,
36};
37
38struct tabla_priv { /* member undecided */
39 struct snd_soc_codec *codec;
40 u32 ref_cnt;
41 u32 adc_count;
42 u32 dec_count;
43 enum tabla_bandgap_type bandgap_type;
44 bool clock_active;
45 bool config_mode_active;
46 bool mbhc_polling_active;
Bradley Rubincb1e2732011-06-23 16:49:20 -070047 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
49 struct tabla_mbhc_calibration *calibration;
50
Bradley Rubincb1e2732011-06-23 16:49:20 -070051 struct snd_soc_jack *headset_jack;
52 struct snd_soc_jack *button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053};
54
55static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
56 struct snd_kcontrol *kcontrol, int event)
57{
58 struct snd_soc_codec *codec = w->codec;
59 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
60
61 pr_debug("%s %d\n", __func__, event);
62 switch (event) {
63 case SND_SOC_DAPM_POST_PMU:
64 if ((tabla->bandgap_type != TABLA_BANDGAP_AUDIO_MODE) ||
65 (!tabla->clock_active)) {
66 pr_err("%s: Error, Tabla must have clocks enabled for "
67 "charge pump\n", __func__);
68 return -EINVAL;
69 }
70
71 snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x01);
72 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
73 0x01);
74 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
75 usleep_range(200, 200);
76 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
77 break;
78 case SND_SOC_DAPM_PRE_PMD:
79 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
80 0x10);
81 usleep_range(20, 20);
82 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
83 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
84 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
85 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
86 0x00);
87 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
88 snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x00);
89 break;
90 }
91 return 0;
92}
93
94static const struct snd_kcontrol_new tabla_snd_controls[] = {
95 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
96 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -070097 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
98 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070099 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
100 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700101 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
102 line_gain),
103
104 SOC_SINGLE("RX1 CHAIN INVERT Switch", TABLA_A_CDC_RX1_B6_CTL, 4, 1, 0),
105 SOC_SINGLE("RX2 CHAIN INVERT Switch", TABLA_A_CDC_RX2_B6_CTL, 4, 1, 0),
106 SOC_SINGLE("RX3 CHAIN INVERT Switch", TABLA_A_CDC_RX3_B6_CTL, 4, 1, 0),
107 SOC_SINGLE("RX4 CHAIN INVERT Switch", TABLA_A_CDC_RX4_B6_CTL, 4, 1, 0),
108 SOC_SINGLE("RX5 CHAIN INVERT Switch", TABLA_A_CDC_RX5_B6_CTL, 4, 1, 0),
109 SOC_SINGLE("RX6 CHAIN INVERT Switch", TABLA_A_CDC_RX6_B6_CTL, 4, 1, 0),
110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
112 line_gain),
113 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
114 line_gain),
115
116 SOC_SINGLE_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL, 0,
117 100, 0, digital_gain),
118 SOC_SINGLE_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL, 0,
119 100, 0, digital_gain),
120
121 SOC_SINGLE_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, 100, 0,
122 digital_gain),
123 SOC_SINGLE_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, 100, 0,
124 digital_gain),
125
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700126 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
127 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
128 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
129 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130
131 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
132};
133
134static const char *rx_mix1_text[] = {
135 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
136 "RX5", "RX6", "RX7"
137};
138
139static const char *sb_tx1_mux_text[] = {
140 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
141 "DEC1"
142};
143
144static const char *sb_tx5_mux_text[] = {
145 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
146 "DEC5"
147};
148
149static const char *sb_tx6_mux_text[] = {
150 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
151 "DEC6"
152};
153
154static const char const *sb_tx7_to_tx10_mux_text[] = {
155 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
156 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
157 "DEC9", "DEC10"
158};
159
160static const char *dec1_mux_text[] = {
161 "ZERO", "DMIC1", "ADC6",
162};
163
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700164static const char *dec2_mux_text[] = {
165 "ZERO", "DMIC2", "ADC5",
166};
167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168static const char *dec5_mux_text[] = {
169 "ZERO", "DMIC5", "ADC2",
170};
171
172static const char *dec6_mux_text[] = {
173 "ZERO", "DMIC6", "ADC1",
174};
175
176static const char const *dec7_mux_text[] = {
177 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
178};
179
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700180static const char *dec8_mux_text[] = {
181 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
182};
183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184static const char *iir1_inp1_text[] = {
185 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
186 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
187};
188
189static const struct soc_enum rx_mix1_inp1_chain_enum =
190 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
191
192static const struct soc_enum rx2_mix1_inp1_chain_enum =
193 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
194
195static const struct soc_enum rx3_mix1_inp1_chain_enum =
196 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
197
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700198static const struct soc_enum rx3_mix1_inp2_chain_enum =
199 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201static const struct soc_enum rx4_mix1_inp1_chain_enum =
202 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
203
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700204static const struct soc_enum rx4_mix1_inp2_chain_enum =
205 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207static const struct soc_enum rx5_mix1_inp1_chain_enum =
208 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
209
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700210static const struct soc_enum rx5_mix1_inp2_chain_enum =
211 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
212
213static const struct soc_enum rx6_mix1_inp1_chain_enum =
214 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
215
216static const struct soc_enum rx6_mix1_inp2_chain_enum =
217 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219static const struct soc_enum sb_tx5_mux_enum =
220 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
221
222static const struct soc_enum sb_tx6_mux_enum =
223 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
224
225static const struct soc_enum sb_tx7_mux_enum =
226 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
227 sb_tx7_to_tx10_mux_text);
228
229static const struct soc_enum sb_tx8_mux_enum =
230 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
231 sb_tx7_to_tx10_mux_text);
232
233static const struct soc_enum sb_tx1_mux_enum =
234 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
235
236static const struct soc_enum dec1_mux_enum =
237 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
238
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700239static const struct soc_enum dec2_mux_enum =
240 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242static const struct soc_enum dec5_mux_enum =
243 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
244
245static const struct soc_enum dec6_mux_enum =
246 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
247
248static const struct soc_enum dec7_mux_enum =
249 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
250
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700251static const struct soc_enum dec8_mux_enum =
252 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254static const struct soc_enum iir1_inp1_mux_enum =
255 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
256
257static const struct snd_kcontrol_new rx_mix1_inp1_mux =
258 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
259
260static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
261 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
262
263static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
264 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
265
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700266static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
267 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
270 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
271
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700272static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
273 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
276 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
277
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700278static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
279 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
280
281static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
282 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
283
284static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
285 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287static const struct snd_kcontrol_new sb_tx5_mux =
288 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
289
290static const struct snd_kcontrol_new sb_tx6_mux =
291 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
292
293static const struct snd_kcontrol_new sb_tx7_mux =
294 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
295
296static const struct snd_kcontrol_new sb_tx8_mux =
297 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
298
299static const struct snd_kcontrol_new sb_tx1_mux =
300 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
301
302static const struct snd_kcontrol_new dec1_mux =
303 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
304
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700305static const struct snd_kcontrol_new dec2_mux =
306 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308static const struct snd_kcontrol_new dec5_mux =
309 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
310
311static const struct snd_kcontrol_new dec6_mux =
312 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
313
314static const struct snd_kcontrol_new dec7_mux =
315 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
316
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700317static const struct snd_kcontrol_new dec8_mux =
318 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320static const struct snd_kcontrol_new iir1_inp1_mux =
321 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
322
323static const struct snd_kcontrol_new dac1_control =
324 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0);
325
326static const struct snd_kcontrol_new hphl_switch =
327 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0);
328
329static const struct snd_kcontrol_new hphr_switch =
330 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0);
331
332static const struct snd_kcontrol_new lineout1_switch =
333 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0);
334
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700335static const struct snd_kcontrol_new lineout2_switch =
336 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0);
337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338static const struct snd_kcontrol_new lineout3_switch =
339 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
340
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700341static const struct snd_kcontrol_new lineout4_switch =
342 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
343
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
346 int enable)
347{
348 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
349
350 pr_debug("%s %d\n", __func__, enable);
351
352 if (enable) {
353 tabla->adc_count++;
354 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
355 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
356 } else {
357 tabla->adc_count--;
358 if (!tabla->adc_count) {
359 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
360 0x2, 0x0);
361 if (!tabla->mbhc_polling_active)
362 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
363 0xE0, 0x0);
364 }
365 }
366}
367
368static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
369 struct snd_kcontrol *kcontrol, int event)
370{
371 struct snd_soc_codec *codec = w->codec;
372 u16 adc_reg;
373
374 pr_debug("%s %d\n", __func__, event);
375
376 if (w->reg == TABLA_A_TX_1_2_EN)
377 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
378 else if (w->reg == TABLA_A_TX_3_4_EN)
379 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
380 else if (w->reg == TABLA_A_TX_5_6_EN)
381 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
382 else {
383 pr_err("%s: Error, invalid adc register\n", __func__);
384 return -EINVAL;
385 }
386
387 switch (event) {
388 case SND_SOC_DAPM_PRE_PMU:
389 tabla_codec_enable_adc_block(codec, 1);
390 break;
391 case SND_SOC_DAPM_POST_PMU:
392 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
393 1 << w->shift);
394 usleep_range(1000, 1000);
395 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
396 usleep_range(1000, 1000);
397 break;
398 case SND_SOC_DAPM_POST_PMD:
399 tabla_codec_enable_adc_block(codec, 0);
400 break;
401 }
402 return 0;
403}
404
405static int tabla_codec_enable_pamp_gain(struct snd_soc_dapm_widget *w,
406 struct snd_kcontrol *kcontrol, int event)
407{
408 struct snd_soc_codec *codec = w->codec;
409
410 pr_debug("%s %d\n", __func__, event);
411 switch (event) {
412 case SND_SOC_DAPM_PRE_PMU:
413 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x80);
414 break;
415 case SND_SOC_DAPM_POST_PMD:
416 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0x80, 0x00);
417 break;
418 }
419 return 0;
420}
421
422static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
423 struct snd_kcontrol *kcontrol, int event)
424{
425 struct snd_soc_codec *codec = w->codec;
426 u16 lineout_gain_reg;
427
428 pr_debug("%s %d\n", __func__, event);
429
430 switch (w->shift) {
431 case 0:
432 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
433 break;
434 case 1:
435 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
436 break;
437 case 2:
438 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
439 break;
440 case 3:
441 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
442 break;
443 case 4:
444 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
445 break;
446 default:
447 pr_err("%s: Error, incorrect lineout register value\n",
448 __func__);
449 return -EINVAL;
450 }
451
452 switch (event) {
453 case SND_SOC_DAPM_PRE_PMU:
454 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
455 break;
456 case SND_SOC_DAPM_POST_PMU:
457 usleep_range(40000, 40000);
458 break;
459 case SND_SOC_DAPM_POST_PMD:
460 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
461 break;
462 }
463 return 0;
464}
465
466static int tabla_codec_enable_dmic1(struct snd_soc_dapm_widget *w,
467 struct snd_kcontrol *kcontrol, int event)
468{
469 struct snd_soc_codec *codec = w->codec;
470
471 pr_debug("%s %d\n", __func__, event);
472 switch (event) {
473 case SND_SOC_DAPM_PRE_PMU:
474 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_MUX_CTL, 0x1, 0x1);
475 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x2, 0x2);
476 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1);
477 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x1, 0x1);
478 break;
479 case SND_SOC_DAPM_POST_PMD:
480 snd_soc_update_bits(codec, TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0);
481 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL, 0x3, 0);
482 break;
483 }
484 return 0;
485}
486
487static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
488 struct snd_kcontrol *kcontrol, int event)
489{
490 struct snd_soc_codec *codec = w->codec;
491 u16 micb_cfilt_reg, micb_int_reg;
492 char *internal_text = "Internal";
493
494 pr_debug("%s %d\n", __func__, event);
495 switch (w->reg) {
496 case TABLA_A_MICB_1_CTL:
497 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
498 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
499 break;
500 case TABLA_A_MICB_2_CTL:
501 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
502 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
503 break;
504 case TABLA_A_MICB_3_CTL:
505 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
506 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
507 break;
508 default:
509 pr_err("%s: Error, invalid micbias register\n", __func__);
510 return -EINVAL;
511 }
512
513 switch (event) {
514 case SND_SOC_DAPM_PRE_PMU:
515 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
516 if (strnstr(w->name, internal_text, 20))
517 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
518 break;
519 case SND_SOC_DAPM_POST_PMD:
520 if (strnstr(w->name, internal_text, 20))
521 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
522 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
523 break;
524 }
525
526 return 0;
527}
528
529static void tabla_codec_enable_dec_clock(struct snd_soc_codec *codec,
530 int enable)
531{
532 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
533
534 if (enable) {
535 tabla->dec_count++;
536 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x4, 0x4);
537 } else {
538 tabla->dec_count--;
539 if (!tabla->dec_count)
540 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
541 0x4, 0x0);
542 }
543}
544
545static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
546 struct snd_kcontrol *kcontrol, int event)
547{
548 struct snd_soc_codec *codec = w->codec;
549 u16 dec_reset_reg;
550
551 pr_debug("%s %d\n", __func__, event);
552
553 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
554 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
555 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
556 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
557 else {
558 pr_err("%s: Error, incorrect dec\n", __func__);
559 return -EINVAL;
560 }
561
562 switch (event) {
563 case SND_SOC_DAPM_PRE_PMU:
564 tabla_codec_enable_dec_clock(codec, 1);
565 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
566 1 << w->shift);
567 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
568 break;
569 case SND_SOC_DAPM_POST_PMD:
570 tabla_codec_enable_dec_clock(codec, 0);
571 break;
572 }
573 return 0;
574}
575
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700576static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 struct snd_kcontrol *kcontrol, int event)
578{
579 struct snd_soc_codec *codec = w->codec;
580
581 switch (event) {
582 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700583 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
584 1 << w->shift, 1 << w->shift);
585 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
586 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 break;
588 }
589 return 0;
590}
591
592static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
593 /*RX stuff */
594 SND_SOC_DAPM_OUTPUT("EAR"),
595
596 SND_SOC_DAPM_PGA_E("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0,
597 tabla_codec_enable_pamp_gain, SND_SOC_DAPM_POST_PMU |
598 SND_SOC_DAPM_PRE_PMD),
599
600 SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
601
602 SND_SOC_DAPM_SWITCH("DAC1", TABLA_A_RX_EAR_EN, 6, 0, &dac1_control),
603 SND_SOC_DAPM_PGA_E("RX1 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
604 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
605 SND_SOC_DAPM_PRE_PMD),
606 SND_SOC_DAPM_PGA("RX BIAS", TABLA_A_RX_COM_BIAS, 7, 0, NULL, 0),
607 SND_SOC_DAPM_MUX_E("RX1 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0,
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700608 &rx_mix1_inp1_mux, tabla_codec_reset_interpolator,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 SND_SOC_DAPM_PRE_PMU),
610 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0,
611 TABLA_A_CDC_RX1_B6_CTL, 5, 0),
612
613 /* RX 2 path */
614 SND_SOC_DAPM_PGA_E("RX2 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
615 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
616 SND_SOC_DAPM_PRE_PMD),
617 SND_SOC_DAPM_MUX_E("RX2 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0,
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700618 &rx2_mix1_inp1_mux, tabla_codec_reset_interpolator,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 SND_SOC_DAPM_PRE_PMU),
620 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0,
621 TABLA_A_CDC_RX2_B6_CTL, 5, 0),
622
623 /* Headphone */
624 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
625 SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
626 SND_SOC_DAPM_SWITCH("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
627 &hphl_switch),
628
629 SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
630 SND_SOC_DAPM_SWITCH("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
631 &hphr_switch),
632
633 /* Speaker */
634 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
637 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
638 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700639 SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
640 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
641 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
643 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
644 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700645 SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
646 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
647 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
648
649 SND_SOC_DAPM_SWITCH("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
650 &lineout1_switch),
651 SND_SOC_DAPM_SWITCH("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
652 &lineout2_switch),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
654 &lineout3_switch),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700655 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
656 &lineout4_switch),
657
658 SND_SOC_DAPM_PGA_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL, 0,
659 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
660 SND_SOC_DAPM_PGA_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL, 0,
661 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
662 SND_SOC_DAPM_PGA_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL, 0,
663 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
664 SND_SOC_DAPM_PGA_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL, 0,
665 tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
666
667 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
668 &rx3_mix1_inp1_mux),
669 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
670 &rx3_mix1_inp2_mux),
671 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
672 &rx4_mix1_inp1_mux),
673 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
674 &rx4_mix1_inp2_mux),
675 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
676 &rx5_mix1_inp1_mux),
677 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
678 &rx5_mix1_inp2_mux),
679 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
680 &rx6_mix1_inp1_mux),
681 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
682 &rx6_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683
684 /* TX */
685 SND_SOC_DAPM_INPUT("AMIC1"),
686 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
687 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
688 SND_SOC_DAPM_POST_PMD),
689 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal", TABLA_A_MICB_1_CTL, 7, 0,
690 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
691 SND_SOC_DAPM_POST_PMD),
692 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
693 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
694 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
695
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700696 SND_SOC_DAPM_INPUT("AMIC5"),
697 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
698 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
699
700 SND_SOC_DAPM_INPUT("AMIC6"),
701 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
702 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
705 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
706 SND_SOC_DAPM_POST_PMD),
707
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700708 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
709 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
710 SND_SOC_DAPM_POST_PMD),
711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
713 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
714 SND_SOC_DAPM_POST_PMD),
715
716 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
717 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
718 SND_SOC_DAPM_POST_PMD),
719
720 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
721 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
722 SND_SOC_DAPM_POST_PMD),
723
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700724 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
725 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
726 SND_SOC_DAPM_POST_PMD),
727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 SND_SOC_DAPM_INPUT("AMIC2"),
729 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
730 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
731 SND_SOC_DAPM_POST_PMD),
732 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal", TABLA_A_MICB_2_CTL, 7, 0,
733 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
734 SND_SOC_DAPM_POST_PMD),
735 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
736 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
737 SND_SOC_DAPM_POST_PMD),
738 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal", TABLA_A_MICB_3_CTL, 7, 0,
739 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
740 SND_SOC_DAPM_POST_PMD),
741 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
742 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
743 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
744
745 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
746 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
747 0, 0),
748
749 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
750 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
751 4, 0),
752
753 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
754 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
755 5, 0),
756
757 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
758 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
759 0, 0),
760
761 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
762 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
763 0, 0),
764
765 /* Digital Mic */
766 SND_SOC_DAPM_INPUT("DMIC1 IN"),
767 SND_SOC_DAPM_MIC("DMIC1", &tabla_codec_enable_dmic1),
768
769 /* Sidetone */
770 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
771 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
772};
773
774static const struct snd_soc_dapm_route audio_map[] = {
775 /* SLIMBUS Connections */
776 {"RX BIAS", NULL, "SLIM RX1"},
777 {"RX BIAS", NULL, "SLIM RX2"},
778
779 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
780 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
781
782 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
783 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
784
785 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
786 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
787
788 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
789 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700790 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
792 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700793 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
794 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795
796 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
797 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
798 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
799
800 /* Earpiece (RX MIX1) */
801 {"EAR", NULL, "EAR PA"},
802 {"EAR PA", NULL, "EAR PA Input"},
803 {"EAR PA Input", NULL, "DAC1"},
804 {"DAC1", "Switch", "RX1 CP"},
805 {"RX1 CP", NULL, "RX1 MIX1 INP1"},
806 {"RX1 MIX1 INP1", "RX1", "RX BIAS"},
807
808 /* Headset (RX MIX1 and RX MIX2) */
809 {"HEADPHONE", NULL, "HPHL"},
810 {"HPHL", NULL, "HPHL DAC"},
811 {"HPHL DAC", "Switch", "RX1 MIX1 INP1"},
812
813 {"HEADPHONE", NULL, "HPHR"},
814 {"HPHR", NULL, "HPHR DAC"},
815 {"HPHR DAC", "Switch", "RX2 CP"},
816 {"RX2 CP", NULL, "RX2 MIX1 INP1"},
817 {"RX2 MIX1 INP1", "RX2", "RX BIAS"},
818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819 {"LINEOUT", NULL, "LINEOUT1"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700820 {"LINEOUT", NULL, "LINEOUT2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 {"LINEOUT", NULL, "LINEOUT3"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700822 {"LINEOUT", NULL, "LINEOUT4"},
823
824 {"LINEOUT1", NULL, "LINEOUT1 DAC"},
825 {"LINEOUT2", NULL, "LINEOUT2 DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 {"LINEOUT3", NULL, "LINEOUT3 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700827 {"LINEOUT4", NULL, "LINEOUT4 DAC"},
828
829 {"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
830 {"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
831 {"LINEOUT3 DAC", "Switch", "RX5 MIX1"},
832 {"LINEOUT4 DAC", "Switch", "RX6 MIX1"},
833
834 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
835 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
836 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
837 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
838 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
839 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
840 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
841 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
842
843 {"RX3 MIX1 INP1", "RX1", "RX BIAS"},
844 {"RX3 MIX1 INP1", "RX2", "RX BIAS"},
845 {"RX3 MIX1 INP2", "RX1", "RX BIAS"},
846 {"RX3 MIX1 INP2", "RX2", "RX BIAS"},
847 {"RX4 MIX1 INP1", "RX1", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 {"RX4 MIX1 INP1", "RX2", "RX BIAS"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700849 {"RX4 MIX1 INP2", "RX1", "RX BIAS"},
850 {"RX4 MIX1 INP2", "RX2", "RX BIAS"},
851 {"RX5 MIX1 INP1", "RX1", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852 {"RX5 MIX1 INP1", "RX2", "RX BIAS"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700853 {"RX5 MIX1 INP2", "RX1", "RX BIAS"},
854 {"RX5 MIX1 INP2", "RX2", "RX BIAS"},
855 {"RX6 MIX1 INP1", "RX1", "RX BIAS"},
856 {"RX6 MIX1 INP1", "RX2", "RX BIAS"},
857 {"RX6 MIX1 INP2", "RX1", "RX BIAS"},
858 {"RX6 MIX1 INP2", "RX2", "RX BIAS"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859
860 /* Handset TX */
861 {"DEC5 MUX", "ADC2", "ADC2"},
862 {"DEC6 MUX", "ADC1", "ADC1"},
863 {"ADC1", NULL, "AMIC1"},
864 {"ADC2", NULL, "AMIC2"},
865
866 /* Digital Mic */
867 {"DEC1 MUX", "DMIC1", "DMIC1"},
868 {"DEC7 MUX", "DMIC1", "DMIC1"},
869 {"DMIC1", NULL, "DMIC1 IN"},
870
871 /* Sidetone (IIR1) */
872 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
873 {"IIR1", NULL, "IIR1 INP1 MUX"},
874 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
875
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700876 /* Analog Inputs */
877 {"DEC8 MUX", "ADC5", "ADC5"},
878 {"DEC2 MUX", "ADC5", "ADC5"},
879 {"ADC5", NULL, "AMIC5"},
880 {"DEC7 MUX", "ADC6", "ADC6"},
881 {"DEC1 MUX", "ADC6", "ADC6"},
882 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883};
884
885static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
886{
887 return tabla_reg_readable[reg];
888}
889
890static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
891{
892 /* Registers lower than 0x100 are top level registers which can be
893 * written by the Tabla core driver.
894 */
895
896 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
897 return 1;
898
899 return 0;
900}
901
902#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
903static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
904 unsigned int value)
905{
906 int ret;
907 pr_debug("%s: write reg %x val %x\n", __func__, reg, value);
908
909 BUG_ON(reg > TABLA_MAX_REGISTER);
910
911 if (!tabla_volatile(codec, reg)) {
912 pr_debug("writing to cache\n");
913 ret = snd_soc_cache_write(codec, reg, value);
914 if (ret != 0)
915 dev_err(codec->dev, "Cache write to %x failed: %d\n",
916 reg, ret);
917 }
918
919 return tabla_reg_write(codec->control_data, reg, value);
920}
921static unsigned int tabla_read(struct snd_soc_codec *codec,
922 unsigned int reg)
923{
924 unsigned int val;
925 int ret;
926
927 BUG_ON(reg > TABLA_MAX_REGISTER);
928
929 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
930 reg < codec->driver->reg_cache_size) {
931 pr_debug("reading from cache\n");
932 ret = snd_soc_cache_read(codec, reg, &val);
933 if (ret >= 0) {
934 pr_debug("register %d, value %d\n", reg, val);
935 return val;
936 } else
937 dev_err(codec->dev, "Cache read from %x failed: %d\n",
938 reg, ret);
939 }
940
941 val = tabla_reg_read(codec->control_data, reg);
942 pr_debug("%s: read reg %x val %x\n", __func__, reg, val);
943 return val;
944}
945
946static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
947{
948 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
949 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
950 0x80);
951 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
952 0x04);
953 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
954 0x01);
955 usleep_range(1000, 1000);
956 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
957 0x00);
958}
959
960static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
961 enum tabla_bandgap_type choice)
962{
963 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
964
965 /* TODO lock resources accessed by audio streams and threaded
966 * interrupt handlers
967 */
968
969 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
970 tabla->bandgap_type);
971
972 if (tabla->bandgap_type == choice)
973 return;
974
975 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
976 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
977 tabla_codec_enable_audio_mode_bandgap(codec);
978 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
979 (choice == TABLA_BANDGAP_MBHC_MODE)) {
980 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
981 0x2);
982 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
983 0x80);
984 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
985 0x4);
986 usleep_range(1000, 1000);
987 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
988 0x00);
989 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
990 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
991 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
992 usleep_range(100, 100);
993 tabla_codec_enable_audio_mode_bandgap(codec);
994 } else if (choice == TABLA_BANDGAP_OFF) {
995 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
996 } else {
997 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
998 }
999 tabla->bandgap_type = choice;
1000}
1001
1002static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1003 int enable)
1004{
1005 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1006
1007 if (enable) {
1008 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1009 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1010 usleep_range(5, 5);
1011 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1012 0x80);
1013 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1014 0x80);
1015 usleep_range(10, 10);
1016 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1017 usleep_range(20, 20);
1018 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1019 } else {
1020 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1021 0);
1022 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1023 }
1024 tabla->config_mode_active = enable ? true : false;
1025
1026 return 0;
1027}
1028
1029static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1030 int config_mode)
1031{
1032 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1033
1034 pr_debug("%s\n", __func__);
1035
1036 if (config_mode) {
1037 tabla_codec_enable_config_mode(codec, 1);
1038 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1039 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1040 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1041 usleep_range(1000, 1000);
1042 } else
1043 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1044
1045 if (!config_mode && tabla->mbhc_polling_active) {
1046 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1047 tabla_codec_enable_config_mode(codec, 0);
1048
1049 }
1050
1051 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1052 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1053 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1054 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1055 usleep_range(50, 50);
1056 tabla->clock_active = true;
1057 return 0;
1058}
1059static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1060{
1061 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1062 pr_debug("%s\n", __func__);
1063 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1064 ndelay(160);
1065 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1066 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1067 tabla->clock_active = false;
1068}
1069
Bradley Rubincb1e2732011-06-23 16:49:20 -07001070static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1071{
1072 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
1073 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1074 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1075 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1076 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1077 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1078}
1079
1080static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
1081{
1082 /* TODO store register values in calibration */
1083
1084 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
1085 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x00);
1086
1087 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x08);
1088 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
1089 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
1090 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
1091
1092 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
1093 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
1094 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
1095 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
1096 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
1097 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
1098}
1099
1100static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1101{
1102 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1103 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1104 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1105}
1106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107static int tabla_startup(struct snd_pcm_substream *substream,
1108 struct snd_soc_dai *dai)
1109{
1110 struct snd_soc_codec *codec = dai->codec;
1111 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1112 int ret = 0;
1113
1114 pr_debug("%s()\n", __func__);
1115
1116 if (!codec) {
1117 pr_err("Error, no codec found\n");
1118 return -EINVAL;
1119 }
1120 tabla->ref_cnt++;
1121
1122 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1123 /* Enable LDO */
1124 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
1125 0xA0);
1126 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
1127 usleep_range(1000, 1000);
1128 }
1129
1130 if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001131 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1133 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001134 tabla_codec_calibrate_hs_polling(codec);
1135 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 }
1137
1138 return ret;
1139}
1140
1141static void tabla_shutdown(struct snd_pcm_substream *substream,
1142 struct snd_soc_dai *dai)
1143{
1144 struct snd_soc_codec *codec = dai->codec;
1145 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1146
1147 pr_debug("%s()\n", __func__);
1148
1149 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1150 /* Disable LDO */
1151 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x00);
1152 usleep_range(1000, 1000);
1153 }
1154
1155 if (!tabla->ref_cnt) {
1156 pr_err("Error, trying to shutdown codec when already down\n");
1157 return;
1158 }
1159 tabla->ref_cnt--;
1160
1161 if (tabla->mbhc_polling_active) {
1162 if (!tabla->ref_cnt) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07001163 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 tabla_codec_enable_bandgap(codec,
1165 TABLA_BANDGAP_MBHC_MODE);
1166 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
1167 0x80);
1168 tabla_codec_enable_clock_block(codec, 1);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001169 tabla_codec_calibrate_hs_polling(codec);
1170 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 }
1172 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1173 }
1174}
1175
1176static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1177{
1178 struct snd_soc_codec *codec = codec_dai->codec;
1179
1180 pr_debug("%s %d\n", __func__, mute);
1181
1182 /* TODO mute TX */
1183 if (mute)
1184 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x01);
1185 else
1186 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_B6_CTL, 0x01, 0x00);
1187
1188 return 0;
1189}
1190
1191static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
1192 int clk_id, unsigned int freq, int dir)
1193{
1194 pr_debug("%s\n", __func__);
1195 return 0;
1196}
1197
1198static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1199{
1200 pr_debug("%s\n", __func__);
1201 return 0;
1202}
1203
1204static int tabla_hw_params(struct snd_pcm_substream *substream,
1205 struct snd_pcm_hw_params *params,
1206 struct snd_soc_dai *dai)
1207{
1208 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
1209 return 0;
1210}
1211
1212static struct snd_soc_dai_ops tabla_dai_ops = {
1213 .startup = tabla_startup,
1214 .shutdown = tabla_shutdown,
1215 .hw_params = tabla_hw_params,
1216 .set_sysclk = tabla_set_dai_sysclk,
1217 .set_fmt = tabla_set_dai_fmt,
1218 .digital_mute = tabla_digital_mute,
1219};
1220
1221static struct snd_soc_dai_driver tabla_dai[] = {
1222 {
1223 .name = "tabla_rx1",
1224 .id = 1,
1225 .playback = {
1226 .stream_name = "AIF1 Playback",
1227 .rates = SNDRV_PCM_RATE_8000_48000,
1228 .formats = TABLA_FORMATS,
1229 .rate_max = 48000,
1230 .rate_min = 8000,
1231 .channels_min = 1,
1232 .channels_max = 2,
1233 },
1234 .ops = &tabla_dai_ops,
1235 },
1236 {
1237 .name = "tabla_tx1",
1238 .id = 2,
1239 .capture = {
1240 .stream_name = "AIF1 Capture",
1241 .rates = SNDRV_PCM_RATE_8000_48000,
1242 .formats = TABLA_FORMATS,
1243 .rate_max = 48000,
1244 .rate_min = 8000,
1245 .channels_min = 1,
1246 .channels_max = 2,
1247 },
1248 .ops = &tabla_dai_ops,
1249 },
1250};
1251
Bradley Rubincb1e2732011-06-23 16:49:20 -07001252static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
1253 int dce)
1254{
1255 u8 bias_msb, bias_lsb;
1256 short bias_value;
1257
1258 if (dce) {
1259 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
1260 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
1261 } else {
1262 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1263 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1264 msleep(100);
1265 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
1266 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
1267 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
1268 }
1269
1270 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1271 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
1272
1273 bias_value = (bias_msb << 8) | bias_lsb;
1274 pr_debug("read microphone bias value %x\n", bias_value);
1275 return bias_value;
1276}
1277
1278static int tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279{
1280 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1281 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001282 int micbias_ctl_reg, micbias_cfilt_val_reg, micbias_cfilt_ctl_reg,
1283 micbias_mbhc_reg;
1284 short bias_value, threshold_no_mic;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285
1286 if (!calibration) {
1287 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001288 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 }
1290
1291 tabla->mbhc_polling_active = true;
1292
1293 if (!tabla->ref_cnt) {
1294 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
1295 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
1296 tabla_codec_enable_clock_block(codec, 1);
1297 }
1298
1299 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
1300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0F, 0x0D);
1302 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1303
1304 /* TODO select cfilt separately from the micbias line inside the machine
1305 * driver
1306 */
1307 switch (calibration->bias) {
1308 case TABLA_MICBIAS1:
1309 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1310 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_1_CTL;
1311 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_1_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001312 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 break;
1314 case TABLA_MICBIAS2:
1315 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1316 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_2_CTL;
1317 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_2_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001318 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 break;
1320 case TABLA_MICBIAS3:
1321 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1322 micbias_cfilt_ctl_reg = TABLA_A_MICB_CFILT_3_CTL;
1323 micbias_cfilt_val_reg = TABLA_A_MICB_CFILT_3_VAL;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001324 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 break;
1326 case TABLA_MICBIAS4:
1327 pr_err("%s: Error, microphone bias 4 not supported\n",
1328 __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001329 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 default:
1331 pr_err("Error, invalid mic bias line\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07001332 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 }
1334 snd_soc_write(codec, micbias_cfilt_ctl_reg, 0x40);
1335
Bradley Rubincb1e2732011-06-23 16:49:20 -07001336 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1F, 0x16);
1337 snd_soc_update_bits(codec, micbias_ctl_reg, 0x60,
1338 calibration->bias << 5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339
1340 snd_soc_write(codec, micbias_cfilt_val_reg, 0x68);
1341
1342 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001343 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344
1345 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
1346 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1347 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1348
1349 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001350 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1351 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352
Bradley Rubincb1e2732011-06-23 16:49:20 -07001353 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1355
Bradley Rubincb1e2732011-06-23 16:49:20 -07001356 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1357 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x01);
1358
1359 tabla_codec_calibrate_hs_polling(codec);
1360
1361 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
1362
1363 threshold_no_mic = 0xF7F6;
1364
1365 if (bias_value < threshold_no_mic) {
1366 pr_debug("headphone detected, micbias %x\n", bias_value);
1367 return 0;
1368 } else {
1369 pr_debug("headset detected, micbias %x\n", bias_value);
1370 return 1;
1371 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372}
1373
1374static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
1375 int insertion)
1376{
1377 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1378 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1379 int central_bias_enabled = 0;
1380 int micbias_int_reg, micbias_ctl_reg, micbias_mbhc_reg;
1381
1382 if (!calibration) {
1383 pr_err("Error, no tabla calibration\n");
1384 return -EINVAL;
1385 }
1386
1387 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
1388
1389 if (insertion)
1390 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
1391 else
1392 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
1393
1394 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
1395 if (!(tabla->clock_active)) {
1396 tabla_codec_enable_config_mode(codec, 1);
1397 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001398 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 usleep_range(calibration->shutdown_plug_removal,
1400 calibration->shutdown_plug_removal);
1401 tabla_codec_enable_config_mode(codec, 0);
1402 } else
1403 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001404 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 }
1406
1407 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0xC,
1408 calibration->hph_current << 2);
1409
1410 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x13);
1411
1412 switch (calibration->bias) {
1413 case TABLA_MICBIAS1:
1414 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1415 micbias_int_reg = TABLA_A_MICB_1_INT_RBIAS;
1416 micbias_ctl_reg = TABLA_A_MICB_1_CTL;
1417 break;
1418 case TABLA_MICBIAS2:
1419 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1420 micbias_int_reg = TABLA_A_MICB_2_INT_RBIAS;
1421 micbias_ctl_reg = TABLA_A_MICB_2_CTL;
1422 break;
1423 case TABLA_MICBIAS3:
1424 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1425 micbias_int_reg = TABLA_A_MICB_3_INT_RBIAS;
1426 micbias_ctl_reg = TABLA_A_MICB_3_CTL;
1427 break;
1428 case TABLA_MICBIAS4:
1429 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1430 micbias_int_reg = TABLA_A_MICB_4_INT_RBIAS;
1431 micbias_ctl_reg = TABLA_A_MICB_4_CTL;
1432 break;
1433 default:
1434 pr_err("Error, invalid mic bias line\n");
1435 return -EINVAL;
1436 }
1437 snd_soc_update_bits(codec, micbias_int_reg, 0x80, 0);
1438 snd_soc_update_bits(codec, micbias_ctl_reg, 0x1, 0);
1439
1440 /* If central bandgap disabled */
1441 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
1442 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
1443 usleep_range(calibration->bg_fast_settle,
1444 calibration->bg_fast_settle);
1445 central_bias_enabled = 1;
1446 }
1447
1448 /* If LDO_H disabled */
1449 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
1450 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
1451 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
1452 usleep_range(calibration->tldoh, calibration->tldoh);
1453 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
1454
1455 if (central_bias_enabled)
1456 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
1457 }
1458 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x60,
1459 calibration->mic_current << 5);
1460 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x80);
1461 usleep_range(calibration->mic_pid, calibration->mic_pid);
1462 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x10);
1463
1464 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
1465
1466 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1467 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
1468 return 0;
1469}
1470
Bradley Rubincb1e2732011-06-23 16:49:20 -07001471int tabla_hs_detect(struct snd_soc_codec *codec,
1472 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 struct tabla_mbhc_calibration *calibration)
1474{
1475 struct tabla_priv *tabla;
1476 if (!codec || !calibration) {
1477 pr_err("Error: no codec or calibration\n");
1478 return -EINVAL;
1479 }
1480 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001481 tabla->headset_jack = headset_jack;
1482 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 tabla->calibration = calibration;
1484
1485 return tabla_codec_enable_hs_detect(codec, 1);
1486}
1487EXPORT_SYMBOL_GPL(tabla_hs_detect);
1488
Bradley Rubincb1e2732011-06-23 16:49:20 -07001489static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490{
1491 struct tabla_priv *priv = data;
1492 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001493
1494 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1495 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1496
1497 pr_debug("%s: Button pressed\n", __func__);
1498 if (priv->button_jack)
1499 snd_soc_jack_report(priv->button_jack, SND_JACK_BTN_0,
1500 SND_JACK_BTN_0);
1501
1502 priv->buttons_pressed |= SND_JACK_BTN_0;
1503 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1504 0x09);
1505 usleep_range(100000, 100000);
1506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 return IRQ_HANDLED;
1508}
1509
Bradley Rubincb1e2732011-06-23 16:49:20 -07001510static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511{
1512 struct tabla_priv *priv = data;
1513 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07001514 if (priv->buttons_pressed & SND_JACK_BTN_0) {
1515 pr_debug("%s: Button released\n", __func__);
1516 if (priv->button_jack)
1517 snd_soc_jack_report(priv->button_jack, 0,
1518 SND_JACK_BTN_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519
Bradley Rubincb1e2732011-06-23 16:49:20 -07001520 priv->buttons_pressed &= ~SND_JACK_BTN_0;
1521 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1522 0x08);
1523 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525
1526 return IRQ_HANDLED;
1527}
1528
Bradley Rubincb1e2732011-06-23 16:49:20 -07001529static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
1530{
1531 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1532 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1533 int micbias_mbhc_reg;
1534
1535 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1536 tabla_codec_enable_config_mode(codec, 1);
1537
1538 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1539 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
1540 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x0);
1541
1542 switch (calibration->bias) {
1543 case TABLA_MICBIAS1:
1544 micbias_mbhc_reg = TABLA_A_MICB_1_MBHC;
1545 break;
1546 case TABLA_MICBIAS2:
1547 micbias_mbhc_reg = TABLA_A_MICB_2_MBHC;
1548 break;
1549 case TABLA_MICBIAS3:
1550 micbias_mbhc_reg = TABLA_A_MICB_3_MBHC;
1551 break;
1552 case TABLA_MICBIAS4:
1553 micbias_mbhc_reg = TABLA_A_MICB_4_MBHC;
1554 break;
1555 default:
1556 pr_err("Error, invalid mic bias line\n");
1557 return;
1558 }
1559 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x80, 0x00);
1560 snd_soc_update_bits(codec, micbias_mbhc_reg, 0x10, 0x00);
1561 usleep_range(calibration->shutdown_plug_removal,
1562 calibration->shutdown_plug_removal);
1563
1564 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1565 if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
1566 tabla_codec_enable_config_mode(codec, 0);
1567
1568 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
1569}
1570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
1572{
1573 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001574
1575 tabla_codec_shutdown_hs_removal_detect(codec);
1576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 if (!tabla->ref_cnt) {
1578 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
1579 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1580 tabla_codec_enable_clock_block(codec, 0);
1581 }
1582
1583 tabla->mbhc_polling_active = false;
1584}
1585
Bradley Rubincb1e2732011-06-23 16:49:20 -07001586static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
1587{
1588 struct tabla_priv *priv = data;
1589 struct snd_soc_codec *codec = priv->codec;
1590 int microphone_present;
1591
1592 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1593
1594 usleep_range(priv->calibration->setup_plug_removal_delay,
1595 priv->calibration->setup_plug_removal_delay);
1596
1597 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02) {
1598 if (priv->headset_jack) {
1599 pr_debug("%s: Reporting removal\n", __func__);
1600 snd_soc_jack_report(priv->headset_jack, 0,
1601 SND_JACK_HEADSET);
1602 }
1603 tabla_codec_shutdown_hs_removal_detect(codec);
1604 tabla_codec_enable_hs_detect(codec, 1);
1605 return IRQ_HANDLED;
1606 }
1607
1608 microphone_present = tabla_codec_setup_hs_polling(codec);
1609
1610 if (microphone_present == 0) {
1611 if (priv->headset_jack) {
1612 pr_debug("%s: Reporting insertion %d\n", __func__,
1613 SND_JACK_HEADPHONE);
1614 snd_soc_jack_report(priv->headset_jack,
1615 SND_JACK_HEADPHONE, SND_JACK_HEADSET);
1616 }
1617 tabla_codec_shutdown_hs_polling(codec);
1618 tabla_codec_enable_hs_detect(codec, 0);
1619 } else if (microphone_present == 1) {
1620 if (priv->headset_jack) {
1621 pr_debug("%s: Reporting insertion %d\n", __func__,
1622 SND_JACK_HEADSET);
1623 snd_soc_jack_report(priv->headset_jack,
1624 SND_JACK_HEADSET, SND_JACK_HEADSET);
1625 }
1626 tabla_codec_start_hs_polling(codec);
1627 }
1628
1629 return IRQ_HANDLED;
1630}
1631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
1633{
1634 struct tabla_priv *priv = data;
1635 struct snd_soc_codec *codec = priv->codec;
1636
1637 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1638 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1639
1640 usleep_range(priv->calibration->shutdown_plug_removal,
1641 priv->calibration->shutdown_plug_removal);
1642
Bradley Rubincb1e2732011-06-23 16:49:20 -07001643 if (priv->headset_jack) {
1644 pr_debug("%s: Reporting removal\n", __func__);
1645 snd_soc_jack_report(priv->headset_jack, 0, SND_JACK_HEADSET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 }
1647 tabla_codec_shutdown_hs_polling(codec);
1648
1649 tabla_codec_enable_hs_detect(codec, 1);
1650
1651 return IRQ_HANDLED;
1652}
1653
1654static unsigned long slimbus_value;
1655
1656static irqreturn_t tabla_slimbus_irq(int irq, void *data)
1657{
1658 struct tabla_priv *priv = data;
1659 struct snd_soc_codec *codec = priv->codec;
1660 int i, j;
1661 u8 val;
1662
1663 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
1664 slimbus_value = tabla_interface_reg_read(codec->control_data,
1665 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
1666 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
1667 val = tabla_interface_reg_read(codec->control_data,
1668 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
1669 if (val & 0x1)
1670 pr_err_ratelimited("overflow error on port %x,"
1671 " value %x\n", i*8 + j, val);
1672 if (val & 0x2)
1673 pr_err_ratelimited("underflow error on port %x,"
1674 " value %x\n", i*8 + j, val);
1675 }
1676 tabla_interface_reg_write(codec->control_data,
1677 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
1678 }
1679
1680 return IRQ_HANDLED;
1681}
1682
1683static int tabla_codec_probe(struct snd_soc_codec *codec)
1684{
1685 struct tabla *control;
1686 struct tabla_priv *tabla;
1687 struct snd_soc_dapm_context *dapm = &codec->dapm;
1688 int ret = 0;
1689 int i;
1690 int tx_channel;
1691
1692 codec->control_data = dev_get_drvdata(codec->dev->parent);
1693 control = codec->control_data;
1694
1695 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
1696 if (!tabla) {
1697 dev_err(codec->dev, "Failed to allocate private data\n");
1698 return -ENOMEM;
1699 }
1700
1701 snd_soc_codec_set_drvdata(codec, tabla);
1702
1703 tabla->ref_cnt = 0;
1704 tabla->bandgap_type = TABLA_BANDGAP_OFF;
1705 tabla->clock_active = false;
1706 tabla->config_mode_active = false;
1707 tabla->mbhc_polling_active = false;
1708 tabla->codec = codec;
1709
1710 /* TODO only enable bandgap when necessary in order to save power */
1711 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
1712 tabla_codec_enable_clock_block(codec, 0);
1713
1714 /* Initialize gain registers to use register gain */
1715 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10);
1716 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10);
1717 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10);
1718 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10);
1719
1720 /* Initialize mic biases to differential mode */
1721 snd_soc_update_bits(codec, TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24);
1722 snd_soc_update_bits(codec, TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24);
1723 snd_soc_update_bits(codec, TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24);
1724 snd_soc_update_bits(codec, TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24);
1725
1726 /* Set headset CFILT to fast mode */
1727 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_CTL, 0x00, 0x00);
1728 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_CTL, 0x00, 0x00);
1729 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_CTL, 0x00, 0x00);
1730
1731 snd_soc_update_bits(codec, TABLA_A_CDC_CONN_CLSG_CTL, 0x30, 0x10);
1732
1733 /* Use 16 bit sample size for now */
1734 for (tx_channel = 0; tx_channel < 6; tx_channel++) {
1735 snd_soc_update_bits(codec,
1736 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x30, 0x20);
1737 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07001738 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739
1740 }
1741 for (tx_channel = 6; tx_channel < 10; tx_channel++) {
1742 snd_soc_update_bits(codec,
1743 TABLA_A_CDC_CONN_TX_SB_B1_CTL + tx_channel, 0x60, 0x40);
1744 snd_soc_update_bits(codec,
Kiran Kandi2c22fe72011-07-07 11:08:19 -07001745 TABLA_A_CDC_TX1_MUX_CTL + (tx_channel * 8), 0x8, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 }
1747 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xAA);
1748 snd_soc_write(codec, TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xAA);
1749
1750 snd_soc_add_controls(codec, tabla_snd_controls,
1751 ARRAY_SIZE(tabla_snd_controls));
1752 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
1753 ARRAY_SIZE(tabla_dapm_widgets));
1754 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
1755 snd_soc_dapm_sync(dapm);
1756
1757 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
1758 tabla_hs_insert_irq, "Headset insert detect", tabla);
1759 if (ret) {
1760 pr_err("%s: Failed to request irq %d\n", __func__,
1761 TABLA_IRQ_MBHC_INSERTION);
1762 goto err_insert_irq;
1763 }
1764 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
1765
1766 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
1767 tabla_hs_remove_irq, "Headset remove detect", tabla);
1768 if (ret) {
1769 pr_err("%s: Failed to request irq %d\n", __func__,
1770 TABLA_IRQ_MBHC_REMOVAL);
1771 goto err_remove_irq;
1772 }
1773 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
1774
1775 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07001776 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 if (ret) {
1778 pr_err("%s: Failed to request irq %d\n", __func__,
1779 TABLA_IRQ_MBHC_POTENTIAL);
1780 goto err_potential_irq;
1781 }
1782 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1783
Bradley Rubincb1e2732011-06-23 16:49:20 -07001784 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
1785 tabla_release_handler, "Button Release detect", tabla);
1786 if (ret) {
1787 pr_err("%s: Failed to request irq %d\n", __func__,
1788 TABLA_IRQ_MBHC_RELEASE);
1789 goto err_release_irq;
1790 }
1791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
1793 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
1794 if (ret) {
1795 pr_err("%s: Failed to request irq %d\n", __func__,
1796 TABLA_IRQ_SLIMBUS);
1797 goto err_slimbus_irq;
1798 }
1799
1800 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
1801 tabla_interface_reg_write(codec->control_data,
1802 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
1803
1804 return ret;
1805
1806err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07001807 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
1808err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
1810err_potential_irq:
1811 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
1812err_remove_irq:
1813 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
1814err_insert_irq:
1815 kfree(tabla);
1816 return ret;
1817}
1818static int tabla_codec_remove(struct snd_soc_codec *codec)
1819{
1820 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1821 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07001822 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
1824 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
1825 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
1826 tabla_codec_disable_clock_block(codec);
1827 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
1828 kfree(tabla);
1829 return 0;
1830}
1831static struct snd_soc_codec_driver soc_codec_dev_tabla = {
1832 .probe = tabla_codec_probe,
1833 .remove = tabla_codec_remove,
1834 .read = tabla_read,
1835 .write = tabla_write,
1836
1837 .readable_register = tabla_readable,
1838 .volatile_register = tabla_volatile,
1839
1840 .reg_cache_size = TABLA_CACHE_SIZE,
1841 .reg_cache_default = tabla_reg_defaults,
1842 .reg_word_size = 1,
1843};
1844static int __devinit tabla_probe(struct platform_device *pdev)
1845{
1846 return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
1847 tabla_dai, ARRAY_SIZE(tabla_dai));
1848}
1849static int __devexit tabla_remove(struct platform_device *pdev)
1850{
1851 snd_soc_unregister_codec(&pdev->dev);
1852 return 0;
1853}
1854static struct platform_driver tabla_codec_driver = {
1855 .probe = tabla_probe,
1856 .remove = tabla_remove,
1857 .driver = {
1858 .name = "tabla_codec",
1859 .owner = THIS_MODULE,
1860 },
1861};
1862
1863static int __init tabla_codec_init(void)
1864{
1865 return platform_driver_register(&tabla_codec_driver);
1866}
1867
1868static void __exit tabla_codec_exit(void)
1869{
1870 platform_driver_unregister(&tabla_codec_driver);
1871}
1872
1873module_init(tabla_codec_init);
1874module_exit(tabla_codec_exit);
1875
1876MODULE_DESCRIPTION("Tabla codec driver");
1877MODULE_VERSION("1.0");
1878MODULE_LICENSE("GPL v2");