blob: 70d9fa9e5fe3d228a445e515ecd6dd5b6836e548 [file] [log] [blame]
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301/* Copyright (c) 2012, 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/firmware.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
21#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/jack.h>
28#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/tlv.h>
31#include <linux/bitops.h>
32#include <linux/delay.h>
Asish Bhattacharya1d069532012-03-07 13:25:24 -080033#include <linux/pm_runtime.h>
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070034#include <linux/kernel.h>
35#include <linux/gpio.h>
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053036#include "wcd9304.h"
37
38#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
39 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
40
41#define NUM_DECIMATORS 4
42#define NUM_INTERPOLATORS 3
43#define BITS_PER_REG 8
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080044#define SITAR_CFILT_FAST_MODE 0x00
45#define SITAR_CFILT_SLOW_MODE 0x40
46#define MBHC_FW_READ_ATTEMPTS 15
47#define MBHC_FW_READ_TIMEOUT 2000000
48
49#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
50
51#define SITAR_I2S_MASTER_MODE_MASK 0x08
52
53#define SITAR_OCP_ATTEMPT 1
54
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053055#define AIF1_PB 1
56#define AIF1_CAP 2
57#define NUM_CODEC_DAIS 2
58
59struct sitar_codec_dai_data {
60 u32 rate;
61 u32 *ch_num;
62 u32 ch_act;
63 u32 ch_tot;
64};
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053065
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080066#define SITAR_MCLK_RATE_12288KHZ 12288000
67#define SITAR_MCLK_RATE_9600KHZ 9600000
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053068
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080069#define SITAR_FAKE_INS_THRESHOLD_MS 2500
70#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070071#define SITAR_MBHC_BUTTON_MIN 0x8000
72#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
73
74#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
75#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
76
77#define MBHC_NUM_DCE_PLUG_DETECT 3
78#define SITAR_MBHC_FAKE_INSERT_LOW 10
79#define SITAR_MBHC_FAKE_INSERT_HIGH 80
80#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
81#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
82#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
83#define NUM_ATTEMPTS_TO_REPORT 5
84#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
85#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053086
87static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
88static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
89static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
90static struct snd_soc_dai_driver sitar_dai[];
91static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
92 struct snd_kcontrol *kcontrol, int event);
93static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
94 struct snd_kcontrol *kcontrol, int event);
95
96enum sitar_bandgap_type {
97 SITAR_BANDGAP_OFF = 0,
98 SITAR_BANDGAP_AUDIO_MODE,
99 SITAR_BANDGAP_MBHC_MODE,
100};
101
102struct mbhc_micbias_regs {
103 u16 cfilt_val;
104 u16 cfilt_ctl;
105 u16 mbhc_reg;
106 u16 int_rbias;
107 u16 ctl_reg;
108 u8 cfilt_sel;
109};
110
111/* Codec supports 2 IIR filters */
112enum {
113 IIR1 = 0,
114 IIR2,
115 IIR_MAX,
116};
117/* Codec supports 5 bands */
118enum {
119 BAND1 = 0,
120 BAND2,
121 BAND3,
122 BAND4,
123 BAND5,
124 BAND_MAX,
125};
126
127/* Flags to track of PA and DAC state.
128 * PA and DAC should be tracked separately as AUXPGA loopback requires
129 * only PA to be turned on without DAC being on. */
130enum sitar_priv_ack_flags {
131 SITAR_HPHL_PA_OFF_ACK = 0,
132 SITAR_HPHR_PA_OFF_ACK,
133 SITAR_HPHL_DAC_OFF_ACK,
134 SITAR_HPHR_DAC_OFF_ACK
135};
136
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800137/* Data used by MBHC */
138struct mbhc_internal_cal_data {
139 u16 dce_z;
140 u16 dce_mb;
141 u16 sta_z;
142 u16 sta_mb;
143 u32 t_sta_dce;
144 u32 t_dce;
145 u32 t_sta;
146 u32 micb_mv;
147 u16 v_ins_hu;
148 u16 v_ins_h;
149 u16 v_b1_hu;
150 u16 v_b1_h;
151 u16 v_b1_huc;
152 u16 v_brh;
153 u16 v_brl;
154 u16 v_no_mic;
155 u8 npoll;
156 u8 nbounce_wait;
157};
158
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700159enum sitar_mbhc_plug_type {
160 PLUG_TYPE_INVALID = -1,
161 PLUG_TYPE_NONE,
162 PLUG_TYPE_HEADSET,
163 PLUG_TYPE_HEADPHONE,
164 PLUG_TYPE_HIGH_HPH,
165};
166
167enum sitar_mbhc_state {
168 MBHC_STATE_NONE = -1,
169 MBHC_STATE_POTENTIAL,
170 MBHC_STATE_POTENTIAL_RECOVERY,
171 MBHC_STATE_RELEASE,
172};
173
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530174struct sitar_priv {
175 struct snd_soc_codec *codec;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800176 u32 mclk_freq;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530177 u32 adc_count;
178 u32 cfilt1_cnt;
179 u32 cfilt2_cnt;
180 u32 cfilt3_cnt;
181 u32 rx_bias_count;
182 enum sitar_bandgap_type bandgap_type;
183 bool mclk_enabled;
184 bool clock_active;
185 bool config_mode_active;
186 bool mbhc_polling_active;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800187 unsigned long mbhc_fake_ins_start;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530188 int buttons_pressed;
189
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800190 enum sitar_micbias_num micbias;
191 /* void* calibration contains:
192 * struct sitar_mbhc_general_cfg generic;
193 * struct sitar_mbhc_plug_detect_cfg plug_det;
194 * struct sitar_mbhc_plug_type_cfg plug_type;
195 * struct sitar_mbhc_btn_detect_cfg btn_det;
196 * struct sitar_mbhc_imped_detect_cfg imped_det;
197 * Note: various size depends on btn_det->num_btn
198 */
199 void *calibration;
200 struct mbhc_internal_cal_data mbhc_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530201
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530202 struct wcd9xxx_pdata *pdata;
203 u32 anc_slot;
204
205 bool no_mic_headset_override;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530206
207 struct mbhc_micbias_regs mbhc_bias_regs;
208 u8 cfilt_k_value;
209 bool mbhc_micbias_switched;
210
211 /* track PA/DAC state */
212 unsigned long hph_pa_dac_state;
213
214 /*track sitar interface type*/
215 u8 intf_type;
216
217 u32 hph_status; /* track headhpone status */
218 /* define separate work for left and right headphone OCP to avoid
219 * additional checking on which OCP event to report so no locking
220 * to ensure synchronization is required
221 */
222 struct work_struct hphlocp_work; /* reporting left hph ocp off */
223 struct work_struct hphrocp_work; /* reporting right hph ocp off */
224
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530225 u8 hphlocp_cnt; /* headphone left ocp retry */
226 u8 hphrocp_cnt; /* headphone right ocp retry */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800227
228 /* Callback function to enable MCLK */
229 int (*mclk_cb) (struct snd_soc_codec*, int);
230
231 /* Work to perform MBHC Firmware Read */
232 struct delayed_work mbhc_firmware_dwork;
233 const struct firmware *mbhc_fw;
234
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530235 /* num of slim ports required */
236 struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700237
238 /* Currently, only used for mbhc purpose, to protect
239 * concurrent execution of mbhc threaded irq handlers and
240 * kill race between DAPM and MBHC.But can serve as a
241 * general lock to protect codec resource
242 */
243 struct mutex codec_resource_lock;
244
245 struct sitar_mbhc_config mbhc_cfg;
246 bool in_gpio_handler;
247 u8 current_plug;
248 bool lpi_enabled;
249 enum sitar_mbhc_state mbhc_state;
250 struct work_struct hs_correct_plug_work;
251 bool hs_detect_work_stop;
252 struct delayed_work mbhc_btn_dwork;
253 unsigned long mbhc_last_resume; /* in jiffies */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530254};
255
256#ifdef CONFIG_DEBUG_FS
257struct sitar_priv *debug_sitar_priv;
258#endif
259
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700260static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
261 struct snd_ctl_elem_value *ucontrol)
262{
263 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
264 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
265 ucontrol->value.integer.value[0] = sitar->anc_slot;
266 return 0;
267}
268
269static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
270 struct snd_ctl_elem_value *ucontrol)
271{
272 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
273 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
274 sitar->anc_slot = ucontrol->value.integer.value[0];
275 return 0;
276}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530277
278static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
279 struct snd_ctl_elem_value *ucontrol)
280{
281 u8 ear_pa_gain;
282 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
283
284 ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
285
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700286 ear_pa_gain &= 0xE0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530287
288 if (ear_pa_gain == 0x00) {
289 ucontrol->value.integer.value[0] = 0;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700290 } else if (ear_pa_gain == 0x80) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530291 ucontrol->value.integer.value[0] = 1;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700292 } else if (ear_pa_gain == 0xA0) {
293 ucontrol->value.integer.value[0] = 2;
294 } else if (ear_pa_gain == 0xE0) {
295 ucontrol->value.integer.value[0] = 3;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530296 } else {
297 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
298 __func__, ear_pa_gain);
299 return -EINVAL;
300 }
301
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530302 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530303
304 return 0;
305}
306
307static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
308 struct snd_ctl_elem_value *ucontrol)
309{
310 u8 ear_pa_gain;
311 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
312
313 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
314 ucontrol->value.integer.value[0]);
315
316 switch (ucontrol->value.integer.value[0]) {
317 case 0:
318 ear_pa_gain = 0x00;
319 break;
320 case 1:
321 ear_pa_gain = 0x80;
322 break;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700323 case 2:
324 ear_pa_gain = 0xA0;
325 break;
326 case 3:
327 ear_pa_gain = 0xE0;
328 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530329 default:
330 return -EINVAL;
331 }
332
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700333 snd_soc_update_bits(codec, SITAR_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530334 return 0;
335}
336
337static int sitar_get_iir_enable_audio_mixer(
338 struct snd_kcontrol *kcontrol,
339 struct snd_ctl_elem_value *ucontrol)
340{
341 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
342 int iir_idx = ((struct soc_multi_mixer_control *)
343 kcontrol->private_value)->reg;
344 int band_idx = ((struct soc_multi_mixer_control *)
345 kcontrol->private_value)->shift;
346
347 ucontrol->value.integer.value[0] =
348 snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
349 (1 << band_idx);
350
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530351 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530352 iir_idx, band_idx,
353 (uint32_t)ucontrol->value.integer.value[0]);
354 return 0;
355}
356
357static int sitar_put_iir_enable_audio_mixer(
358 struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_value *ucontrol)
360{
361 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
362 int iir_idx = ((struct soc_multi_mixer_control *)
363 kcontrol->private_value)->reg;
364 int band_idx = ((struct soc_multi_mixer_control *)
365 kcontrol->private_value)->shift;
366 int value = ucontrol->value.integer.value[0];
367
368 /* Mask first 5 bits, 6-8 are reserved */
369 snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
370 (1 << band_idx), (value << band_idx));
371
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530372 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530373 iir_idx, band_idx, value);
374 return 0;
375}
376static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
377 int iir_idx, int band_idx,
378 int coeff_idx)
379{
380 /* Address does not automatically update if reading */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530381 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530382 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530383 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530384
385 /* Mask bits top 2 bits since they are reserved */
386 return ((snd_soc_read(codec,
387 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
388 (snd_soc_read(codec,
389 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
390 (snd_soc_read(codec,
391 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
392 (snd_soc_read(codec,
393 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
394 0x3FFFFFFF;
395}
396
397static int sitar_get_iir_band_audio_mixer(
398 struct snd_kcontrol *kcontrol,
399 struct snd_ctl_elem_value *ucontrol)
400{
401 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
402 int iir_idx = ((struct soc_multi_mixer_control *)
403 kcontrol->private_value)->reg;
404 int band_idx = ((struct soc_multi_mixer_control *)
405 kcontrol->private_value)->shift;
406
407 ucontrol->value.integer.value[0] =
408 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
409 ucontrol->value.integer.value[1] =
410 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
411 ucontrol->value.integer.value[2] =
412 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
413 ucontrol->value.integer.value[3] =
414 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
415 ucontrol->value.integer.value[4] =
416 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
417
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530418 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530419 "%s: IIR #%d band #%d b1 = 0x%x\n"
420 "%s: IIR #%d band #%d b2 = 0x%x\n"
421 "%s: IIR #%d band #%d a1 = 0x%x\n"
422 "%s: IIR #%d band #%d a2 = 0x%x\n",
423 __func__, iir_idx, band_idx,
424 (uint32_t)ucontrol->value.integer.value[0],
425 __func__, iir_idx, band_idx,
426 (uint32_t)ucontrol->value.integer.value[1],
427 __func__, iir_idx, band_idx,
428 (uint32_t)ucontrol->value.integer.value[2],
429 __func__, iir_idx, band_idx,
430 (uint32_t)ucontrol->value.integer.value[3],
431 __func__, iir_idx, band_idx,
432 (uint32_t)ucontrol->value.integer.value[4]);
433 return 0;
434}
435
436static void set_iir_band_coeff(struct snd_soc_codec *codec,
437 int iir_idx, int band_idx,
438 int coeff_idx, uint32_t value)
439{
440 /* Mask top 3 bits, 6-8 are reserved */
441 /* Update address manually each time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530442 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530443 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530444 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530445
446 /* Mask top 2 bits, 7-8 are reserved */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530447 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530448 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530449 (value >> 24) & 0x3F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530450
451 /* Isolate 8bits at a time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530452 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530453 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530454 (value >> 16) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530455
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530456 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530457 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530458 (value >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530459
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530460 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530461 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530462 value & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530463}
464
465static int sitar_put_iir_band_audio_mixer(
466 struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
468{
469 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
470 int iir_idx = ((struct soc_multi_mixer_control *)
471 kcontrol->private_value)->reg;
472 int band_idx = ((struct soc_multi_mixer_control *)
473 kcontrol->private_value)->shift;
474
475 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
476 ucontrol->value.integer.value[0]);
477 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
478 ucontrol->value.integer.value[1]);
479 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
480 ucontrol->value.integer.value[2]);
481 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
482 ucontrol->value.integer.value[3]);
483 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
484 ucontrol->value.integer.value[4]);
485
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530486 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530487 "%s: IIR #%d band #%d b1 = 0x%x\n"
488 "%s: IIR #%d band #%d b2 = 0x%x\n"
489 "%s: IIR #%d band #%d a1 = 0x%x\n"
490 "%s: IIR #%d band #%d a2 = 0x%x\n",
491 __func__, iir_idx, band_idx,
492 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
493 __func__, iir_idx, band_idx,
494 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
495 __func__, iir_idx, band_idx,
496 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
497 __func__, iir_idx, band_idx,
498 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
499 __func__, iir_idx, band_idx,
500 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
501 return 0;
502}
503
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700504static const char * const sitar_ear_pa_gain_text[] = {"POS_6_DB",
505 "POS_2_DB", "NEG_2P5_DB", "NEG_12_DB"};
506
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530507static const struct soc_enum sitar_ear_pa_gain_enum[] = {
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700508 SOC_ENUM_SINGLE_EXT(4, sitar_ear_pa_gain_text),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530509};
510
511/*cut of frequency for high pass filter*/
512static const char *cf_text[] = {
513 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
514};
515
516static const struct soc_enum cf_dec1_enum =
517 SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
518
519static const struct soc_enum cf_rxmix1_enum =
520 SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
521
522static const struct snd_kcontrol_new sitar_snd_controls[] = {
523
524 SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
525 sitar_pa_gain_get, sitar_pa_gain_put),
526
527 SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
528 line_gain),
529 SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
530 line_gain),
531
532 SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
533 line_gain),
534 SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
535 line_gain),
536
537 SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
538 -84, 40, digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800539 SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
540 -84, 40, digital_gain),
541 SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
542 -84, 40, digital_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530543
544 SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
545 digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800546 SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
547 digital_gain),
548 SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
549 digital_gain),
550 SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
551 digital_gain),
552
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530553 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
554 40, digital_gain),
555 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
556 40, digital_gain),
557 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
558 40, digital_gain),
559 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
560 40, digital_gain),
561 SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
562 SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800563 SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530564
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700565 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
566 sitar_put_anc_slot),
567
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530568 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
569
570 SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
571
572 SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
573
574 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
575
576 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
577 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
578 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
579 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
580 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
581 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
582 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
583 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
584 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
585 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
586 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
587 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
588 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
589 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
590 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
591 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
592 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
593 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
594 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
595 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
596
597 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
598 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
599 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
600 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
601 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
602 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
603 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
604 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
605 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
606 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
607 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
608 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
609 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
610 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
611 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
612 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
613 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
614 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
615 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
616 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
617};
618
619static const char *rx_mix1_text[] = {
620 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
621 "RX5"
622};
623
624static const char *rx_dac1_text[] = {
625 "ZERO", "RX1", "RX2"
626};
627
628static const char *rx_dac2_text[] = {
629 "ZERO", "RX1",
630};
631
632static const char *rx_dac3_text[] = {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800633 "ZERO", "RX1", "INV_RX1", "RX2"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530634};
635
636static const char *rx_dac4_text[] = {
637 "ZERO", "ON"
638};
639
640static const char *sb_tx1_mux_text[] = {
641 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
642 "DEC1"
643};
644
645static const char *sb_tx2_mux_text[] = {
646 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
647 "DEC2"
648};
649
650static const char *sb_tx3_mux_text[] = {
651 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
652 "DEC3"
653};
654
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800655static const char *sb_tx4_mux_text[] = {
656 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
657 "DEC4"
658};
659
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530660static const char *sb_tx5_mux_text[] = {
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -0700661 "ZERO", "RMIX1", "RMIX2", "RMIX3", "DEC1", "DEC2", "DEC3", "DEC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530662};
663
664static const char *dec1_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700665 "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530666};
667
668static const char *dec2_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700669 "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530670};
671
672static const char *dec3_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -0700673 "ZERO", "DMIC3", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC2", "DMIC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530674};
675
676static const char *dec4_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -0700677 "ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530678};
679
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700680static const char const *anc_mux_text[] = {
681 "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
682 "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
683};
684
685static const char const *anc1_fb_mux_text[] = {
686 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
687};
688
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530689static const char const *iir_inp1_text[] = {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530690 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
691 "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
692};
693
694static const struct soc_enum rx_mix1_inp1_chain_enum =
695 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
696
697static const struct soc_enum rx_mix1_inp2_chain_enum =
698 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
699
700static const struct soc_enum rx2_mix1_inp1_chain_enum =
701 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
702
703static const struct soc_enum rx2_mix1_inp2_chain_enum =
704 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
705
706static const struct soc_enum rx3_mix1_inp1_chain_enum =
707 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
708
709static const struct soc_enum rx3_mix1_inp2_chain_enum =
710 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
711
712static const struct soc_enum rx_dac1_enum =
713 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
714
715static const struct soc_enum rx_dac2_enum =
716 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
717
718static const struct soc_enum rx_dac3_enum =
719 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
720
721static const struct soc_enum rx_dac4_enum =
722 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
723
724static const struct soc_enum sb_tx5_mux_enum =
725 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
726
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800727static const struct soc_enum sb_tx4_mux_enum =
728 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
729
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530730static const struct soc_enum sb_tx3_mux_enum =
731 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
732
733static const struct soc_enum sb_tx2_mux_enum =
734 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
735
736static const struct soc_enum sb_tx1_mux_enum =
737 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
738
739static const struct soc_enum dec1_mux_enum =
740 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
741
742static const struct soc_enum dec2_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800743 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530744
745static const struct soc_enum dec3_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800746 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530747
748static const struct soc_enum dec4_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800749 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530750
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700751static const struct soc_enum anc1_mux_enum =
752 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
753
754static const struct soc_enum anc2_mux_enum =
755 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
756
757static const struct soc_enum anc1_fb_mux_enum =
758 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
759
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530760static const struct soc_enum iir1_inp1_mux_enum =
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530761 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir_inp1_text);
762
763static const struct soc_enum iir2_inp1_mux_enum =
764 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ2_B1_CTL, 0, 16, iir_inp1_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530765
766static const struct snd_kcontrol_new rx_mix1_inp1_mux =
767 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
768
769static const struct snd_kcontrol_new rx_mix1_inp2_mux =
770 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
771
772static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
773 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
774
775static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
776 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
777
778static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
779 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
780
781static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
782 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
783
784static const struct snd_kcontrol_new rx_dac1_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800785 SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530786
787static const struct snd_kcontrol_new rx_dac2_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800788 SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530789
790static const struct snd_kcontrol_new rx_dac3_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800791 SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530792
793static const struct snd_kcontrol_new rx_dac4_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800794 SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530795
796static const struct snd_kcontrol_new sb_tx5_mux =
797 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
798
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800799static const struct snd_kcontrol_new sb_tx4_mux =
800 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
801
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530802static const struct snd_kcontrol_new sb_tx3_mux =
803 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
804
805static const struct snd_kcontrol_new sb_tx2_mux =
806 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
807
808static const struct snd_kcontrol_new sb_tx1_mux =
809 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
810
811static const struct snd_kcontrol_new dec1_mux =
812 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
813
814static const struct snd_kcontrol_new dec2_mux =
815 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
816
817static const struct snd_kcontrol_new dec3_mux =
818 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
819
820static const struct snd_kcontrol_new dec4_mux =
821 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
822
823static const struct snd_kcontrol_new iir1_inp1_mux =
824 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
825
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530826static const struct snd_kcontrol_new iir2_inp1_mux =
827 SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
828
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700829static const struct snd_kcontrol_new anc1_mux =
830 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
831
832static const struct snd_kcontrol_new anc2_mux =
833 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
834
835static const struct snd_kcontrol_new anc1_fb_mux =
836 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
837
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530838static const struct snd_kcontrol_new dac1_switch[] = {
839 SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
840};
841
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530842static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
843 int enable)
844{
845 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
846
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530847 pr_debug("%s %d\n", __func__, enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530848
849 if (enable) {
850 sitar->adc_count++;
851 snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
852
853 } else {
854 sitar->adc_count--;
855 if (!sitar->adc_count) {
856 if (!sitar->mbhc_polling_active)
857 snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS,
858 0xE0, 0x0);
859 }
860 }
861}
862
863static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
864 struct snd_kcontrol *kcontrol, int event)
865{
866 struct snd_soc_codec *codec = w->codec;
867 u16 adc_reg;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700868 u8 init_bit_shift;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530869
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530870 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530871
872 if (w->reg == SITAR_A_TX_1_2_EN)
873 adc_reg = SITAR_A_TX_1_2_TEST_CTL;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700874 else if (w->reg == SITAR_A_TX_3_EN)
875 adc_reg = SITAR_A_TX_3_TEST_CTL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530876 else {
877 pr_err("%s: Error, invalid adc register\n", __func__);
878 return -EINVAL;
879 }
880
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700881 if (w->shift == 3)
882 init_bit_shift = 6;
883 else if (w->shift == 7)
884 init_bit_shift = 7;
885 else {
886 pr_err("%s: Error, invalid init bit postion adc register\n",
887 __func__);
888 return -EINVAL;
889 }
890
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530891 switch (event) {
892 case SND_SOC_DAPM_PRE_PMU:
893 sitar_codec_enable_adc_block(codec, 1);
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700894 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
895 1 << init_bit_shift);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530896 break;
897 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700898
899 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
900
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530901 break;
902 case SND_SOC_DAPM_POST_PMD:
903 sitar_codec_enable_adc_block(codec, 0);
904 break;
905 }
906 return 0;
907}
908
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800909static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
910 struct snd_kcontrol *kcontrol, int event)
911{
912 struct snd_soc_codec *codec = w->codec;
913
914 pr_debug("%s %s %d\n", __func__, w->name, event);
915
916 switch (event) {
917 case SND_SOC_DAPM_PRE_PMU:
918 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
919 break;
920
921 case SND_SOC_DAPM_POST_PMD:
922 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
923 break;
924 }
925 return 0;
926}
927
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530928static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
929 struct snd_kcontrol *kcontrol, int event)
930{
931 struct snd_soc_codec *codec = w->codec;
932 u16 lineout_gain_reg;
933
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530934 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530935
936 switch (w->shift) {
937 case 0:
938 lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
939 break;
940 case 1:
941 lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
942 break;
943 default:
944 pr_err("%s: Error, incorrect lineout register value\n",
945 __func__);
946 return -EINVAL;
947 }
948
949 switch (event) {
950 case SND_SOC_DAPM_PRE_PMU:
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800951 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530952 break;
953 case SND_SOC_DAPM_POST_PMU:
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530954 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530955 __func__, w->name);
956 usleep_range(16000, 16000);
957 break;
958 case SND_SOC_DAPM_POST_PMD:
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800959 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530960 break;
961 }
962 return 0;
963}
964
965static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
966 struct snd_kcontrol *kcontrol, int event)
967{
968 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -0700969 u16 tx_dmic_ctl_reg, tx_mux_ctl_reg;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530970 u8 dmic_clk_sel, dmic_clk_en;
971 unsigned int dmic;
972 int ret;
973
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -0700974 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530975 if (ret < 0) {
976 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
977 return -EINVAL;
978 }
979
980 switch (dmic) {
981 case 1:
982 case 2:
983 dmic_clk_sel = 0x02;
984 dmic_clk_en = 0x01;
985 break;
986 case 3:
987 case 4:
988 dmic_clk_sel = 0x08;
989 dmic_clk_en = 0x04;
990 break;
991
992 break;
993
994 default:
995 pr_err("%s: Invalid DMIC Selection\n", __func__);
996 return -EINVAL;
997 }
998
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -0700999 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301000 tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1001
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301002 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301003
1004 switch (event) {
1005 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -07001006 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x01);
1007
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301008 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1009 dmic_clk_sel, dmic_clk_sel);
1010
1011 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1012
1013 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1014 dmic_clk_en, dmic_clk_en);
1015 break;
1016 case SND_SOC_DAPM_POST_PMD:
1017 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1018 dmic_clk_en, 0);
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -07001019
1020 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301021 break;
1022 }
1023 return 0;
1024}
1025
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001026static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
1027 struct snd_kcontrol *kcontrol, int event)
1028{
1029 struct snd_soc_codec *codec = w->codec;
1030 const char *filename;
1031 const struct firmware *fw;
1032 int i;
1033 int ret;
1034 int num_anc_slots;
1035 struct anc_header *anc_head;
1036 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1037 u32 anc_writes_size = 0;
1038 int anc_size_remaining;
1039 u32 *anc_ptr;
1040 u16 reg;
1041 u8 mask, val, old_val;
1042
1043 pr_debug("%s %d\n", __func__, event);
1044 switch (event) {
1045 case SND_SOC_DAPM_PRE_PMU:
1046
1047 /* Use the same firmware file as that of WCD9310,
1048 * since the register sequences are same for
1049 * WCD9310 and WCD9304
1050 */
1051 filename = "wcd9310/wcd9310_anc.bin";
1052
1053 ret = request_firmware(&fw, filename, codec->dev);
1054 if (ret != 0) {
1055 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1056 ret);
1057 return -ENODEV;
1058 }
1059
1060 if (fw->size < sizeof(struct anc_header)) {
1061 dev_err(codec->dev, "Not enough data\n");
1062 release_firmware(fw);
1063 return -ENOMEM;
1064 }
1065
1066 /* First number is the number of register writes */
1067 anc_head = (struct anc_header *)(fw->data);
1068 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1069 anc_size_remaining = fw->size - sizeof(struct anc_header);
1070 num_anc_slots = anc_head->num_anc_slots;
1071
1072 if (sitar->anc_slot >= num_anc_slots) {
1073 dev_err(codec->dev, "Invalid ANC slot selected\n");
1074 release_firmware(fw);
1075 return -EINVAL;
1076 }
1077
1078 for (i = 0; i < num_anc_slots; i++) {
1079
1080 if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
1081 dev_err(codec->dev, "Invalid register format\n");
1082 release_firmware(fw);
1083 return -EINVAL;
1084 }
1085 anc_writes_size = (u32)(*anc_ptr);
1086 anc_size_remaining -= sizeof(u32);
1087 anc_ptr += 1;
1088
1089 if (anc_writes_size * SITAR_PACKED_REG_SIZE
1090 > anc_size_remaining) {
1091 dev_err(codec->dev, "Invalid register format\n");
1092 release_firmware(fw);
1093 return -ENOMEM;
1094 }
1095
1096 if (sitar->anc_slot == i)
1097 break;
1098
1099 anc_size_remaining -= (anc_writes_size *
1100 SITAR_PACKED_REG_SIZE);
1101 anc_ptr += anc_writes_size;
1102 }
1103 if (i == num_anc_slots) {
1104 dev_err(codec->dev, "Selected ANC slot not present\n");
1105 release_firmware(fw);
1106 return -ENOMEM;
1107 }
1108
1109 for (i = 0; i < anc_writes_size; i++) {
1110 SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1111 mask, val);
1112 old_val = snd_soc_read(codec, reg);
1113 snd_soc_write(codec, reg, (old_val & ~mask) |
1114 (val & mask));
1115 }
1116
1117 release_firmware(fw);
1118
1119 /* For Sitar, it is required to enable both Feed-forward
1120 * and Feed back clocks to enable ANC
1121 */
1122 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
1123
1124 break;
1125
1126 case SND_SOC_DAPM_POST_PMD:
1127 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1128 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
1129 break;
1130 }
1131 return 0;
1132}
1133
1134
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301135static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
1136{
1137 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001138 int mbhc_state = sitar->mbhc_state;
1139
1140 pr_debug("%s: enter\n", __func__);
1141 if (!sitar->mbhc_polling_active) {
1142 pr_debug("Polling is not active, do not start polling\n");
1143 return;
1144 }
1145 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
1146
1147
1148 if (!sitar->no_mic_headset_override) {
1149 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1150 pr_debug("%s recovering MBHC state macine\n", __func__);
1151 sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
1152 /* set to max button press threshold */
1153 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
1154 0x7F);
1155 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
1156 0xFF);
1157 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
1158 0x7F);
1159 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
1160 0xFF);
1161 /* set to max */
1162 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
1163 0x7F);
1164 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
1165 0xFF);
1166 }
1167 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301168
1169 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001170 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
1171 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1172 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301173}
1174
1175static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
1176{
1177 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1178
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001179 pr_debug("%s: enter\n", __func__);
1180 if (!sitar->mbhc_polling_active) {
1181 pr_debug("polling not active, nothing to pause\n");
1182 return;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301183 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001184
1185 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1186 pr_debug("%s: leave\n", __func__);
1187
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301188}
1189
1190static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1191 int mode)
1192{
1193 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1194 u8 reg_mode_val, cur_mode_val;
1195 bool mbhc_was_polling = false;
1196
1197 if (mode)
1198 reg_mode_val = SITAR_CFILT_FAST_MODE;
1199 else
1200 reg_mode_val = SITAR_CFILT_SLOW_MODE;
1201
1202 cur_mode_val = snd_soc_read(codec,
1203 sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
1204
1205 if (cur_mode_val != reg_mode_val) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001206 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301207 if (sitar->mbhc_polling_active) {
1208 sitar_codec_pause_hs_polling(codec);
1209 mbhc_was_polling = true;
1210 }
1211 snd_soc_update_bits(codec,
1212 sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1213 if (mbhc_was_polling)
1214 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001215 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301216 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301217 cur_mode_val, reg_mode_val);
1218 } else {
1219 pr_err("%s: CFILT Value is already %x\n",
1220 __func__, cur_mode_val);
1221 }
1222}
1223
1224static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1225 u8 cfilt_sel, int inc)
1226{
1227 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1228 u32 *cfilt_cnt_ptr = NULL;
1229 u16 micb_cfilt_reg;
1230
1231 switch (cfilt_sel) {
1232 case SITAR_CFILT1_SEL:
1233 cfilt_cnt_ptr = &sitar->cfilt1_cnt;
1234 micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
1235 break;
1236 case SITAR_CFILT2_SEL:
1237 cfilt_cnt_ptr = &sitar->cfilt2_cnt;
1238 micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
1239 break;
1240 default:
1241 return; /* should not happen */
1242 }
1243
1244 if (inc) {
1245 if (!(*cfilt_cnt_ptr)++) {
1246 /* Switch CFILT to slow mode if MBHC CFILT being used */
1247 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1248 sitar_codec_switch_cfilt_mode(codec, 0);
1249
1250 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1251 }
1252 } else {
1253 /* check if count not zero, decrement
1254 * then check if zero, go ahead disable cfilter
1255 */
1256 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1257 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1258
1259 /* Switch CFILT to fast mode if MBHC CFILT being used */
1260 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1261 sitar_codec_switch_cfilt_mode(codec, 1);
1262 }
1263 }
1264}
1265
1266static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1267{
1268 int rc = -EINVAL;
1269 unsigned min_mv, max_mv;
1270
1271 switch (ldoh_v) {
1272 case SITAR_LDOH_1P95_V:
1273 min_mv = 160;
1274 max_mv = 1800;
1275 break;
1276 case SITAR_LDOH_2P35_V:
1277 min_mv = 200;
1278 max_mv = 2200;
1279 break;
1280 case SITAR_LDOH_2P75_V:
1281 min_mv = 240;
1282 max_mv = 2600;
1283 break;
1284 case SITAR_LDOH_2P85_V:
1285 min_mv = 250;
1286 max_mv = 2700;
1287 break;
1288 default:
1289 goto done;
1290 }
1291
1292 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1293 goto done;
1294
1295 for (rc = 4; rc <= 44; rc++) {
1296 min_mv = max_mv * (rc) / 44;
1297 if (min_mv >= cfilt_mv) {
1298 rc -= 4;
1299 break;
1300 }
1301 }
1302done:
1303 return rc;
1304}
1305
1306static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
1307{
1308 u8 hph_reg_val = 0;
1309 hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
1310
1311 return (hph_reg_val & 0x30) ? true : false;
1312}
1313
1314static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1315{
1316 u8 hph_reg_val = 0;
1317 if (left)
1318 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001319 SITAR_A_RX_HPH_L_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301320 else
1321 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001322 SITAR_A_RX_HPH_R_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301323
1324 return (hph_reg_val & 0xC0) ? true : false;
1325}
1326
1327static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
1328 int vddio_switch)
1329{
1330 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1331 int cfilt_k_val;
1332 bool mbhc_was_polling = false;
1333
1334 switch (vddio_switch) {
1335 case 1:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001336 if (sitar->mbhc_micbias_switched == 0 &&
1337 sitar->mbhc_polling_active) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301338
1339 sitar_codec_pause_hs_polling(codec);
1340 /* Enable Mic Bias switch to VDDIO */
1341 sitar->cfilt_k_value = snd_soc_read(codec,
1342 sitar->mbhc_bias_regs.cfilt_val);
1343 cfilt_k_val = sitar_find_k_value(
1344 sitar->pdata->micbias.ldoh_v, 1800);
1345 snd_soc_update_bits(codec,
1346 sitar->mbhc_bias_regs.cfilt_val,
1347 0xFC, (cfilt_k_val << 2));
1348
1349 snd_soc_update_bits(codec,
1350 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1351 snd_soc_update_bits(codec,
1352 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1353 sitar_codec_start_hs_polling(codec);
1354
1355 sitar->mbhc_micbias_switched = true;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301356 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301357 __func__);
1358 }
1359 break;
1360
1361 case 0:
1362 if (sitar->mbhc_micbias_switched) {
1363 if (sitar->mbhc_polling_active) {
1364 sitar_codec_pause_hs_polling(codec);
1365 mbhc_was_polling = true;
1366 }
1367 /* Disable Mic Bias switch to VDDIO */
1368 if (sitar->cfilt_k_value != 0)
1369 snd_soc_update_bits(codec,
1370 sitar->mbhc_bias_regs.cfilt_val, 0XFC,
1371 sitar->cfilt_k_value);
1372 snd_soc_update_bits(codec,
1373 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1374 snd_soc_update_bits(codec,
1375 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1376
1377 if (mbhc_was_polling)
1378 sitar_codec_start_hs_polling(codec);
1379
1380 sitar->mbhc_micbias_switched = false;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301381 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301382 __func__);
1383 }
1384 break;
1385 }
1386}
1387
1388static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1389 struct snd_kcontrol *kcontrol, int event)
1390{
1391 struct snd_soc_codec *codec = w->codec;
1392 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1393 u16 micb_int_reg;
1394 int micb_line;
1395 u8 cfilt_sel_val = 0;
1396 char *internal1_text = "Internal1";
1397 char *internal2_text = "Internal2";
1398
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301399 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301400 switch (w->reg) {
1401 case SITAR_A_MICB_1_CTL:
1402 micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
1403 cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
1404 micb_line = SITAR_MICBIAS1;
1405 break;
1406 case SITAR_A_MICB_2_CTL:
1407 micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
1408 cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
1409 micb_line = SITAR_MICBIAS2;
1410 break;
1411 default:
1412 pr_err("%s: Error, invalid micbias register\n", __func__);
1413 return -EINVAL;
1414 }
1415
1416 switch (event) {
1417 case SND_SOC_DAPM_PRE_PMU:
1418 /* Decide whether to switch the micbias for MBHC */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001419 if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
1420 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301421 sitar_codec_switch_micbias(codec, 0);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001422 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1423 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301424
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001425 snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301426 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
1427
1428 if (strnstr(w->name, internal1_text, 30))
1429 snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
1430 else if (strnstr(w->name, internal2_text, 30))
1431 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1432 break;
1433 case SND_SOC_DAPM_POST_PMU:
1434 if (sitar->mbhc_polling_active &&
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001435 sitar->mbhc_cfg.micbias == micb_line) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001436 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301437 sitar_codec_pause_hs_polling(codec);
1438 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001439 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301440 }
1441 break;
1442 case SND_SOC_DAPM_POST_PMD:
1443
1444 if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
1445 && sitar_is_hph_pa_on(codec))
1446 sitar_codec_switch_micbias(codec, 1);
1447
1448 if (strnstr(w->name, internal1_text, 30))
1449 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1450 else if (strnstr(w->name, internal2_text, 30))
1451 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1452 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
1453 break;
1454 }
1455
1456 return 0;
1457}
1458
1459static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
1460 struct snd_kcontrol *kcontrol, int event)
1461{
1462 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001463 u16 dec_reset_reg, gain_reg;
1464 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301465
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301466 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301467
1468 if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1469 dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
1470 else {
1471 pr_err("%s: Error, incorrect dec\n", __func__);
1472 return -EINVAL;
1473 }
1474
1475 switch (event) {
1476 case SND_SOC_DAPM_PRE_PMU:
1477 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1478 1 << w->shift);
1479 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1480 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001481 case SND_SOC_DAPM_POST_PMU:
1482 /* Reprogram the digital gain after power up of Decimator */
1483 gain_reg = SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * w->shift);
1484 current_gain = snd_soc_read(codec, gain_reg);
1485 snd_soc_write(codec, gain_reg, current_gain);
1486 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301487 }
1488 return 0;
1489}
1490
1491static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
1492 struct snd_kcontrol *kcontrol, int event)
1493{
1494 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001495 u16 gain_reg;
1496 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301497
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301498 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301499
1500 switch (event) {
1501 case SND_SOC_DAPM_PRE_PMU:
1502 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1503 1 << w->shift, 1 << w->shift);
1504 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1505 1 << w->shift, 0x0);
1506 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001507 case SND_SOC_DAPM_POST_PMU:
1508 /* Reprogram gain after power up interpolator */
1509 gain_reg = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * w->shift);
1510 current_gain = snd_soc_read(codec, gain_reg);
1511 snd_soc_write(codec, gain_reg, current_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301512 }
1513 return 0;
1514}
1515
1516static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1517 struct snd_kcontrol *kcontrol, int event)
1518{
1519 switch (event) {
1520 case SND_SOC_DAPM_POST_PMU:
1521 case SND_SOC_DAPM_POST_PMD:
1522 usleep_range(1000, 1000);
1523 pr_debug("LDO_H\n");
1524 break;
1525 }
1526 return 0;
1527}
1528
1529static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1530{
1531 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1532
1533 if (enable) {
1534 sitar->rx_bias_count++;
1535 if (sitar->rx_bias_count == 1)
1536 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1537 0x80, 0x80);
1538 } else {
1539 sitar->rx_bias_count--;
1540 if (!sitar->rx_bias_count)
1541 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1542 0x80, 0x00);
1543 }
1544}
1545
1546static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1547 struct snd_kcontrol *kcontrol, int event)
1548{
1549 struct snd_soc_codec *codec = w->codec;
1550
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301551 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301552
1553 switch (event) {
1554 case SND_SOC_DAPM_PRE_PMU:
1555 sitar_enable_rx_bias(codec, 1);
1556 break;
1557 case SND_SOC_DAPM_POST_PMD:
1558 sitar_enable_rx_bias(codec, 0);
1559 break;
1560 }
1561 return 0;
1562}
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001563static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301564 struct snd_kcontrol *kcontrol, int event)
1565{
1566 struct snd_soc_codec *codec = w->codec;
1567
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301568 pr_debug("%s %s %d\n", __func__, w->name, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301569
1570 switch (event) {
1571 case SND_SOC_DAPM_PRE_PMU:
1572 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1573 break;
1574 case SND_SOC_DAPM_POST_PMD:
1575 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1576 break;
1577 }
1578 return 0;
1579}
1580
1581static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
1582 struct snd_soc_jack *jack, int status,
1583 int mask)
1584{
1585 /* XXX: wake_lock_timeout()? */
1586 snd_soc_jack_report(jack, status, mask);
1587}
1588
1589static void hphocp_off_report(struct sitar_priv *sitar,
1590 u32 jack_status, int irq)
1591{
1592 struct snd_soc_codec *codec;
1593
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001594 if (!sitar) {
1595 pr_err("%s: Bad sitar private data\n", __func__);
1596 return;
1597 }
1598
1599 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1600 codec = sitar->codec;
1601 if (sitar->hph_status & jack_status) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301602 sitar->hph_status &= ~jack_status;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001603 if (sitar->mbhc_cfg.headset_jack)
1604 sitar_snd_soc_jack_report(sitar,
1605 sitar->mbhc_cfg.headset_jack,
1606 sitar->hph_status,
1607 SITAR_JACK_MASK);
1608 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1609 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301610 /* reset retry counter as PA is turned off signifying
1611 * start of new OCP detection session
1612 */
1613 if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
1614 sitar->hphlocp_cnt = 0;
1615 else
1616 sitar->hphrocp_cnt = 0;
1617 wcd9xxx_enable_irq(codec->control_data, irq);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301618 }
1619}
1620
1621static void hphlocp_off_report(struct work_struct *work)
1622{
1623 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
1624 hphlocp_work);
1625 hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
1626}
1627
1628static void hphrocp_off_report(struct work_struct *work)
1629{
1630 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
1631 hphrocp_work);
1632 hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
1633}
1634
1635static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
1636 struct snd_kcontrol *kcontrol, int event)
1637{
1638 struct snd_soc_codec *codec = w->codec;
1639 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1640 u8 mbhc_micb_ctl_val;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301641 pr_debug("%s: event = %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301642
1643 switch (event) {
1644 case SND_SOC_DAPM_PRE_PMU:
1645 mbhc_micb_ctl_val = snd_soc_read(codec,
1646 sitar->mbhc_bias_regs.ctl_reg);
1647
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001648 if (!(mbhc_micb_ctl_val & 0x80)) {
1649 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301650 sitar_codec_switch_micbias(codec, 1);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001651 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1652 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301653
1654 break;
1655
1656 case SND_SOC_DAPM_POST_PMD:
1657 /* schedule work is required because at the time HPH PA DAPM
1658 * event callback is called by DAPM framework, CODEC dapm mutex
1659 * would have been locked while snd_soc_jack_report also
1660 * attempts to acquire same lock.
1661 */
1662 if (w->shift == 5) {
1663 clear_bit(SITAR_HPHL_PA_OFF_ACK,
1664 &sitar->hph_pa_dac_state);
1665 clear_bit(SITAR_HPHL_DAC_OFF_ACK,
1666 &sitar->hph_pa_dac_state);
1667 if (sitar->hph_status & SND_JACK_OC_HPHL)
1668 schedule_work(&sitar->hphlocp_work);
1669 } else if (w->shift == 4) {
1670 clear_bit(SITAR_HPHR_PA_OFF_ACK,
1671 &sitar->hph_pa_dac_state);
1672 clear_bit(SITAR_HPHR_DAC_OFF_ACK,
1673 &sitar->hph_pa_dac_state);
1674 if (sitar->hph_status & SND_JACK_OC_HPHR)
1675 schedule_work(&sitar->hphrocp_work);
1676 }
1677
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001678 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
1679 sitar_codec_switch_micbias(codec, 0);
1680 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301681
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301682 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301683 w->name);
1684 usleep_range(10000, 10000);
1685
1686 break;
1687 }
1688 return 0;
1689}
1690
1691static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
1692 struct mbhc_micbias_regs *micbias_regs)
1693{
1694 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301695 unsigned int cfilt;
1696
Patrick Laia5062da2012-05-11 17:55:09 -07001697 switch (sitar->mbhc_cfg.micbias) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301698 case SITAR_MICBIAS1:
1699 cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
1700 micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
1701 micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
1702 micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
1703 break;
1704 case SITAR_MICBIAS2:
1705 cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
1706 micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
1707 micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
1708 micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
1709 break;
1710 default:
1711 /* Should never reach here */
1712 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
1713 return;
1714 }
1715
1716 micbias_regs->cfilt_sel = cfilt;
1717
1718 switch (cfilt) {
1719 case SITAR_CFILT1_SEL:
1720 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
1721 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001722 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301723 break;
1724 case SITAR_CFILT2_SEL:
1725 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
1726 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001727 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301728 break;
1729 }
1730}
1731
1732static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
1733 struct snd_kcontrol *kcontrol, int event)
1734{
1735 struct snd_soc_codec *codec = w->codec;
1736
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301737 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301738 switch (event) {
1739 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07001740 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
1741 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301742 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
1743 0x01);
1744 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
1745 usleep_range(200, 200);
1746 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
1747 break;
1748 case SND_SOC_DAPM_PRE_PMD:
1749 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
1750 0x10);
1751 usleep_range(20, 20);
1752 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
1753 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
1754 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
1755 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
1756 0x00);
1757 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
1758 break;
1759 }
1760 return 0;
1761}
1762
1763static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
1764 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
1765 4, 0, NULL, 0),
1766 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
1767 0, NULL, 0),
1768};
1769
1770static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
1771 /*RX stuff */
1772 SND_SOC_DAPM_OUTPUT("EAR"),
1773
1774 SND_SOC_DAPM_PGA("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0),
1775 SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
1776 ARRAY_SIZE(dac1_switch)),
1777 SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
1778 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
1779 0, sitar_codec_enable_slimrx,
1780 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1781 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
1782 0, sitar_codec_enable_slimrx,
1783 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1784 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1785 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1786 SND_SOC_DAPM_AIF_IN("SLIM RX5", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1787
1788 /* Headphone */
1789 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
1790 SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
1791 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1792 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301793
1794 SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
1795 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1796 SND_SOC_DAPM_POST_PMD),
1797
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001798 SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
1799 sitar_hph_dac_event,
1800 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301801 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001802 sitar_hph_dac_event,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301803 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1804
1805 /* Speaker */
1806 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1807 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1808
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001809 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
1810 , sitar_lineout_dac_event,
1811 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1812 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
1813 , sitar_lineout_dac_event,
1814 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1815
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301816 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
1817 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1818 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1819 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
1820 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1821 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1822
1823 SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001824 0, sitar_codec_reset_interpolator,
1825 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301826 SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001827 0, sitar_codec_reset_interpolator,
1828 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301829 SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001830 0, sitar_codec_reset_interpolator,
1831 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301832
1833 SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
1834 &rx_dac1_mux),
1835 SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
1836 &rx_dac2_mux),
1837 SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
1838 &rx_dac3_mux),
1839 SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
1840 &rx_dac4_mux),
1841
1842 SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1843 SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1844 SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
1845
1846 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1847 &rx_mix1_inp1_mux),
1848 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1849 &rx_mix1_inp2_mux),
1850 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1851 &rx2_mix1_inp1_mux),
1852 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1853 &rx2_mix1_inp2_mux),
1854 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1855 &rx3_mix1_inp1_mux),
1856 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1857 &rx3_mix1_inp2_mux),
1858
1859 SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
1860 sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1861 SND_SOC_DAPM_PRE_PMD),
1862 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
1863 sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
1864 SND_SOC_DAPM_POST_PMD),
1865
1866 SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
1867 sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1868 /* TX */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001869
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301870 SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1871 0),
1872 SND_SOC_DAPM_INPUT("AMIC1"),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001873 SND_SOC_DAPM_INPUT("AMIC2"),
1874 SND_SOC_DAPM_INPUT("AMIC3"),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301875 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
1876 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1877 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1878 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
1879 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1880 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1881
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301882 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
1883 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1884 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1885 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
1886 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1887 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1888 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
1889 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1890 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1891
1892 SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
1893 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1894 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1895 SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
1896 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1897 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001898 SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
1899 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1900 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301901
1902 SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001903 &dec1_mux, sitar_codec_enable_dec,
1904 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001905 SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001906 &dec2_mux, sitar_codec_enable_dec,
1907 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001908 SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001909 &dec3_mux, sitar_codec_enable_dec,
1910 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001911 SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001912 &dec4_mux, sitar_codec_enable_dec,
1913 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301914
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001915 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1916 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1917
1918 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1919 sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1920 SND_SOC_DAPM_POST_PMD),
1921
1922 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1923
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301924 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1925 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
1926 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001927 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001928 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301929
1930 SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1931 0, sitar_codec_enable_slimtx,
1932 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1933
1934 SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1935 0, sitar_codec_enable_slimtx,
1936 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1937
1938 SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1939 0, sitar_codec_enable_slimtx,
1940 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001941 SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1942 0, sitar_codec_enable_slimtx,
1943 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301944
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001945 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1946 0, sitar_codec_enable_slimtx,
1947 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1948
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301949 /* Digital Mic Inputs */
1950 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
1951 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1952 SND_SOC_DAPM_POST_PMD),
1953 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
1954 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1955 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301956 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
1957 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1958 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301959 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
1960 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1961 SND_SOC_DAPM_POST_PMD),
1962
1963 /* Sidetone */
1964 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1965 SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301966 SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
1967 SND_SOC_DAPM_PGA("IIR2", SITAR_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301968
1969};
1970
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05301971static const struct snd_soc_dapm_route audio_i2s_map[] = {
1972 {"RX_I2S_CLK", NULL, "CP"},
1973 {"RX_I2S_CLK", NULL, "CDC_CONN"},
1974 {"SLIM RX1", NULL, "RX_I2S_CLK"},
1975 {"SLIM RX2", NULL, "RX_I2S_CLK"},
1976 {"SLIM RX3", NULL, "RX_I2S_CLK"},
1977 {"SLIM RX4", NULL, "RX_I2S_CLK"},
1978
1979 {"SLIM TX1", NULL, "TX_I2S_CLK"},
1980 {"SLIM TX2", NULL, "TX_I2S_CLK"},
1981 {"SLIM TX3", NULL, "TX_I2S_CLK"},
1982 {"SLIM TX4", NULL, "TX_I2S_CLK"},
1983};
1984
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301985static const struct snd_soc_dapm_route audio_map[] = {
1986 /* Earpiece (RX MIX1) */
1987 {"EAR", NULL, "EAR PA"},
1988 {"EAR PA", "NULL", "DAC1"},
1989 {"DAC1", "Switch", "DAC1 MUX"},
1990 {"DAC1", NULL, "CP"},
1991 {"DAC1", NULL, "EAR DRIVER"},
1992
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001993 {"CP", NULL, "RX_BIAS"},
1994
1995 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
1996 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301997
1998 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07001999 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002000 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2001 {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302002
2003 {"LINEOUT1", NULL, "LINEOUT1 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002004 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002005 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2006 {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
2007
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002008 {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
2009 {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
2010 {"ANC", NULL, "ANC1 FB MUX"},
2011
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302012
2013 /* Headset (RX MIX1 and RX MIX2) */
2014 {"HEADPHONE", NULL, "HPHL"},
2015 {"HEADPHONE", NULL, "HPHR"},
2016
Patrick Lai9b250b72012-05-24 14:45:57 -07002017 {"HPHL DAC", NULL, "CP"},
2018 {"HPHR DAC", NULL, "CP"},
2019
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302020 {"HPHL", NULL, "HPHL DAC"},
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002021 {"HPHL DAC", "NULL", "DAC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302022 {"HPHR", NULL, "HPHR DAC"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002023 {"HPHR DAC", NULL, "RX3 MIX1"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302024
2025 {"DAC1 MUX", "RX1", "RX1 CHAIN"},
2026 {"DAC2 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002027
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302028 {"DAC3 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002029 {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302030 {"DAC3 MUX", "RX2", "RX2 MIX1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002031
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302032 {"DAC4 MUX", "ON", "RX2 MIX1"},
2033
2034 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2035
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302036 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2037 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2038 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2039 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2040 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2041 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2042
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002043 /* ANC */
2044 {"ANC", NULL, "ANC1 MUX"},
2045 {"ANC", NULL, "ANC2 MUX"},
2046 {"ANC1 MUX", "ADC1", "ADC1"},
2047 {"ANC1 MUX", "ADC2", "ADC2"},
2048 {"ANC1 MUX", "ADC3", "ADC3"},
2049 {"ANC2 MUX", "ADC1", "ADC1"},
2050 {"ANC2 MUX", "ADC2", "ADC2"},
2051 {"ANC2 MUX", "ADC3", "ADC3"},
2052
2053 {"ANC", NULL, "CDC_CONN"},
2054
2055 {"RX2 MIX1", NULL, "ANC"},
2056 {"RX3 MIX1", NULL, "ANC"},
2057
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302058 /* SLIMBUS Connections */
2059
2060 /* Slimbus port 5 is non functional in Sitar 1.0 */
2061 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2062 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2063 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2064 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2065 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302066 {"RX1 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302067 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2068 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2069 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2070 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2071 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302072 {"RX1 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302073 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2074 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2075 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2076 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2077 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302078 {"RX2 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302079 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2080 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2081 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2082 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2083 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302084 {"RX2 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302085 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2086 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2087 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2088 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2089 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302090 {"RX3 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302091 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2092 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2093 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2094 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2095 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302096 {"RX3 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302097
2098
2099 /* TX */
2100 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302101 {"SLIM TX2", NULL, "SLIM TX2 MUX"},
2102 {"SLIM TX3", NULL, "SLIM TX3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002103 {"SLIM TX4", NULL, "SLIM TX4 MUX"},
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002104 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302105
2106 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2107 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
2108 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002109 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002110 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
2111 {"SLIM TX5 MUX", "DEC2", "DEC2 MUX"},
2112 {"SLIM TX5 MUX", "DEC3", "DEC3 MUX"},
2113 {"SLIM TX5 MUX", "DEC4", "DEC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302114
2115 /* Decimator Inputs */
2116 {"DEC1 MUX", "DMIC1", "DMIC1"},
2117 {"DEC1 MUX", "DMIC4", "DMIC4"},
2118 {"DEC1 MUX", "ADC1", "ADC1"},
2119 {"DEC1 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002120 {"DEC1 MUX", "ADC3", "ADC3"},
2121 {"DEC1 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302122 {"DEC2 MUX", "DMIC2", "DMIC2"},
2123 {"DEC2 MUX", "DMIC3", "DMIC3"},
2124 {"DEC2 MUX", "ADC1", "ADC1"},
2125 {"DEC2 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002126 {"DEC2 MUX", "ADC3", "ADC3"},
2127 {"DEC2 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302128 {"DEC3 MUX", "DMIC3", "DMIC3"},
2129 {"DEC3 MUX", "ADC1", "ADC1"},
2130 {"DEC3 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002131 {"DEC3 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302132 {"DEC3 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07002133 {"DEC3 MUX", "DMIC4", "DMIC4"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002134 {"DEC3 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302135 {"DEC4 MUX", "DMIC4", "DMIC4"},
2136 {"DEC4 MUX", "ADC1", "ADC1"},
2137 {"DEC4 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002138 {"DEC4 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302139 {"DEC4 MUX", "DMIC3", "DMIC3"},
2140 {"DEC4 MUX", "DMIC2", "DMIC2"},
2141 {"DEC4 MUX", "DMIC1", "DMIC1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002142 {"DEC4 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302143
2144 /* ADC Connections */
2145 {"ADC1", NULL, "AMIC1"},
2146 {"ADC2", NULL, "AMIC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002147 {"ADC3", NULL, "AMIC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302148
2149 /* IIR */
2150 {"IIR1", NULL, "IIR1 INP1 MUX"},
2151 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302152 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2153 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2154 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2155 {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
2156 {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
2157 {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
2158 {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
2159 {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
2160
2161 {"IIR2", NULL, "IIR2 INP1 MUX"},
2162 {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
2163 {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
2164 {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
2165 {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
2166 {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
2167 {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
2168 {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
2169 {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
2170 {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
2171
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302172 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2173 {"MIC BIAS1 External", NULL, "LDO_H"},
2174 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2175 {"MIC BIAS2 External", NULL, "LDO_H"},
2176};
2177
2178static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
2179{
2180 return sitar_reg_readable[reg];
2181}
2182
2183static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2184{
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002185 int i;
2186
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302187 /* Registers lower than 0x100 are top level registers which can be
2188 * written by the Sitar core driver.
2189 */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302190 if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2191 return 1;
2192
2193 /* IIR Coeff registers are not cacheable */
2194 if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
2195 (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
2196 return 1;
2197
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002198 for (i = 0; i < NUM_DECIMATORS; i++) {
2199 if (reg == SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * i))
2200 return 1;
2201 }
2202
2203 for (i = 0; i < NUM_INTERPOLATORS; i++) {
2204 if (reg == SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * i))
2205 return 1;
2206 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302207 return 0;
2208}
2209
2210#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2211static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
2212 unsigned int value)
2213{
2214 int ret;
2215
2216 BUG_ON(reg > SITAR_MAX_REGISTER);
2217
2218 if (!sitar_volatile(codec, reg)) {
2219 ret = snd_soc_cache_write(codec, reg, value);
2220 if (ret != 0)
2221 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2222 reg, ret);
2223 }
2224
2225 return wcd9xxx_reg_write(codec->control_data, reg, value);
2226}
2227static unsigned int sitar_read(struct snd_soc_codec *codec,
2228 unsigned int reg)
2229{
2230 unsigned int val;
2231 int ret;
2232
2233 BUG_ON(reg > SITAR_MAX_REGISTER);
2234
2235 if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
2236 reg < codec->driver->reg_cache_size) {
2237 ret = snd_soc_cache_read(codec, reg, &val);
2238 if (ret >= 0) {
2239 return val;
2240 } else
2241 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2242 reg, ret);
2243 }
2244
2245 val = wcd9xxx_reg_read(codec->control_data, reg);
2246 return val;
2247}
2248
2249static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2250{
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002251 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302252
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002253 if (SITAR_IS_1P0(sitar_core->version))
2254 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
2255
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002256 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302257 usleep_range(1000, 1000);
2258 snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
2259 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2260 0x80);
2261 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
2262 0x04);
2263 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
2264 0x01);
2265 usleep_range(1000, 1000);
2266 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2267 0x00);
2268}
2269
2270static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
2271 enum sitar_bandgap_type choice)
2272{
2273 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002274 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302275
2276 /* TODO lock resources accessed by audio streams and threaded
2277 * interrupt handlers
2278 */
2279
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302280 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302281 sitar->bandgap_type);
2282
2283 if (sitar->bandgap_type == choice)
2284 return;
2285
2286 if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
2287 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2288 sitar_codec_enable_audio_mode_bandgap(codec);
2289 } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
Bhalchandra Gajare7708ee32012-05-24 17:37:37 -07002290 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302291 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
2292 0x2);
2293 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2294 0x80);
2295 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
2296 0x4);
2297 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
2298 0x1);
2299 usleep_range(1000, 1000);
2300 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2301 0x00);
2302 } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
2303 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2304 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
2305 usleep_range(100, 100);
2306 sitar_codec_enable_audio_mode_bandgap(codec);
2307 } else if (choice == SITAR_BANDGAP_OFF) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002308 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302309 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002310 if (SITAR_IS_1P0(sitar_core->version))
2311 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
2312 0xFF, 0x65);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002313 usleep_range(1000, 1000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302314 } else {
2315 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2316 }
2317 sitar->bandgap_type = choice;
2318}
2319
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002320static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
2321 int enable)
2322{
2323 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2324
2325 if (enable) {
2326 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
2327 snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
2328 usleep_range(5, 5);
2329 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
2330 0x80);
2331 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
2332 0x80);
2333 usleep_range(10, 10);
2334 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
2335 usleep_range(20, 20);
2336 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
2337 } else {
2338 snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
2339 0);
2340 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
2341 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2342 }
2343 sitar->config_mode_active = enable ? true : false;
2344
2345 return 0;
2346}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302347
2348static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
2349 int config_mode)
2350{
2351 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2352
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302353 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302354
2355 if (config_mode) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002356 sitar_codec_enable_config_mode(codec, 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302357 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
2358 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2359 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
2360 usleep_range(1000, 1000);
2361 } else
2362 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2363
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002364 if (!config_mode && sitar->mbhc_polling_active) {
2365 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2366 sitar_codec_enable_config_mode(codec, 0);
2367
2368 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302369
2370 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
2371 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
2372 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302373 usleep_range(50, 50);
2374 sitar->clock_active = true;
2375 return 0;
2376}
2377static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
2378{
2379 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302380 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302381 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
2382 ndelay(160);
2383 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
2384 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
2385 sitar->clock_active = false;
2386}
2387
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002388static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
2389{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002390 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002391 return 0;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002392 else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002393 return 1;
2394 else {
2395 BUG_ON(1);
2396 return -EINVAL;
2397 }
2398}
2399
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302400static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2401{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002402 u8 *n_ready, *n_cic;
2403 struct sitar_mbhc_btn_detect_cfg *btn_det;
2404 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302405
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002406 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302407
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002408 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
2409 sitar->mbhc_data.v_ins_hu & 0xFF);
2410 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
2411 (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302412
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002413 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
2414 sitar->mbhc_data.v_b1_hu & 0xFF);
2415 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
2416 (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
2417
2418 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
2419 sitar->mbhc_data.v_b1_h & 0xFF);
2420 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
2421 (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
2422
2423 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
2424 sitar->mbhc_data.v_brh & 0xFF);
2425 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
2426 (sitar->mbhc_data.v_brh >> 8) & 0xFF);
2427
2428 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
2429 sitar->mbhc_data.v_brl & 0xFF);
2430 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
2431 (sitar->mbhc_data.v_brl >> 8) & 0xFF);
2432
2433 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
2434 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
2435 n_ready[sitar_codec_mclk_index(sitar)]);
2436 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
2437 sitar->mbhc_data.npoll);
2438 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
2439 sitar->mbhc_data.nbounce_wait);
2440 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
2441 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
2442 n_cic[sitar_codec_mclk_index(sitar)]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302443}
2444
2445static int sitar_startup(struct snd_pcm_substream *substream,
2446 struct snd_soc_dai *dai)
2447{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08002448 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
2449 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
2450 (wcd9xxx->dev->parent != NULL))
2451 pm_runtime_get_sync(wcd9xxx->dev->parent);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302452 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302453 substream->name, substream->stream);
2454
2455 return 0;
2456}
2457
2458static void sitar_shutdown(struct snd_pcm_substream *substream,
2459 struct snd_soc_dai *dai)
2460{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08002461 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
2462 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
2463 (wcd9xxx->dev->parent != NULL)) {
2464 pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
2465 pm_runtime_put(wcd9xxx->dev->parent);
2466 }
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302467 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302468 substream->name, substream->stream);
2469}
2470
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002471int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302472{
2473 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2474
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302475 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302476
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002477 if (dapm)
2478 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302479 if (mclk_enable) {
2480 sitar->mclk_enabled = true;
2481
2482 if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
2483 sitar_codec_pause_hs_polling(codec);
2484 sitar_codec_enable_bandgap(codec,
2485 SITAR_BANDGAP_AUDIO_MODE);
2486 sitar_codec_enable_clock_block(codec, 0);
2487 sitar_codec_calibrate_hs_polling(codec);
2488 sitar_codec_start_hs_polling(codec);
2489 } else {
2490 sitar_codec_enable_bandgap(codec,
2491 SITAR_BANDGAP_AUDIO_MODE);
2492 sitar_codec_enable_clock_block(codec, 0);
2493 }
2494 } else {
2495
2496 if (!sitar->mclk_enabled) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002497 if (dapm)
2498 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302499 pr_err("Error, MCLK already diabled\n");
2500 return -EINVAL;
2501 }
2502 sitar->mclk_enabled = false;
2503
2504 if (sitar->mbhc_polling_active) {
2505 if (!sitar->mclk_enabled) {
2506 sitar_codec_pause_hs_polling(codec);
2507 sitar_codec_enable_bandgap(codec,
2508 SITAR_BANDGAP_MBHC_MODE);
2509 sitar_enable_rx_bias(codec, 1);
2510 sitar_codec_enable_clock_block(codec, 1);
2511 sitar_codec_calibrate_hs_polling(codec);
2512 sitar_codec_start_hs_polling(codec);
2513 }
2514 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
2515 0x05, 0x01);
2516 } else {
2517 sitar_codec_disable_clock_block(codec);
2518 sitar_codec_enable_bandgap(codec,
2519 SITAR_BANDGAP_OFF);
2520 }
2521 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002522 if (dapm)
2523 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302524 return 0;
2525}
2526
2527static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
2528 int clk_id, unsigned int freq, int dir)
2529{
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302530 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302531 return 0;
2532}
2533
2534static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2535{
2536 u8 val = 0;
2537 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2538
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302539 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302540 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2541 case SND_SOC_DAIFMT_CBS_CFS:
2542 /* CPU is master */
2543 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2544 if (dai->id == AIF1_CAP)
2545 snd_soc_update_bits(dai->codec,
2546 SITAR_A_CDC_CLK_TX_I2S_CTL,
2547 SITAR_I2S_MASTER_MODE_MASK, 0);
2548 else if (dai->id == AIF1_PB)
2549 snd_soc_update_bits(dai->codec,
2550 SITAR_A_CDC_CLK_RX_I2S_CTL,
2551 SITAR_I2S_MASTER_MODE_MASK, 0);
2552 }
2553 break;
2554 case SND_SOC_DAIFMT_CBM_CFM:
2555 /* CPU is slave */
2556 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2557 val = SITAR_I2S_MASTER_MODE_MASK;
2558 if (dai->id == AIF1_CAP)
2559 snd_soc_update_bits(dai->codec,
2560 SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
2561 else if (dai->id == AIF1_PB)
2562 snd_soc_update_bits(dai->codec,
2563 SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
2564 }
2565 break;
2566 default:
2567 return -EINVAL;
2568 }
2569 return 0;
2570}
2571static int sitar_set_channel_map(struct snd_soc_dai *dai,
2572 unsigned int tx_num, unsigned int *tx_slot,
2573 unsigned int rx_num, unsigned int *rx_slot)
2574
2575{
2576 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2577 u32 i = 0;
2578 if (!tx_slot && !rx_slot) {
2579 pr_err("%s: Invalid\n", __func__);
2580 return -EINVAL;
2581 }
2582 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
2583
2584 if (dai->id == AIF1_PB) {
2585 for (i = 0; i < rx_num; i++) {
2586 sitar->dai[dai->id - 1].ch_num[i] = rx_slot[i];
2587 sitar->dai[dai->id - 1].ch_act = 0;
2588 sitar->dai[dai->id - 1].ch_tot = rx_num;
2589 }
2590 } else if (dai->id == AIF1_CAP) {
2591 for (i = 0; i < tx_num; i++) {
2592 sitar->dai[dai->id - 1].ch_num[i] = tx_slot[i];
2593 sitar->dai[dai->id - 1].ch_act = 0;
2594 sitar->dai[dai->id - 1].ch_tot = tx_num;
2595 }
2596 }
2597 return 0;
2598}
2599
2600static int sitar_get_channel_map(struct snd_soc_dai *dai,
2601 unsigned int *tx_num, unsigned int *tx_slot,
2602 unsigned int *rx_num, unsigned int *rx_slot)
2603
2604{
2605 struct wcd9xxx *sitar = dev_get_drvdata(dai->codec->control_data);
2606
2607 u32 cnt = 0;
2608 u32 tx_ch[SLIM_MAX_TX_PORTS];
2609 u32 rx_ch[SLIM_MAX_RX_PORTS];
2610
2611 if (!rx_slot && !tx_slot) {
2612 pr_err("%s: Invalid\n", __func__);
2613 return -EINVAL;
2614 }
2615 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
2616 /* for virtual port, codec driver needs to do
2617 * housekeeping, for now should be ok
2618 */
2619 wcd9xxx_get_channel(sitar, rx_ch, tx_ch);
2620 if (dai->id == AIF1_PB) {
2621 *rx_num = sitar_dai[dai->id - 1].playback.channels_max;
2622 while (cnt < *rx_num) {
2623 rx_slot[cnt] = rx_ch[cnt];
2624 cnt++;
2625 }
2626 } else if (dai->id == AIF1_CAP) {
2627 *tx_num = sitar_dai[dai->id - 1].capture.channels_max;
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002628 tx_slot[0] = tx_ch[cnt];
2629 tx_slot[1] = tx_ch[4 + cnt];
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07002630 tx_slot[2] = tx_ch[2 + cnt];
2631 tx_slot[3] = tx_ch[3 + cnt];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302632 }
2633 return 0;
2634}
2635
2636static int sitar_hw_params(struct snd_pcm_substream *substream,
2637 struct snd_pcm_hw_params *params,
2638 struct snd_soc_dai *dai)
2639{
2640 struct snd_soc_codec *codec = dai->codec;
2641 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2642 u8 path, shift;
2643 u16 tx_fs_reg, rx_fs_reg;
2644 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2645
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302646 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302647
2648 switch (params_rate(params)) {
2649 case 8000:
2650 tx_fs_rate = 0x00;
2651 rx_fs_rate = 0x00;
2652 break;
2653 case 16000:
2654 tx_fs_rate = 0x01;
2655 rx_fs_rate = 0x20;
2656 break;
2657 case 32000:
2658 tx_fs_rate = 0x02;
2659 rx_fs_rate = 0x40;
2660 break;
2661 case 48000:
2662 tx_fs_rate = 0x03;
2663 rx_fs_rate = 0x60;
2664 break;
2665 default:
2666 pr_err("%s: Invalid sampling rate %d\n", __func__,
2667 params_rate(params));
2668 return -EINVAL;
2669 }
2670
2671
2672 /**
2673 * If current dai is a tx dai, set sample rate to
2674 * all the txfe paths that are currently not active
2675 */
2676 if (dai->id == AIF1_CAP) {
2677
2678 tx_state = snd_soc_read(codec,
2679 SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2680
2681 for (path = 1, shift = 0;
2682 path <= NUM_DECIMATORS; path++, shift++) {
2683
2684 if (!(tx_state & (1 << shift))) {
2685 tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
2686 + (BITS_PER_REG*(path-1));
2687 snd_soc_update_bits(codec, tx_fs_reg,
2688 0x03, tx_fs_rate);
2689 }
2690 }
2691 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2692 switch (params_format(params)) {
2693 case SNDRV_PCM_FORMAT_S16_LE:
2694 snd_soc_update_bits(codec,
2695 SITAR_A_CDC_CLK_TX_I2S_CTL,
2696 0x20, 0x20);
2697 break;
2698 case SNDRV_PCM_FORMAT_S32_LE:
2699 snd_soc_update_bits(codec,
2700 SITAR_A_CDC_CLK_TX_I2S_CTL,
2701 0x20, 0x00);
2702 break;
2703 default:
2704 pr_err("invalid format\n");
2705 break;
2706 }
2707 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
2708 0x03, tx_fs_rate);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302709 } else {
2710 sitar->dai[dai->id - 1].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302711 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302712 }
2713
2714 /**
2715 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2716 * with varying sample rates
2717 */
2718
2719 /**
2720 * If current dai is a rx dai, set sample rate to
2721 * all the rx paths that are currently not active
2722 */
2723 if (dai->id == AIF1_PB) {
2724
2725 rx_state = snd_soc_read(codec,
2726 SITAR_A_CDC_CLK_RX_B1_CTL);
2727
2728 for (path = 1, shift = 0;
2729 path <= NUM_INTERPOLATORS; path++, shift++) {
2730
2731 if (!(rx_state & (1 << shift))) {
2732 rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
2733 + (BITS_PER_REG*(path-1));
2734 snd_soc_update_bits(codec, rx_fs_reg,
2735 0xE0, rx_fs_rate);
2736 }
2737 }
2738 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2739 switch (params_format(params)) {
2740 case SNDRV_PCM_FORMAT_S16_LE:
2741 snd_soc_update_bits(codec,
2742 SITAR_A_CDC_CLK_RX_I2S_CTL,
2743 0x20, 0x20);
2744 break;
2745 case SNDRV_PCM_FORMAT_S32_LE:
2746 snd_soc_update_bits(codec,
2747 SITAR_A_CDC_CLK_RX_I2S_CTL,
2748 0x20, 0x00);
2749 break;
2750 default:
2751 pr_err("invalid format\n");
2752 break;
2753 }
2754 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
2755 0x03, (rx_fs_rate >> 0x05));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302756 } else {
2757 sitar->dai[dai->id - 1].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302758 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302759 }
2760
2761 return 0;
2762}
2763
2764static struct snd_soc_dai_ops sitar_dai_ops = {
2765 .startup = sitar_startup,
2766 .shutdown = sitar_shutdown,
2767 .hw_params = sitar_hw_params,
2768 .set_sysclk = sitar_set_dai_sysclk,
2769 .set_fmt = sitar_set_dai_fmt,
2770 .set_channel_map = sitar_set_channel_map,
2771 .get_channel_map = sitar_get_channel_map,
2772};
2773
2774static struct snd_soc_dai_driver sitar_dai[] = {
2775 {
2776 .name = "sitar_rx1",
2777 .id = AIF1_PB,
2778 .playback = {
2779 .stream_name = "AIF1 Playback",
2780 .rates = WCD9304_RATES,
2781 .formats = SITAR_FORMATS,
2782 .rate_max = 48000,
2783 .rate_min = 8000,
2784 .channels_min = 1,
2785 .channels_max = 2,
2786 },
2787 .ops = &sitar_dai_ops,
2788 },
2789 {
2790 .name = "sitar_tx1",
2791 .id = AIF1_CAP,
2792 .capture = {
2793 .stream_name = "AIF1 Capture",
2794 .rates = WCD9304_RATES,
2795 .formats = SITAR_FORMATS,
2796 .rate_max = 48000,
2797 .rate_min = 8000,
2798 .channels_min = 1,
2799 .channels_max = 2,
2800 },
2801 .ops = &sitar_dai_ops,
2802 },
2803};
2804
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302805static struct snd_soc_dai_driver sitar_i2s_dai[] = {
2806 {
2807 .name = "sitar_i2s_rx1",
2808 .id = AIF1_PB,
2809 .playback = {
2810 .stream_name = "AIF1 Playback",
2811 .rates = WCD9304_RATES,
2812 .formats = SITAR_FORMATS,
2813 .rate_max = 192000,
2814 .rate_min = 8000,
2815 .channels_min = 1,
2816 .channels_max = 4,
2817 },
2818 .ops = &sitar_dai_ops,
2819 },
2820 {
2821 .name = "sitar_i2s_tx1",
2822 .id = AIF1_CAP,
2823 .capture = {
2824 .stream_name = "AIF1 Capture",
2825 .rates = WCD9304_RATES,
2826 .formats = SITAR_FORMATS,
2827 .rate_max = 192000,
2828 .rate_min = 8000,
2829 .channels_min = 1,
2830 .channels_max = 4,
2831 },
2832 .ops = &sitar_dai_ops,
2833 },
2834};
2835
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302836static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
2837 struct snd_kcontrol *kcontrol, int event)
2838{
2839 struct wcd9xxx *sitar;
2840 struct snd_soc_codec *codec = w->codec;
2841 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
2842 u32 j = 0;
2843 codec->control_data = dev_get_drvdata(codec->dev->parent);
2844 sitar = codec->control_data;
2845 /* Execute the callback only if interface type is slimbus */
2846 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2847 return 0;
2848 switch (event) {
2849 case SND_SOC_DAPM_POST_PMU:
2850 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2851 if (sitar_dai[j].id == AIF1_CAP)
2852 continue;
2853 if (!strncmp(w->sname,
2854 sitar_dai[j].playback.stream_name, 13)) {
2855 ++sitar_p->dai[j].ch_act;
2856 break;
2857 }
2858 }
2859 if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
2860 wcd9xxx_cfg_slim_sch_rx(sitar,
2861 sitar_p->dai[j].ch_num,
2862 sitar_p->dai[j].ch_tot,
2863 sitar_p->dai[j].rate);
2864 break;
2865 case SND_SOC_DAPM_POST_PMD:
2866 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2867 if (sitar_dai[j].id == AIF1_CAP)
2868 continue;
2869 if (!strncmp(w->sname,
2870 sitar_dai[j].playback.stream_name, 13)) {
2871 --sitar_p->dai[j].ch_act;
2872 break;
2873 }
2874 }
2875 if (!sitar_p->dai[j].ch_act) {
2876 wcd9xxx_close_slim_sch_rx(sitar,
2877 sitar_p->dai[j].ch_num,
2878 sitar_p->dai[j].ch_tot);
Bhalchandra Gajare1ff24fd2012-03-30 11:24:47 -07002879 /* Wait for remove channel to complete
2880 * before derouting Rx path
2881 */
2882 usleep_range(15000, 15000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302883 sitar_p->dai[j].rate = 0;
2884 memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
2885 sitar_p->dai[j].ch_tot));
2886 sitar_p->dai[j].ch_tot = 0;
2887 }
2888 }
2889 return 0;
2890}
2891
2892static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
2893 struct snd_kcontrol *kcontrol, int event)
2894{
2895 struct wcd9xxx *sitar;
2896 struct snd_soc_codec *codec = w->codec;
2897 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
2898 /* index to the DAI ID, for now hardcoding */
2899 u32 j = 0;
2900
2901 codec->control_data = dev_get_drvdata(codec->dev->parent);
2902 sitar = codec->control_data;
2903
2904 /* Execute the callback only if interface type is slimbus */
2905 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2906 return 0;
2907 switch (event) {
2908 case SND_SOC_DAPM_POST_PMU:
2909 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2910 if (sitar_dai[j].id == AIF1_PB)
2911 continue;
2912 if (!strncmp(w->sname,
2913 sitar_dai[j].capture.stream_name, 13)) {
2914 ++sitar_p->dai[j].ch_act;
2915 break;
2916 }
2917 }
2918 if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
2919 wcd9xxx_cfg_slim_sch_tx(sitar,
2920 sitar_p->dai[j].ch_num,
2921 sitar_p->dai[j].ch_tot,
2922 sitar_p->dai[j].rate);
2923 break;
2924 case SND_SOC_DAPM_POST_PMD:
2925 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2926 if (sitar_dai[j].id == AIF1_PB)
2927 continue;
2928 if (!strncmp(w->sname,
2929 sitar_dai[j].capture.stream_name, 13)) {
2930 --sitar_p->dai[j].ch_act;
2931 break;
2932 }
2933 }
2934 if (!sitar_p->dai[j].ch_act) {
2935 wcd9xxx_close_slim_sch_tx(sitar,
2936 sitar_p->dai[j].ch_num,
2937 sitar_p->dai[j].ch_tot);
2938 sitar_p->dai[j].rate = 0;
2939 memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
2940 sitar_p->dai[j].ch_tot));
2941 sitar_p->dai[j].ch_tot = 0;
2942 }
2943 }
2944 return 0;
2945}
2946
2947
2948static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
2949{
2950 u8 bias_msb, bias_lsb;
2951 short bias_value;
2952
2953 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
2954 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
2955 bias_value = (bias_msb << 8) | bias_lsb;
2956 return bias_value;
2957}
2958
2959static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
2960{
2961 u8 bias_msb, bias_lsb;
2962 short bias_value;
2963
2964 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
2965 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
2966 bias_value = (bias_msb << 8) | bias_lsb;
2967 return bias_value;
2968}
2969
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002970static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
2971 bool on)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302972{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002973 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
2974}
2975
2976static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
2977 bool override_bypass, bool noreldetection)
2978{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302979 short bias_value;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002980 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2981
2982 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
2983 if (noreldetection)
2984 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302985
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002986 /* Turn on the override */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002987 if (!override_bypass)
2988 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302989 if (dce) {
2990 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2991 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
2992 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002993 usleep_range(sitar->mbhc_data.t_sta_dce,
2994 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302995 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002996 usleep_range(sitar->mbhc_data.t_dce,
2997 sitar->mbhc_data.t_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302998 bias_value = sitar_codec_read_dce_result(codec);
2999 } else {
3000 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3001 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
3002 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003003 usleep_range(sitar->mbhc_data.t_sta_dce,
3004 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303005 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003006 usleep_range(sitar->mbhc_data.t_sta,
3007 sitar->mbhc_data.t_sta);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303008 bias_value = sitar_codec_read_sta_result(codec);
3009 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3010 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
3011 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003012 /* Turn off the override after measuring mic voltage */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003013 if (!override_bypass)
3014 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3015
3016 if (noreldetection)
3017 sitar_turn_onoff_rel_detection(codec, true);
3018 wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303019
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303020 return bias_value;
3021}
3022
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003023static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3024 bool norel)
3025{
3026 return __sitar_codec_sta_dce(codec, dce, false, norel);
3027}
3028
3029static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3030{
3031 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3032 const struct sitar_mbhc_general_cfg *generic =
3033 SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3034
3035 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
3036 sitar_codec_enable_config_mode(codec, 1);
3037
3038 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3039 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
3040
3041 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
3042
3043 usleep_range(generic->t_shutdown_plug_rem,
3044 generic->t_shutdown_plug_rem);
3045
3046 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
3047 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
3048 sitar_codec_enable_config_mode(codec, 0);
3049
3050 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
3051}
3052
3053static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
3054{
3055 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3056
3057 sitar_codec_shutdown_hs_removal_detect(codec);
3058
3059 if (!sitar->mclk_enabled) {
3060 sitar_codec_disable_clock_block(codec);
3061 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
3062 }
3063
3064 sitar->mbhc_polling_active = false;
3065 sitar->mbhc_state = MBHC_STATE_NONE;
3066}
3067
3068/* called only from interrupt which is under codec_resource_lock acquisition */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303069static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
3070{
3071 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303072 short bias_value;
3073 u8 cfilt_mode;
3074
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003075 if (!sitar->mbhc_cfg.calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303076 pr_err("Error, no sitar calibration\n");
3077 return -ENODEV;
3078 }
3079
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303080 if (!sitar->mclk_enabled) {
3081 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
3082 sitar_enable_rx_bias(codec, 1);
3083 sitar_codec_enable_clock_block(codec, 1);
3084 }
3085
3086 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
3087
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303088 /* Make sure CFILT is in fast mode, save current mode */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003089 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
3090 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
3091
3092 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303093
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303094 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3095 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
3096
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003097 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
3098 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
3099 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
3100
3101 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303102 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3103 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
3104
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003105 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303106 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3107
3108 sitar_codec_calibrate_hs_polling(codec);
3109
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003110 /* don't flip override */
3111 bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003112 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
3113 cfilt_mode);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303114 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
3115
3116 return bias_value;
3117}
3118
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003119static int sitar_cancel_btn_work(struct sitar_priv *sitar)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303120{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003121 int r = 0;
3122 struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303123
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003124 if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
3125 /* if scheduled mbhc_btn_dwork is canceled from here,
3126 * we have to unlock from here instead btn_work */
3127 wcd9xxx_unlock_sleep(core);
3128 r = 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303129 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003130 return r;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303131}
3132
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003133
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003134static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3135 s16 vin_mv)
3136{
3137 short diff, zero;
3138 struct sitar_priv *sitar;
3139 u32 mb_mv, in;
3140
3141 sitar = snd_soc_codec_get_drvdata(codec);
3142 mb_mv = sitar->mbhc_data.micb_mv;
3143
3144 if (mb_mv == 0) {
3145 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3146 return -EINVAL;
3147 }
3148
3149 if (dce) {
3150 diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
3151 zero = sitar->mbhc_data.dce_z;
3152 } else {
3153 diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
3154 zero = sitar->mbhc_data.sta_z;
3155 }
3156 in = (u32) diff * vin_mv;
3157
3158 return (u16) (in / mb_mv) + zero;
3159}
3160
3161static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3162 u16 bias_value)
3163{
3164 struct sitar_priv *sitar;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003165 s16 value, z, mb;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003166 s32 mv;
3167
3168 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003169 value = bias_value;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003170
3171 if (dce) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003172 z = (sitar->mbhc_data.dce_z);
3173 mb = (sitar->mbhc_data.dce_mb);
3174 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003175 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003176 z = (sitar->mbhc_data.sta_z);
3177 mb = (sitar->mbhc_data.sta_mb);
3178 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003179 }
3180
3181 return mv;
3182}
3183
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003184static void btn_lpress_fn(struct work_struct *work)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303185{
3186 struct delayed_work *delayed_work;
3187 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003188 short bias_value;
3189 int dce_mv, sta_mv;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003190 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303191
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003192 pr_debug("%s:\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303193
3194 delayed_work = to_delayed_work(work);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003195 sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003196 core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303197
3198 if (sitar) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003199 if (sitar->mbhc_cfg.button_jack) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003200 bias_value = sitar_codec_read_sta_result(sitar->codec);
3201 sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003202 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003203 bias_value = sitar_codec_read_dce_result(sitar->codec);
3204 dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003205 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003206 pr_debug("%s: Reporting long button press event"
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003207 " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
3208 sitar_snd_soc_jack_report(sitar,
3209 sitar->mbhc_cfg.button_jack,
3210 sitar->buttons_pressed,
3211 sitar->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303212 }
3213 } else {
3214 pr_err("%s: Bad sitar private data\n", __func__);
3215 }
3216
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003217 pr_debug("%s: leave\n", __func__);
3218 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303219}
3220
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003221
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003222void sitar_mbhc_cal(struct snd_soc_codec *codec)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303223{
3224 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003225 struct sitar_mbhc_btn_detect_cfg *btn_det;
3226 u8 cfilt_mode, bg_mode;
3227 u8 ncic, nmeas, navg;
3228 u32 mclk_rate;
3229 u32 dce_wait, sta_wait;
3230 u8 *n_cic;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003231 void *calibration;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003232
3233 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003234 calibration = sitar->mbhc_cfg.calibration;
3235
3236 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
3237 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003238
3239 /* First compute the DCE / STA wait times
3240 * depending on tunable parameters.
3241 * The value is computed in microseconds
3242 */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003243 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003244 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3245 ncic = n_cic[sitar_codec_mclk_index(sitar)];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003246 nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
3247 navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
3248 mclk_rate = sitar->mbhc_cfg.mclk_rate;
3249 dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003250 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
3251
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003252 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
3253 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003254
3255 /* LDOH and CFILT are already configured during pdata handling.
3256 * Only need to make sure CFILT and bandgap are in Fast mode.
3257 * Need to restore defaults once calculation is done.
3258 */
3259 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
3260 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3261 bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
3262 0x02);
3263
3264 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3265 * to perform ADC calibration
3266 */
3267 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003268 sitar->mbhc_cfg.micbias << 5);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003269 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3270 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003271 snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003272 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3273
3274 /* DCE measurement for 0 volts */
3275 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3276 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3277 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3278 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
3279 usleep_range(100, 100);
3280 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3281 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
3282 sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
3283
3284 /* DCE measurment for MB voltage */
3285 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3286 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3287 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
3288 usleep_range(100, 100);
3289 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3290 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
3291 sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
3292
3293 /* Sta measuremnt for 0 volts */
3294 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3295 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3296 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3297 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
3298 usleep_range(100, 100);
3299 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3300 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
3301 sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
3302
3303 /* STA Measurement for MB Voltage */
3304 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
3305 usleep_range(100, 100);
3306 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3307 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
3308 sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
3309
3310 /* Restore default settings. */
3311 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3312 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
3313 cfilt_mode);
3314 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3315
3316 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
3317 usleep_range(100, 100);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003318
3319 wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
3320 sitar_turn_onoff_rel_detection(codec, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003321}
3322
3323void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
3324 const enum sitar_mbhc_btn_det_mem mem)
3325{
3326 void *ret = &btn_det->_v_btn_low;
3327
3328 switch (mem) {
3329 case SITAR_BTN_DET_GAIN:
3330 ret += sizeof(btn_det->_n_cic);
3331 case SITAR_BTN_DET_N_CIC:
3332 ret += sizeof(btn_det->_n_ready);
3333 case SITAR_BTN_DET_N_READY:
3334 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3335 case SITAR_BTN_DET_V_BTN_HIGH:
3336 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3337 case SITAR_BTN_DET_V_BTN_LOW:
3338 /* do nothing */
3339 break;
3340 default:
3341 ret = NULL;
3342 }
3343
3344 return ret;
3345}
3346
3347static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
3348{
3349 struct sitar_priv *sitar;
3350 s16 btn_mv = 0, btn_delta_mv;
3351 struct sitar_mbhc_btn_detect_cfg *btn_det;
3352 struct sitar_mbhc_plug_type_cfg *plug_type;
3353 u16 *btn_high;
3354 u8 *n_ready;
3355 int i;
3356
3357 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003358 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
3359 plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003360
3361 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003362 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003363 sitar->mbhc_data.npoll = 9;
3364 sitar->mbhc_data.nbounce_wait = 30;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003365 } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003366 sitar->mbhc_data.npoll = 7;
3367 sitar->mbhc_data.nbounce_wait = 23;
3368 }
3369
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003370 sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
3371 (sitar->mbhc_cfg.mclk_rate / 1000) *
3372 n_ready[sitar_codec_mclk_index(sitar)]) +
3373 10;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003374 sitar->mbhc_data.v_ins_hu =
3375 sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3376 sitar->mbhc_data.v_ins_h =
3377 sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3378
3379 btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
3380 for (i = 0; i < btn_det->num_btn; i++)
3381 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3382
3383 sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
3384 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3385
3386 sitar->mbhc_data.v_b1_hu =
3387 sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
3388
3389 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3390
3391 sitar->mbhc_data.v_b1_huc =
3392 sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3393
3394 sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003395 sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003396
3397 sitar->mbhc_data.v_no_mic =
3398 sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3399}
3400
3401void sitar_mbhc_init(struct snd_soc_codec *codec)
3402{
3403 struct sitar_priv *sitar;
3404 struct sitar_mbhc_general_cfg *generic;
3405 struct sitar_mbhc_btn_detect_cfg *btn_det;
3406 int n;
3407 u8 *n_cic, *gain;
3408
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003409 pr_err("%s(): ENTER\n", __func__);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003410 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003411 generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3412 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003413
3414 for (n = 0; n < 8; n++) {
3415 if (n != 7) {
3416 snd_soc_update_bits(codec,
3417 SITAR_A_CDC_MBHC_FIR_B1_CFG,
3418 0x07, n);
3419 snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
3420 btn_det->c[n]);
3421 }
3422 }
3423 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
3424 btn_det->nc);
3425
3426 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3427 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
3428 n_cic[sitar_codec_mclk_index(sitar)]);
3429
3430 gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
3431 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
3432 gain[sitar_codec_mclk_index(sitar)] << 3);
3433
3434 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3435 generic->mbhc_nsa << 4);
3436
3437 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3438 btn_det->n_meas);
3439
3440 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3441
3442 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3443
3444 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
3445 btn_det->mbhc_nsc << 3);
3446
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003447 snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
3448 sitar->mbhc_cfg.micbias);
3449
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003450 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003451
3452 snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
3453
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003454}
3455
3456static bool sitar_mbhc_fw_validate(const struct firmware *fw)
3457{
3458 u32 cfg_offset;
3459 struct sitar_mbhc_imped_detect_cfg *imped_cfg;
3460 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
3461
3462 if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
3463 return false;
3464
3465 /* previous check guarantees that there is enough fw data up
3466 * to num_btn
3467 */
3468 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
3469 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3470 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
3471 return false;
3472
3473 /* previous check guarantees that there is enough fw data up
3474 * to start of impedance detection configuration
3475 */
3476 imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
3477 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3478
3479 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
3480 return false;
3481
3482 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
3483 return false;
3484
3485 return true;
3486}
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003487
3488
3489static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
3490{
3491 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
3492}
3493
3494/* called under codec_resource_lock acquisition */
3495void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
3496{
3497 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3498 u8 wg_time;
3499
3500 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
3501 wg_time += 1;
3502
3503 /* If headphone PA is on, check if userspace receives
3504 * removal event to sync-up PA's state */
3505 if (sitar_is_hph_pa_on(codec)) {
3506 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
3507 set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
3508 set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
3509 } else {
3510 pr_debug("%s PA is off\n", __func__);
3511 }
3512
3513 if (sitar_is_hph_dac_on(codec, 1))
3514 set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
3515 if (sitar_is_hph_dac_on(codec, 0))
3516 set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
3517
3518 snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
3519 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
3520 0xC0, 0x00);
3521 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
3522 0xC0, 0x00);
3523 usleep_range(wg_time * 1000, wg_time * 1000);
3524}
3525
3526static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
3527{
3528 bool pa_turned_on = false;
3529 struct snd_soc_codec *codec = sitar->codec;
3530 u8 wg_time;
3531
3532 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
3533 wg_time += 1;
3534
3535 if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
3536 &sitar->hph_pa_dac_state)) {
3537 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
3538 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
3539 0xC0, 0xC0);
3540 }
3541 if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
3542 &sitar->hph_pa_dac_state)) {
3543 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
3544 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
3545 0xC0, 0xC0);
3546 }
3547
3548 if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
3549 &sitar->hph_pa_dac_state)) {
3550 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
3551 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
3552 1 << 4);
3553 pa_turned_on = true;
3554 }
3555 if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
3556 &sitar->hph_pa_dac_state)) {
3557 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
3558 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
3559 1 << 5);
3560 pa_turned_on = true;
3561 }
3562
3563 if (pa_turned_on) {
3564 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
3565 __func__);
3566 usleep_range(wg_time * 1000, wg_time * 1000);
3567 }
3568}
3569
3570static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
3571 enum snd_jack_types jack_type)
3572{
3573 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3574
3575 if (!insertion) {
3576 /* Report removal */
3577 sitar->hph_status &= ~jack_type;
3578 if (sitar->mbhc_cfg.headset_jack) {
3579 /* cancel possibly scheduled btn work and
3580 * report release if we reported button press */
3581 if (sitar_cancel_btn_work(sitar)) {
3582 pr_debug("%s: button press is canceled\n",
3583 __func__);
3584 } else if (sitar->buttons_pressed) {
3585 pr_debug("%s: Reporting release for reported "
3586 "button press %d\n", __func__,
3587 jack_type);
3588 sitar_snd_soc_jack_report(sitar,
3589 sitar->mbhc_cfg.button_jack, 0,
3590 sitar->buttons_pressed);
3591 sitar->buttons_pressed &=
3592 ~SITAR_JACK_BUTTON_MASK;
3593 }
3594 pr_debug("%s: Reporting removal %d\n", __func__,
3595 jack_type);
3596 sitar_snd_soc_jack_report(sitar,
3597 sitar->mbhc_cfg.headset_jack,
3598 sitar->hph_status,
3599 SITAR_JACK_MASK);
3600 }
3601 sitar_set_and_turnoff_hph_padac(codec);
3602 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
3603 SITAR_IRQ_HPH_PA_OCPR_FAULT);
3604 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
3605 SITAR_IRQ_HPH_PA_OCPL_FAULT);
3606 sitar->current_plug = PLUG_TYPE_NONE;
3607 sitar->mbhc_polling_active = false;
3608 } else {
3609 /* Report insertion */
3610 sitar->hph_status |= jack_type;
3611
3612 if (jack_type == SND_JACK_HEADPHONE)
3613 sitar->current_plug = PLUG_TYPE_HEADPHONE;
3614 else if (jack_type == SND_JACK_HEADSET) {
3615 sitar->mbhc_polling_active = true;
3616 sitar->current_plug = PLUG_TYPE_HEADSET;
3617 }
3618 if (sitar->mbhc_cfg.headset_jack) {
3619 pr_debug("%s: Reporting insertion %d\n", __func__,
3620 jack_type);
3621 sitar_snd_soc_jack_report(sitar,
3622 sitar->mbhc_cfg.headset_jack,
3623 sitar->hph_status,
3624 SITAR_JACK_MASK);
3625 }
3626 sitar_clr_and_turnon_hph_padac(sitar);
3627 }
3628}
3629
3630
3631static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
3632{
3633 return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
3634 sitar->mbhc_cfg.gpio_level_insert);
3635}
3636
3637static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
3638 int mic_volt, int mic_volt_prev)
3639{
3640 int delta = abs(mic_volt - mic_volt_prev);
3641 if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
3642 pr_debug("%s: volt delta %dmv\n", __func__, delta);
3643 return true;
3644 }
3645 return false;
3646}
3647
3648static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
3649 s32 mic_volt)
3650{
3651 bool invalid = false;
3652
3653 if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
3654 && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
3655 invalid = true;
3656 }
3657
3658 return invalid;
3659}
3660
3661static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
3662 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
3663 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
3664{
3665 int i;
3666 bool r = false;
3667 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3668 struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
3669 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
3670
3671 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
3672 if (mic_mv[i] < plug_type_ptr->v_no_mic)
3673 plug_type[i] = PLUG_TYPE_HEADPHONE;
3674 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
3675 plug_type[i] = PLUG_TYPE_HEADSET;
3676 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
3677 plug_type[i] = PLUG_TYPE_HIGH_HPH;
3678
3679 r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
3680 if (!r && i > 0) {
3681 if (plug_type[i-1] != plug_type[i])
3682 r = true;
3683 else
3684 r = sitar_is_invalid_insert_delta(codec,
3685 mic_mv[i],
3686 mic_mv[i - 1]);
3687 }
3688 }
3689
3690 return r;
3691}
3692
3693/* called under codec_resource_lock acquisition */
3694void sitar_find_plug_and_report(struct snd_soc_codec *codec,
3695 enum sitar_mbhc_plug_type plug_type)
3696{
3697 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3698
3699 if (plug_type == PLUG_TYPE_HEADPHONE
3700 && sitar->current_plug == PLUG_TYPE_NONE) {
3701 /* Nothing was reported previously
3702 * reporte a headphone
3703 */
3704 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
3705 sitar_codec_cleanup_hs_polling(codec);
3706 } else if (plug_type == PLUG_TYPE_HEADSET) {
3707 /* If Headphone was reported previously, this will
3708 * only report the mic line
3709 */
3710 sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
3711 msleep(100);
3712 sitar_codec_start_hs_polling(codec);
3713 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
3714 if (sitar->current_plug == PLUG_TYPE_NONE)
3715 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
3716 sitar_codec_cleanup_hs_polling(codec);
3717 pr_debug("setup mic trigger for further detection\n");
3718 sitar->lpi_enabled = true;
3719 /* TODO ::: sitar_codec_enable_hs_detect */
3720 pr_err("%s(): High impedence hph not supported\n", __func__);
3721 }
3722}
3723
3724/* should be called under interrupt context that hold suspend */
3725static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
3726{
3727 pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
3728 sitar->hs_detect_work_stop = false;
3729 wcd9xxx_lock_sleep(sitar->codec->control_data);
3730 schedule_work(&sitar->hs_correct_plug_work);
3731}
3732
3733/* called under codec_resource_lock acquisition */
3734static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
3735{
3736 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
3737 sitar->hs_detect_work_stop = true;
3738 wmb();
3739 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
3740 if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
3741 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
3742 wcd9xxx_unlock_sleep(sitar->codec->control_data);
3743 }
3744 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
3745}
3746
3747static void sitar_hs_correct_gpio_plug(struct work_struct *work)
3748{
3749 struct sitar_priv *sitar;
3750 struct snd_soc_codec *codec;
3751 int retry = 0, i;
3752 bool correction = false;
3753 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
3754 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
3755 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
3756 unsigned long timeout;
3757
3758 sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
3759 codec = sitar->codec;
3760
3761 pr_debug("%s: enter\n", __func__);
3762 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
3763
3764 /* Keep override on during entire plug type correction work.
3765 *
3766 * This is okay under the assumption that any GPIO irqs which use
3767 * MBHC block cancel and sync this work so override is off again
3768 * prior to GPIO interrupt handler's MBHC block usage.
3769 * Also while this correction work is running, we can guarantee
3770 * DAPM doesn't use any MBHC block as this work only runs with
3771 * headphone detection.
3772 */
3773 sitar_turn_onoff_override(codec, true);
3774
3775 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
3776 while (!time_after(jiffies, timeout)) {
3777 ++retry;
3778 rmb();
3779 if (sitar->hs_detect_work_stop) {
3780 pr_debug("%s: stop requested\n", __func__);
3781 break;
3782 }
3783
3784 msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
3785 if (sitar_hs_gpio_level_remove(sitar)) {
3786 pr_debug("%s: GPIO value is low\n", __func__);
3787 break;
3788 }
3789
3790 /* can race with removal interrupt */
3791 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
3792 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
3793 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
3794 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
3795 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
3796 __func__, retry, mic_mv[i], mb_v[i]);
3797 }
3798 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
3799
3800 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
3801 pr_debug("Invalid plug in attempt # %d\n", retry);
3802 if (retry == NUM_ATTEMPTS_TO_REPORT &&
3803 sitar->current_plug == PLUG_TYPE_NONE) {
3804 sitar_codec_report_plug(codec, 1,
3805 SND_JACK_HEADPHONE);
3806 }
3807 } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
3808 plug_type) &&
3809 plug_type[0] == PLUG_TYPE_HEADPHONE) {
3810 pr_debug("Good headphone detected, continue polling mic\n");
3811 if (sitar->current_plug == PLUG_TYPE_NONE) {
3812 sitar_codec_report_plug(codec, 1,
3813 SND_JACK_HEADPHONE);
3814 }
3815 } else {
3816 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
3817 /* Turn off override */
3818 sitar_turn_onoff_override(codec, false);
3819 sitar_find_plug_and_report(codec, plug_type[0]);
3820 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
3821 pr_debug("Attempt %d found correct plug %d\n", retry,
3822 plug_type[0]);
3823 correction = true;
3824 break;
3825 }
3826 }
3827
3828 /* Turn off override */
3829 if (!correction)
3830 sitar_turn_onoff_override(codec, false);
3831
3832 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
3833 pr_debug("%s: leave\n", __func__);
3834 /* unlock sleep */
3835 wcd9xxx_unlock_sleep(sitar->codec->control_data);
3836}
3837
3838/* called under codec_resource_lock acquisition */
3839static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
3840{
3841 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3842 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
3843 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
3844 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
3845 int i;
3846
3847 pr_debug("%s: enter\n", __func__);
3848
3849 sitar_turn_onoff_override(codec, true);
3850 mb_v[0] = sitar_codec_setup_hs_polling(codec);
3851 mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
3852 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
3853
3854 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
3855 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
3856 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
3857 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
3858 mic_mv[i]);
3859 }
3860 sitar_turn_onoff_override(codec, false);
3861
3862 if (sitar_hs_gpio_level_remove(sitar)) {
3863 pr_debug("%s: GPIO value is low when determining plug\n",
3864 __func__);
3865 return;
3866 }
3867
3868 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
3869 sitar_schedule_hs_detect_plug(sitar);
3870 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
3871 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
3872 sitar_schedule_hs_detect_plug(sitar);
3873 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
3874 pr_debug("%s: Valid plug found, determine plug type\n",
3875 __func__);
3876 sitar_find_plug_and_report(codec, plug_type[0]);
3877 }
3878
3879}
3880
3881/* called under codec_resource_lock acquisition */
3882static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
3883{
3884 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3885 const struct sitar_mbhc_plug_detect_cfg *plug_det =
3886 SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
3887
3888 if (plug_det->t_ins_complete > 20)
3889 msleep(plug_det->t_ins_complete);
3890 else
3891 usleep_range(plug_det->t_ins_complete * 1000,
3892 plug_det->t_ins_complete * 1000);
3893
3894 if (sitar_hs_gpio_level_remove(sitar))
3895 pr_debug("%s: GPIO value is low when determining "
3896 "plug\n", __func__);
3897 else
3898 sitar_codec_decide_gpio_plug(codec);
3899
3900 return;
3901}
3902
3903static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
3904{
3905 bool insert;
3906 struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
3907 bool is_removed = false;
3908
3909 pr_debug("%s: enter\n", __func__);
3910
3911 priv->in_gpio_handler = true;
3912 /* Wait here for debounce time */
3913 usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
3914 SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
3915
3916 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
3917
3918 /* cancel pending button press */
3919 if (sitar_cancel_btn_work(priv))
3920 pr_debug("%s: button press is canceled\n", __func__);
3921
3922 insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
3923 priv->mbhc_cfg.gpio_level_insert);
3924 if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
3925 priv->lpi_enabled = false;
3926 wmb();
3927
3928 /* cancel detect plug */
3929 sitar_cancel_hs_detect_plug(priv);
3930
3931 /* Disable Mic Bias pull down and HPH Switch to GND */
3932 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
3933 0x00);
3934 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
3935 sitar_codec_detect_plug_type(codec);
3936 } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
3937 priv->lpi_enabled = false;
3938 wmb();
3939
3940 /* cancel detect plug */
3941 sitar_cancel_hs_detect_plug(priv);
3942
3943 if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
3944 sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
3945 is_removed = true;
3946 } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
3947 sitar_codec_pause_hs_polling(codec);
3948 sitar_codec_cleanup_hs_polling(codec);
3949 sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
3950 is_removed = true;
3951 }
3952
3953 if (is_removed) {
3954 /* Enable Mic Bias pull down and HPH Switch to GND */
3955 snd_soc_update_bits(codec,
3956 priv->mbhc_bias_regs.ctl_reg, 0x01,
3957 0x01);
3958 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
3959 0x01);
3960 /* Make sure mic trigger is turned off */
3961 snd_soc_update_bits(codec,
3962 priv->mbhc_bias_regs.ctl_reg,
3963 0x01, 0x01);
3964 snd_soc_update_bits(codec,
3965 priv->mbhc_bias_regs.mbhc_reg,
3966 0x90, 0x00);
3967 /* Reset MBHC State Machine */
3968 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
3969 0x08, 0x08);
3970 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
3971 0x08, 0x00);
3972 /* Turn off override */
3973 sitar_turn_onoff_override(codec, false);
3974 }
3975 }
3976
3977 priv->in_gpio_handler = false;
3978 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
3979 pr_debug("%s: leave\n", __func__);
3980}
3981
3982static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
3983{
3984 int r = IRQ_HANDLED;
3985 struct snd_soc_codec *codec = data;
3986
3987 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
3988 pr_warn("%s(): Failed to hold suspend\n", __func__);
3989 r = IRQ_NONE;
3990 } else {
3991 sitar_hs_gpio_handler(codec);
3992 wcd9xxx_unlock_sleep(codec->control_data);
3993 }
3994 return r;
3995}
3996
3997static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
3998{
3999 int rc = 0;
4000 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4001
4002 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4003 sitar_mbhc_init(codec);
4004 sitar_mbhc_cal(codec);
4005 sitar_mbhc_calc_thres(codec);
4006 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4007 sitar_codec_calibrate_hs_polling(codec);
4008
4009 /* Enable Mic Bias pull down and HPH Switch to GND */
4010 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
4011 0x01, 0x01);
4012 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
4013 0x01, 0x01);
4014
4015 rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
4016 NULL,
4017 sitar_mechanical_plug_detect_irq,
4018 (IRQF_TRIGGER_RISING |
4019 IRQF_TRIGGER_FALLING),
4020 "sitar-hs-gpio", codec);
4021
4022 if (!IS_ERR_VALUE(rc)) {
4023 rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
4024 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
4025 0x10, 0x10);
4026 wcd9xxx_enable_irq(codec->control_data,
4027 SITAR_IRQ_HPH_PA_OCPL_FAULT);
4028 wcd9xxx_enable_irq(codec->control_data,
4029 SITAR_IRQ_HPH_PA_OCPR_FAULT);
4030 /* Bootup time detection */
4031 sitar_hs_gpio_handler(codec);
4032 }
4033
4034 return rc;
4035}
4036
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004037static void mbhc_fw_read(struct work_struct *work)
4038{
4039 struct delayed_work *dwork;
4040 struct sitar_priv *sitar;
4041 struct snd_soc_codec *codec;
4042 const struct firmware *fw;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004043 int ret = -1, retry = 0;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004044
4045 dwork = to_delayed_work(work);
4046 sitar = container_of(dwork, struct sitar_priv,
4047 mbhc_firmware_dwork);
4048 codec = sitar->codec;
4049
4050 while (retry < MBHC_FW_READ_ATTEMPTS) {
4051 retry++;
4052 pr_info("%s:Attempt %d to request MBHC firmware\n",
4053 __func__, retry);
4054 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
4055 codec->dev);
4056
4057 if (ret != 0) {
4058 usleep_range(MBHC_FW_READ_TIMEOUT,
4059 MBHC_FW_READ_TIMEOUT);
4060 } else {
4061 pr_info("%s: MBHC Firmware read succesful\n", __func__);
4062 break;
4063 }
4064 }
4065
4066 if (ret != 0) {
4067 pr_err("%s: Cannot load MBHC firmware use default cal\n",
4068 __func__);
4069 } else if (sitar_mbhc_fw_validate(fw) == false) {
4070 pr_err("%s: Invalid MBHC cal data size use default cal\n",
4071 __func__);
4072 release_firmware(fw);
4073 } else {
4074 sitar->calibration = (void *)fw->data;
4075 sitar->mbhc_fw = fw;
4076 }
4077
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004078 sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004079}
4080
4081int sitar_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004082 const struct sitar_mbhc_config *cfg)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004083{
4084 struct sitar_priv *sitar;
4085 int rc = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304086
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004087 if (!codec || !cfg->calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304088 pr_err("Error: no codec or calibration\n");
4089 return -EINVAL;
4090 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004091
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004092 if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
4093 if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004094 pr_err("Error: clock rate %dHz is not yet supported\n",
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004095 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004096 else
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004097 pr_err("Error: unsupported clock rate %d\n",
4098 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004099 return -EINVAL;
4100 }
4101
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304102 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004103 sitar->mbhc_cfg = *cfg;
4104 sitar->in_gpio_handler = false;
4105 sitar->current_plug = PLUG_TYPE_NONE;
4106 sitar->lpi_enabled = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304107 sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
4108
4109 /* Put CFILT in fast mode by default */
4110 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004111 0x40, SITAR_CFILT_FAST_MODE);
4112
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004113 INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004114 INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304115 INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
4116 INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004117 INIT_WORK(&sitar->hs_correct_plug_work,
4118 sitar_hs_correct_gpio_plug);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004119
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004120 if (!sitar->mbhc_cfg.read_fw_bin) {
4121 rc = sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004122 } else {
4123 schedule_delayed_work(&sitar->mbhc_firmware_dwork,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004124 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304125 }
4126
4127 return rc;
4128}
4129EXPORT_SYMBOL_GPL(sitar_hs_detect);
4130
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004131static int sitar_determine_button(const struct sitar_priv *priv,
4132 const s32 bias_mv)
4133{
4134 s16 *v_btn_low, *v_btn_high;
4135 struct sitar_mbhc_btn_detect_cfg *btn_det;
4136 int i, btn = -1;
4137
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004138 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004139 v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
4140 v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
4141 SITAR_BTN_DET_V_BTN_HIGH);
4142 for (i = 0; i < btn_det->num_btn; i++) {
4143 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4144 btn = i;
4145 break;
4146 }
4147 }
4148
4149 if (btn == -1)
4150 pr_debug("%s: couldn't find button number for mic mv %d\n",
4151 __func__, bias_mv);
4152
4153 return btn;
4154}
4155
4156static int sitar_get_button_mask(const int btn)
4157{
4158 int mask = 0;
4159 switch (btn) {
4160 case 0:
4161 mask = SND_JACK_BTN_0;
4162 break;
4163 case 1:
4164 mask = SND_JACK_BTN_1;
4165 break;
4166 case 2:
4167 mask = SND_JACK_BTN_2;
4168 break;
4169 case 3:
4170 mask = SND_JACK_BTN_3;
4171 break;
4172 case 4:
4173 mask = SND_JACK_BTN_4;
4174 break;
4175 case 5:
4176 mask = SND_JACK_BTN_5;
4177 break;
4178 case 6:
4179 mask = SND_JACK_BTN_6;
4180 break;
4181 case 7:
4182 mask = SND_JACK_BTN_7;
4183 break;
4184 }
4185 return mask;
4186}
4187
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004188
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304189static irqreturn_t sitar_dce_handler(int irq, void *data)
4190{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004191 int i, mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004192 short dce, sta, bias_value_dce;
4193 s32 mv, stamv, bias_mv_dce;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004194 int btn = -1, meas = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304195 struct sitar_priv *priv = data;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004196 const struct sitar_mbhc_btn_detect_cfg *d =
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004197 SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004198 short btnmeas[d->n_btn_meas + 1];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304199 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08004200 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004201 int n_btn_meas = d->n_btn_meas;
4202 u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304203
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004204 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304205
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004206 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4207 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
4208 pr_debug("%s: mbhc is being recovered, skip button press\n",
4209 __func__);
4210 goto done;
4211 }
4212
4213 priv->mbhc_state = MBHC_STATE_POTENTIAL;
4214
4215 if (!priv->mbhc_polling_active) {
4216 pr_warn("%s: mbhc polling is not active, skip button press\n",
4217 __func__);
4218 goto done;
4219 }
4220
4221 dce = sitar_codec_read_dce_result(codec);
4222 mv = sitar_codec_sta_dce_v(codec, 1, dce);
4223
4224 /* If GPIO interrupt already kicked in, ignore button press */
4225 if (priv->in_gpio_handler) {
4226 pr_debug("%s: GPIO State Changed, ignore button press\n",
4227 __func__);
4228 btn = -1;
4229 goto done;
4230 }
4231
4232 if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
4233 if (priv->mbhc_last_resume &&
4234 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
4235 pr_debug("%s: Button is already released shortly after "
4236 "resume\n", __func__);
4237 n_btn_meas = 0;
4238 } else {
4239 pr_debug("%s: Button is already released without "
4240 "resume", __func__);
4241 sta = sitar_codec_read_sta_result(codec);
4242 stamv = sitar_codec_sta_dce_v(codec, 0, sta);
4243 btn = sitar_determine_button(priv, mv);
4244 if (btn != sitar_determine_button(priv, stamv))
4245 btn = -1;
4246 goto done;
4247 }
4248 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304249
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004250 /* determine pressed button */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004251 btnmeas[meas++] = sitar_determine_button(priv, mv);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004252 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004253 meas - 1, dce, mv, btnmeas[meas - 1]);
4254 if (n_btn_meas == 0)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004255 btn = btnmeas[0];
4256 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004257 bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004258 bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
4259 btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
4260 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
4261 __func__, meas, bias_value_dce, bias_mv_dce,
4262 btnmeas[meas]);
4263 /* if large enough measurements are collected,
4264 * start to check if last all n_btn_con measurements were
4265 * in same button low/high range */
4266 if (meas + 1 >= d->n_btn_con) {
4267 for (i = 0; i < d->n_btn_con; i++)
4268 if ((btnmeas[meas] < 0) ||
4269 (btnmeas[meas] != btnmeas[meas - i]))
4270 break;
4271 if (i == d->n_btn_con) {
4272 /* button pressed */
4273 btn = btnmeas[meas];
4274 break;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004275 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
4276 /* if left measurements are less than n_btn_con,
4277 * it's impossible to find button number */
4278 break;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004279 }
4280 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004281 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304282
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004283 if (btn >= 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004284 if (priv->in_gpio_handler) {
4285 pr_debug("%s: GPIO already triggered, ignore button "
4286 "press\n", __func__);
4287 goto done;
4288 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004289 mask = sitar_get_button_mask(btn);
4290 priv->buttons_pressed |= mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004291 wcd9xxx_lock_sleep(core);
4292 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
4293 msecs_to_jiffies(400)) == 0) {
4294 WARN(1, "Button pressed twice without release"
4295 "event\n");
4296 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004297 }
4298 } else {
4299 pr_debug("%s: bogus button press, too short press?\n",
4300 __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304301 }
4302
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004303 done:
4304 pr_debug("%s: leave\n", __func__);
4305 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304306 return IRQ_HANDLED;
4307}
4308
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004309static int sitar_is_fake_press(struct sitar_priv *priv)
4310{
4311 int i;
4312 int r = 0;
4313 struct snd_soc_codec *codec = priv->codec;
4314 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
4315 short mb_v;
4316
4317 for (i = 0; i < dces; i++) {
4318 usleep_range(10000, 10000);
4319 if (i == 0) {
4320 mb_v = sitar_codec_sta_dce(codec, 0, true);
4321 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
4322 sitar_codec_sta_dce_v(codec, 0, mb_v));
4323 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4324 mb_v > (short)priv->mbhc_data.v_ins_hu) {
4325 r = 1;
4326 break;
4327 }
4328 } else {
4329 mb_v = sitar_codec_sta_dce(codec, 1, true);
4330 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
4331 sitar_codec_sta_dce_v(codec, 1, mb_v));
4332 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
4333 mb_v > (short)priv->mbhc_data.v_ins_h) {
4334 r = 1;
4335 break;
4336 }
4337 }
4338 }
4339
4340 return r;
4341}
4342
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304343static irqreturn_t sitar_release_handler(int irq, void *data)
4344{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004345 int ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304346 struct sitar_priv *priv = data;
4347 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304348
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004349 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304350
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004351 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4352 priv->mbhc_state = MBHC_STATE_RELEASE;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304353
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004354 if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
4355 ret = sitar_cancel_btn_work(priv);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304356 if (ret == 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004357 pr_debug("%s: Reporting long button release event\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004358 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004359 if (priv->mbhc_cfg.button_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304360 sitar_snd_soc_jack_report(priv,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004361 priv->mbhc_cfg.button_jack, 0,
4362 priv->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304363 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004364 if (sitar_is_fake_press(priv)) {
4365 pr_debug("%s: Fake button press interrupt\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004366 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004367 } else if (priv->mbhc_cfg.button_jack) {
4368 if (priv->in_gpio_handler) {
4369 pr_debug("%s: GPIO kicked in, ignore\n",
4370 __func__);
4371 } else {
4372 pr_debug("%s: Reporting short button 0 "
4373 "press and release\n",
4374 __func__);
4375 sitar_snd_soc_jack_report(priv,
4376 priv->mbhc_cfg.button_jack,
4377 priv->buttons_pressed,
4378 priv->buttons_pressed);
4379 sitar_snd_soc_jack_report(priv,
4380 priv->mbhc_cfg.button_jack, 0,
4381 priv->buttons_pressed);
4382 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304383 }
4384 }
4385
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004386 priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
4387 }
4388
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004389 sitar_codec_calibrate_hs_polling(codec);
4390
4391 if (priv->mbhc_cfg.gpio)
4392 msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
4393
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304394 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004395
4396 pr_debug("%s: leave\n", __func__);
4397 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4398
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304399 return IRQ_HANDLED;
4400}
4401
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304402static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
4403{
4404 struct sitar_priv *sitar = data;
4405 struct snd_soc_codec *codec;
4406
4407 pr_info("%s: received HPHL OCP irq\n", __func__);
4408
4409 if (sitar) {
4410 codec = sitar->codec;
4411 if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
4412 pr_info("%s: retry\n", __func__);
4413 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004414 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304415 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004416 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304417 } else {
4418 wcd9xxx_disable_irq(codec->control_data,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004419 SITAR_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304420 sitar->hphlocp_cnt = 0;
4421 sitar->hph_status |= SND_JACK_OC_HPHL;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004422 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304423 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004424 sitar->mbhc_cfg.headset_jack,
4425 sitar->hph_status,
4426 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304427 }
4428 } else {
4429 pr_err("%s: Bad sitar private data\n", __func__);
4430 }
4431
4432 return IRQ_HANDLED;
4433}
4434
4435static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
4436{
4437 struct sitar_priv *sitar = data;
4438 struct snd_soc_codec *codec;
4439
4440 pr_info("%s: received HPHR OCP irq\n", __func__);
4441
4442 if (sitar) {
4443 codec = sitar->codec;
4444 if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
4445 pr_info("%s: retry\n", __func__);
4446 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
4447 0x00);
4448 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
4449 0x10);
4450 } else {
4451 wcd9xxx_disable_irq(codec->control_data,
4452 SITAR_IRQ_HPH_PA_OCPR_FAULT);
4453 sitar->hphrocp_cnt = 0;
4454 sitar->hph_status |= SND_JACK_OC_HPHR;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004455 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304456 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004457 sitar->mbhc_cfg.headset_jack,
4458 sitar->hph_status,
4459 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304460 }
4461 } else {
4462 pr_err("%s: Bad sitar private data\n", __func__);
4463 }
4464
4465 return IRQ_HANDLED;
4466}
4467
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304468static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
4469{
4470 struct sitar_priv *priv = data;
4471 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304472
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004473 pr_debug("%s: enter\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004474 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304475 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304476
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304477 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4478
4479 /* Turn off both HPH and MIC line schmitt triggers */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004480 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304481 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004482 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304483
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004484 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304485
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004486 rmb();
4487 if (priv->lpi_enabled)
4488 msleep(100);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304489
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004490 rmb();
4491 if (!priv->lpi_enabled) {
4492 pr_debug("%s: lpi is disabled\n", __func__);
4493 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4494 priv->mbhc_cfg.gpio_level_insert) {
4495 pr_debug("%s: Valid insertion, "
4496 "detect plug type\n", __func__);
4497 sitar_codec_decide_gpio_plug(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304498 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004499 pr_debug("%s: Invalid insertion, "
4500 "stop plug detection\n", __func__);
4501 }
4502 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4503 return IRQ_HANDLED;
4504}
4505
4506static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
4507{
4508 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4509 struct sitar_mbhc_plug_type_cfg *plug_type =
4510 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4511
4512 return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
4513 && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
4514 && (mic_mv > plug_type->v_no_mic)
4515 && (mic_mv < plug_type->v_hs_max)) ? true : false;
4516}
4517
4518/* called under codec_resource_lock acquisition
4519 * returns true if mic voltage range is back to normal insertion
4520 * returns false either if timedout or removed */
4521static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
4522{
4523 int i;
4524 bool timedout, settled = false;
4525 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4526 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4527 unsigned long retry = 0, timeout;
4528 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4529
4530 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4531 while (!(timedout = time_after(jiffies, timeout))) {
4532 retry++;
4533 if (sitar_hs_gpio_level_remove(sitar)) {
4534 pr_debug("%s: GPIO indicates removal\n", __func__);
4535 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304536 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004537
4538 if (retry > 1)
4539 msleep(250);
4540 else
4541 msleep(50);
4542
4543 if (sitar_hs_gpio_level_remove(sitar)) {
4544 pr_debug("%s: GPIO indicates removal\n", __func__);
4545 break;
4546 }
4547
4548 sitar_turn_onoff_override(codec, true);
4549 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4550 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4551 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4552 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
4553 __func__, retry, mic_mv[i], mb_v[i]);
4554 }
4555 sitar_turn_onoff_override(codec, false);
4556
4557 if (sitar_hs_gpio_level_remove(sitar)) {
4558 pr_debug("%s: GPIO indicates removal\n", __func__);
4559 break;
4560 }
4561
4562 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
4563 if (!is_valid_mic_voltage(codec, mic_mv[i]))
4564 break;
4565
4566 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
4567 pr_debug("%s: MIC voltage settled\n", __func__);
4568 settled = true;
4569 msleep(200);
4570 break;
4571 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304572 }
4573
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004574 if (timedout)
4575 pr_debug("%s: Microphone did not settle in %d seconds\n",
4576 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
4577 return settled;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304578}
4579
4580static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
4581{
4582 struct sitar_priv *priv = data;
4583 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304584
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004585 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304586
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004587 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4588 if (sitar_hs_remove_settle(codec))
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304589 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004590 pr_debug("%s: remove settle done\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304591
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004592 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304593 return IRQ_HANDLED;
4594}
4595
4596
4597static unsigned long slimbus_value;
4598
4599static irqreturn_t sitar_slimbus_irq(int irq, void *data)
4600{
4601 struct sitar_priv *priv = data;
4602 struct snd_soc_codec *codec = priv->codec;
4603 int i, j;
4604 u8 val;
4605
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304606
4607 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
4608 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
4609 SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
4610 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4611 val = wcd9xxx_interface_reg_read(codec->control_data,
4612 SITAR_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4613 if (val & 0x1)
4614 pr_err_ratelimited("overflow error on port %x,"
4615 " value %x\n", i*8 + j, val);
4616 if (val & 0x2)
4617 pr_err_ratelimited("underflow error on port %x,"
4618 " value %x\n", i*8 + j, val);
4619 }
4620 wcd9xxx_interface_reg_write(codec->control_data,
4621 SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4622 }
4623
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304624 return IRQ_HANDLED;
4625}
4626
4627
4628static int sitar_handle_pdata(struct sitar_priv *sitar)
4629{
4630 struct snd_soc_codec *codec = sitar->codec;
4631 struct wcd9xxx_pdata *pdata = sitar->pdata;
4632 int k1, k2, rc = 0;
4633 u8 leg_mode = pdata->amic_settings.legacy_mode;
4634 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4635 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4636 u8 flag = pdata->amic_settings.use_pdata;
4637 u8 i = 0, j = 0;
4638 u8 val_txfe = 0, value = 0;
4639
4640 if (!pdata) {
4641 rc = -ENODEV;
4642 goto done;
4643 }
4644
4645 /* Make sure settings are correct */
4646 if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
4647 (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
4648 (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
4649 rc = -EINVAL;
4650 goto done;
4651 }
4652
4653 /* figure out k value */
4654 k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
4655 pdata->micbias.cfilt1_mv);
4656 k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
4657 pdata->micbias.cfilt2_mv);
4658
4659 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
4660 rc = -EINVAL;
4661 goto done;
4662 }
4663
4664 /* Set voltage level and always use LDO */
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07004665 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
4666 (pdata->micbias.ldoh_v << 2));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304667
4668 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
4669 (k1 << 2));
4670 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
4671 (k2 << 2));
4672
4673 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
4674 (pdata->micbias.bias1_cfilt_sel << 5));
4675 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
4676 (pdata->micbias.bias2_cfilt_sel << 5));
4677
Bhalchandra Gajare15dbeaa2012-06-26 12:53:07 -07004678 /* Set micbias capless mode */
4679 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x10,
4680 (pdata->micbias.bias1_cap_mode << 4));
4681 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
4682 (pdata->micbias.bias2_cap_mode << 4));
4683
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304684 for (i = 0; i < 6; j++, i += 2) {
4685 if (flag & (0x01 << i)) {
4686 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4687 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4688 val_txfe = val_txfe |
4689 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4690 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
4691 0x10, value);
4692 snd_soc_update_bits(codec,
4693 SITAR_A_TX_1_2_TEST_EN + j * 10,
4694 0x30, val_txfe);
4695 }
4696 if (flag & (0x01 << (i + 1))) {
4697 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4698 val_txfe = (txfe_bypass &
4699 (0x01 << (i + 1))) ? 0x02 : 0x00;
4700 val_txfe |= (txfe_buff &
4701 (0x01 << (i + 1))) ? 0x01 : 0x00;
4702 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
4703 0x01, value);
4704 snd_soc_update_bits(codec,
4705 SITAR_A_TX_1_2_TEST_EN + j * 10,
4706 0x03, val_txfe);
4707 }
4708 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004709 if (flag & 0x40) {
4710 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4711 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4712 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4713 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
4714 0x13, value);
4715 }
4716
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304717
4718 if (pdata->ocp.use_pdata) {
4719 /* not defined in CODEC specification */
4720 if (pdata->ocp.hph_ocp_limit == 1 ||
4721 pdata->ocp.hph_ocp_limit == 5) {
4722 rc = -EINVAL;
4723 goto done;
4724 }
4725 snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
4726 0x0F, pdata->ocp.num_attempts);
4727 snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
4728 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4729 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
4730 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4731 }
4732done:
4733 return rc;
4734}
4735
4736static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
4737
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304738 SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
4739 SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
4740
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304741 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
4742 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
4743
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304744 SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
4745 SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
4746 SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
4747
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304748 SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
Asish Bhattacharya2e1d7522012-05-25 15:08:40 +05304749 SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
4750 SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304751
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304752 SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
4753
4754 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4755
4756};
4757
4758static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
4759{
4760 u32 i;
4761 for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
4762 snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
4763 sitar_1_1_reg_defaults[i].val);
4764
4765}
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05304766
4767static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
4768 {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
4769};
4770
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304771static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
4772 /* Initialize current threshold to 350MA
4773 * number of wait and run cycles to 4096
4774 */
Bhalchandra Gajare33f74302012-06-14 15:12:51 -07004775 {SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304776 {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
4777
4778 {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
4779
4780 /* Initialize gain registers to use register gain */
4781 {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
4782 {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
4783 {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
4784 {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
4785
4786 /* Initialize mic biases to differential mode */
4787 {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4788 {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4789
4790 {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4791
4792 /* Use 16 bit sample size for TX1 to TX6 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004793 {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304794 {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4795 {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4796 {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4797 {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004798 {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304799
4800 /* Use 16 bit sample size for RX */
4801 {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4802 {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
4803
4804 /*enable HPF filter for TX paths */
4805 {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004806 {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07004807
4808 /*enable External clock select*/
4809 {SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304810};
4811
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05304812static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
4813{
4814 u32 i;
4815 for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
4816 snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
4817 sitar_i2c_codec_reg_init_val[i].mask,
4818 sitar_i2c_codec_reg_init_val[i].val);
4819}
4820
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304821static void sitar_codec_init_reg(struct snd_soc_codec *codec)
4822{
4823 u32 i;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304824 for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
4825 snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
4826 sitar_codec_reg_init_val[i].mask,
4827 sitar_codec_reg_init_val[i].val);
4828}
4829
4830static int sitar_codec_probe(struct snd_soc_codec *codec)
4831{
4832 struct sitar *control;
4833 struct sitar_priv *sitar;
4834 struct snd_soc_dapm_context *dapm = &codec->dapm;
4835 int ret = 0;
4836 int i;
4837 u8 sitar_version;
4838 int ch_cnt;
4839
4840 codec->control_data = dev_get_drvdata(codec->dev->parent);
4841 control = codec->control_data;
4842
4843 sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
4844 if (!sitar) {
4845 dev_err(codec->dev, "Failed to allocate private data\n");
4846 return -ENOMEM;
4847 }
4848
4849 /* Make sure mbhc micbias register addresses are zeroed out */
4850 memset(&sitar->mbhc_bias_regs, 0,
4851 sizeof(struct mbhc_micbias_regs));
4852 sitar->cfilt_k_value = 0;
4853 sitar->mbhc_micbias_switched = false;
4854
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004855 /* Make sure mbhc intenal calibration data is zeroed out */
4856 memset(&sitar->mbhc_data, 0,
4857 sizeof(struct mbhc_internal_cal_data));
4858 sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
4859 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4860 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304861 snd_soc_codec_set_drvdata(codec, sitar);
4862
4863 sitar->mclk_enabled = false;
4864 sitar->bandgap_type = SITAR_BANDGAP_OFF;
4865 sitar->clock_active = false;
4866 sitar->config_mode_active = false;
4867 sitar->mbhc_polling_active = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304868 sitar->no_mic_headset_override = false;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004869 mutex_init(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304870 sitar->codec = codec;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004871 sitar->mbhc_state = MBHC_STATE_NONE;
4872 sitar->mbhc_last_resume = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304873 sitar->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304874 sitar_update_reg_defaults(codec);
4875 sitar_codec_init_reg(codec);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05304876 sitar->intf_type = wcd9xxx_get_intf_type();
4877 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
4878 sitar_i2c_codec_init_reg(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304879
4880 ret = sitar_handle_pdata(sitar);
4881 if (IS_ERR_VALUE(ret)) {
4882 pr_err("%s: bad pdata\n", __func__);
4883 goto err_pdata;
4884 }
4885
Steve Mucklef132c6c2012-06-06 18:30:57 -07004886 snd_soc_add_codec_controls(codec, sitar_snd_controls,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304887 ARRAY_SIZE(sitar_snd_controls));
4888 snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
4889 ARRAY_SIZE(sitar_dapm_widgets));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05304890 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
4891 snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
4892 ARRAY_SIZE(sitar_dapm_i2s_widgets));
4893 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4894 ARRAY_SIZE(audio_i2s_map));
4895 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304896 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
4897
4898 sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
4899 pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
4900
4901 sitar_version &= 0x1F;
4902 pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
4903
4904 snd_soc_dapm_sync(dapm);
4905
4906
4907 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
4908 sitar_hs_insert_irq, "Headset insert detect", sitar);
4909 if (ret) {
4910 pr_err("%s: Failed to request irq %d\n", __func__,
4911 SITAR_IRQ_MBHC_INSERTION);
4912 goto err_insert_irq;
4913 }
4914 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
4915
4916 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
4917 sitar_hs_remove_irq, "Headset remove detect", sitar);
4918 if (ret) {
4919 pr_err("%s: Failed to request irq %d\n", __func__,
4920 SITAR_IRQ_MBHC_REMOVAL);
4921 goto err_remove_irq;
4922 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304923
4924 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
4925 sitar_dce_handler, "DC Estimation detect", sitar);
4926 if (ret) {
4927 pr_err("%s: Failed to request irq %d\n", __func__,
4928 SITAR_IRQ_MBHC_POTENTIAL);
4929 goto err_potential_irq;
4930 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304931
4932 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
4933 sitar_release_handler, "Button Release detect", sitar);
4934 if (ret) {
4935 pr_err("%s: Failed to request irq %d\n", __func__,
4936 SITAR_IRQ_MBHC_RELEASE);
4937 goto err_release_irq;
4938 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304939
4940 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
4941 sitar_slimbus_irq, "SLIMBUS Slave", sitar);
4942 if (ret) {
4943 pr_err("%s: Failed to request irq %d\n", __func__,
4944 SITAR_IRQ_SLIMBUS);
4945 goto err_slimbus_irq;
4946 }
4947
4948 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
4949 wcd9xxx_interface_reg_write(codec->control_data,
4950 SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4951
4952
4953 ret = wcd9xxx_request_irq(codec->control_data,
4954 SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
4955 "HPH_L OCP detect", sitar);
4956 if (ret) {
4957 pr_err("%s: Failed to request irq %d\n", __func__,
4958 SITAR_IRQ_HPH_PA_OCPL_FAULT);
4959 goto err_hphl_ocp_irq;
4960 }
4961 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
4962
4963 ret = wcd9xxx_request_irq(codec->control_data,
4964 SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
4965 "HPH_R OCP detect", sitar);
4966 if (ret) {
4967 pr_err("%s: Failed to request irq %d\n", __func__,
4968 SITAR_IRQ_HPH_PA_OCPR_FAULT);
4969 goto err_hphr_ocp_irq;
4970 }
4971 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
4972
4973 for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
4974 switch (sitar_dai[i].id) {
4975 case AIF1_PB:
4976 ch_cnt = sitar_dai[i].playback.channels_max;
4977 break;
4978 case AIF1_CAP:
4979 ch_cnt = sitar_dai[i].capture.channels_max;
4980 break;
4981 default:
4982 continue;
4983 }
4984 sitar->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
4985 ch_cnt), GFP_KERNEL);
4986 }
4987
Steve Mucklef132c6c2012-06-06 18:30:57 -07004988 codec->ignore_pmdown_time = 1;
4989
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304990#ifdef CONFIG_DEBUG_FS
4991 debug_sitar_priv = sitar;
4992#endif
4993
4994 return ret;
4995
4996err_hphr_ocp_irq:
4997 wcd9xxx_free_irq(codec->control_data,
4998 SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
4999err_hphl_ocp_irq:
5000 wcd9xxx_free_irq(codec->control_data,
5001 SITAR_IRQ_SLIMBUS, sitar);
5002err_slimbus_irq:
5003 wcd9xxx_free_irq(codec->control_data,
5004 SITAR_IRQ_MBHC_RELEASE, sitar);
5005err_release_irq:
5006 wcd9xxx_free_irq(codec->control_data,
5007 SITAR_IRQ_MBHC_POTENTIAL, sitar);
5008err_potential_irq:
5009 wcd9xxx_free_irq(codec->control_data,
5010 SITAR_IRQ_MBHC_REMOVAL, sitar);
5011err_remove_irq:
5012 wcd9xxx_free_irq(codec->control_data,
5013 SITAR_IRQ_MBHC_INSERTION, sitar);
5014err_insert_irq:
5015err_pdata:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005016 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305017 kfree(sitar);
5018 return ret;
5019}
5020static int sitar_codec_remove(struct snd_soc_codec *codec)
5021{
5022 int i;
5023 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5024 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
5025 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
5026 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
5027 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
5028 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005029 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305030 sitar_codec_disable_clock_block(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005031 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305032 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005033 if (sitar->mbhc_fw)
5034 release_firmware(sitar->mbhc_fw);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305035 for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
5036 kfree(sitar->dai[i].ch_num);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005037 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305038 kfree(sitar);
5039 return 0;
5040}
5041static struct snd_soc_codec_driver soc_codec_dev_sitar = {
5042 .probe = sitar_codec_probe,
5043 .remove = sitar_codec_remove,
5044 .read = sitar_read,
5045 .write = sitar_write,
5046
5047 .readable_register = sitar_readable,
5048 .volatile_register = sitar_volatile,
5049
5050 .reg_cache_size = SITAR_CACHE_SIZE,
5051 .reg_cache_default = sitar_reg_defaults,
5052 .reg_word_size = 1,
5053};
5054
5055#ifdef CONFIG_DEBUG_FS
5056static struct dentry *debugfs_poke;
5057
5058static int codec_debug_open(struct inode *inode, struct file *file)
5059{
5060 file->private_data = inode->i_private;
5061 return 0;
5062}
5063
5064static ssize_t codec_debug_write(struct file *filp,
5065 const char __user *ubuf, size_t cnt, loff_t *ppos)
5066{
5067 char lbuf[32];
5068 char *buf;
5069 int rc;
5070
5071 if (cnt > sizeof(lbuf) - 1)
5072 return -EINVAL;
5073
5074 rc = copy_from_user(lbuf, ubuf, cnt);
5075 if (rc)
5076 return -EFAULT;
5077
5078 lbuf[cnt] = '\0';
5079 buf = (char *)lbuf;
5080 debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
5081 ? false : true;
5082
5083 return rc;
5084}
5085
5086static const struct file_operations codec_debug_ops = {
5087 .open = codec_debug_open,
5088 .write = codec_debug_write,
5089};
5090#endif
5091
5092#ifdef CONFIG_PM
5093static int sitar_suspend(struct device *dev)
5094{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005095 dev_dbg(dev, "%s: system suspend\n", __func__);
5096 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305097}
5098
5099static int sitar_resume(struct device *dev)
5100{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005101 struct platform_device *pdev = to_platform_device(dev);
5102 struct sitar_priv *sitar = platform_get_drvdata(pdev);
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005103 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005104 sitar->mbhc_last_resume = jiffies;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005105 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305106}
5107
5108static const struct dev_pm_ops sitar_pm_ops = {
5109 .suspend = sitar_suspend,
5110 .resume = sitar_resume,
5111};
5112#endif
5113
5114static int __devinit sitar_probe(struct platform_device *pdev)
5115{
5116 int ret = 0;
5117 pr_err("%s\n", __func__);
5118#ifdef CONFIG_DEBUG_FS
5119 debugfs_poke = debugfs_create_file("TRRS",
5120 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
5121
5122#endif
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305123 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5124 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305125 sitar_dai, ARRAY_SIZE(sitar_dai));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305126 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5127 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
5128 sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305129 return ret;
5130}
5131static int __devexit sitar_remove(struct platform_device *pdev)
5132{
5133 snd_soc_unregister_codec(&pdev->dev);
5134
5135#ifdef CONFIG_DEBUG_FS
5136 debugfs_remove(debugfs_poke);
5137#endif
5138 return 0;
5139}
5140static struct platform_driver sitar_codec_driver = {
5141 .probe = sitar_probe,
5142 .remove = sitar_remove,
5143 .driver = {
5144 .name = "sitar_codec",
5145 .owner = THIS_MODULE,
5146#ifdef CONFIG_PM
5147 .pm = &sitar_pm_ops,
5148#endif
5149 },
5150};
5151
5152static int __init sitar_codec_init(void)
5153{
5154 return platform_driver_register(&sitar_codec_driver);
5155}
5156
5157static void __exit sitar_codec_exit(void)
5158{
5159 platform_driver_unregister(&sitar_codec_driver);
5160}
5161
5162module_init(sitar_codec_init);
5163module_exit(sitar_codec_exit);
5164
5165MODULE_DESCRIPTION("Sitar codec driver");
5166MODULE_VERSION("1.0");
5167MODULE_LICENSE("GPL v2");