blob: 579cf8b0444eb19682d568b4dbaaae02c9b9088c [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302 *
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>
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -070036#include <linux/wait.h>
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053037#include "wcd9304.h"
38
39#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
40 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
Asish Bhattacharyab9afc732012-08-01 15:11:24 +053041#define ADC_DMIC_SEL_ADC 0
42#define ADC_DMIC_SEL_DMIC 1
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053043
Asish Bhattacharya34aa1982012-09-20 14:24:05 +053044#define NUM_AMIC 3
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053045#define NUM_DECIMATORS 4
46#define NUM_INTERPOLATORS 3
47#define BITS_PER_REG 8
Kuirong Wang906ac472012-07-09 12:54:44 -070048
49enum {
50 AIF1_PB = 0,
51 AIF1_CAP,
52 NUM_CODEC_DAIS,
53};
54
55struct wcd9xxx_ch sitar_rx_chs[SITAR_RX_MAX] = {
56 WCD9XXX_CH(10, 0),
57 WCD9XXX_CH(11, 1),
58 WCD9XXX_CH(12, 2),
59 WCD9XXX_CH(13, 3),
60 WCD9XXX_CH(14, 4)
61};
62
63struct wcd9xxx_ch sitar_tx_chs[SITAR_TX_MAX] = {
64 WCD9XXX_CH(0, 0),
65 WCD9XXX_CH(1, 1),
66 WCD9XXX_CH(2, 2),
67 WCD9XXX_CH(3, 3),
68 WCD9XXX_CH(4, 4),
69};
70
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080071#define SITAR_CFILT_FAST_MODE 0x00
72#define SITAR_CFILT_SLOW_MODE 0x40
73#define MBHC_FW_READ_ATTEMPTS 15
74#define MBHC_FW_READ_TIMEOUT 2000000
75
Kuirong Wang906ac472012-07-09 12:54:44 -070076#define SLIM_CLOSE_TIMEOUT 1000
77
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080078#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
79
80#define SITAR_I2S_MASTER_MODE_MASK 0x08
81
82#define SITAR_OCP_ATTEMPT 1
83
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080084#define SITAR_MCLK_RATE_12288KHZ 12288000
85#define SITAR_MCLK_RATE_9600KHZ 9600000
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053086
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080087#define SITAR_FAKE_INS_THRESHOLD_MS 2500
88#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070089#define SITAR_MBHC_BUTTON_MIN 0x8000
90#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
91
92#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
93#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
94
95#define MBHC_NUM_DCE_PLUG_DETECT 3
96#define SITAR_MBHC_FAKE_INSERT_LOW 10
97#define SITAR_MBHC_FAKE_INSERT_HIGH 80
98#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
99#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
100#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
101#define NUM_ATTEMPTS_TO_REPORT 5
102#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
103#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530104
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -0700105#define CUT_OF_FREQ_MASK 0x30
106#define CF_MIN_3DB_4HZ 0x0
107#define CF_MIN_3DB_75HZ 0x01
108#define CF_MIN_3DB_150HZ 0x02
109
110
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530111static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
112static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
113static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
114static struct snd_soc_dai_driver sitar_dai[];
115static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
116 struct snd_kcontrol *kcontrol, int event);
117static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
118 struct snd_kcontrol *kcontrol, int event);
119
120enum sitar_bandgap_type {
121 SITAR_BANDGAP_OFF = 0,
122 SITAR_BANDGAP_AUDIO_MODE,
123 SITAR_BANDGAP_MBHC_MODE,
124};
125
126struct mbhc_micbias_regs {
127 u16 cfilt_val;
128 u16 cfilt_ctl;
129 u16 mbhc_reg;
130 u16 int_rbias;
131 u16 ctl_reg;
132 u8 cfilt_sel;
133};
134
135/* Codec supports 2 IIR filters */
136enum {
137 IIR1 = 0,
138 IIR2,
139 IIR_MAX,
140};
141/* Codec supports 5 bands */
142enum {
143 BAND1 = 0,
144 BAND2,
145 BAND3,
146 BAND4,
147 BAND5,
148 BAND_MAX,
149};
150
151/* Flags to track of PA and DAC state.
152 * PA and DAC should be tracked separately as AUXPGA loopback requires
153 * only PA to be turned on without DAC being on. */
154enum sitar_priv_ack_flags {
155 SITAR_HPHL_PA_OFF_ACK = 0,
156 SITAR_HPHR_PA_OFF_ACK,
157 SITAR_HPHL_DAC_OFF_ACK,
158 SITAR_HPHR_DAC_OFF_ACK
159};
160
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800161/* Data used by MBHC */
162struct mbhc_internal_cal_data {
163 u16 dce_z;
164 u16 dce_mb;
165 u16 sta_z;
166 u16 sta_mb;
167 u32 t_sta_dce;
168 u32 t_dce;
169 u32 t_sta;
170 u32 micb_mv;
171 u16 v_ins_hu;
172 u16 v_ins_h;
173 u16 v_b1_hu;
174 u16 v_b1_h;
175 u16 v_b1_huc;
176 u16 v_brh;
177 u16 v_brl;
178 u16 v_no_mic;
179 u8 npoll;
180 u8 nbounce_wait;
181};
182
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700183enum sitar_mbhc_plug_type {
184 PLUG_TYPE_INVALID = -1,
185 PLUG_TYPE_NONE,
186 PLUG_TYPE_HEADSET,
187 PLUG_TYPE_HEADPHONE,
188 PLUG_TYPE_HIGH_HPH,
189};
190
191enum sitar_mbhc_state {
192 MBHC_STATE_NONE = -1,
193 MBHC_STATE_POTENTIAL,
194 MBHC_STATE_POTENTIAL_RECOVERY,
195 MBHC_STATE_RELEASE,
196};
197
Kuirong Wang906ac472012-07-09 12:54:44 -0700198static const u32 vport_check_table[NUM_CODEC_DAIS] = {
199 0, /* AIF1_PB */
200 0, /* AIF1_CAP */
201};
202
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -0700203struct hpf_work {
204 struct sitar_priv *sitar;
205 u32 decimator;
206 u8 tx_hpf_cut_of_freq;
207 struct delayed_work dwork;
208};
209
210static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
211
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530212struct sitar_priv {
213 struct snd_soc_codec *codec;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800214 u32 mclk_freq;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530215 u32 adc_count;
216 u32 cfilt1_cnt;
217 u32 cfilt2_cnt;
218 u32 cfilt3_cnt;
219 u32 rx_bias_count;
220 enum sitar_bandgap_type bandgap_type;
221 bool mclk_enabled;
222 bool clock_active;
223 bool config_mode_active;
224 bool mbhc_polling_active;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800225 unsigned long mbhc_fake_ins_start;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530226 int buttons_pressed;
227
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800228 enum sitar_micbias_num micbias;
229 /* void* calibration contains:
230 * struct sitar_mbhc_general_cfg generic;
231 * struct sitar_mbhc_plug_detect_cfg plug_det;
232 * struct sitar_mbhc_plug_type_cfg plug_type;
233 * struct sitar_mbhc_btn_detect_cfg btn_det;
234 * struct sitar_mbhc_imped_detect_cfg imped_det;
235 * Note: various size depends on btn_det->num_btn
236 */
237 void *calibration;
238 struct mbhc_internal_cal_data mbhc_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530239
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530240 struct wcd9xxx_pdata *pdata;
241 u32 anc_slot;
242
243 bool no_mic_headset_override;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530244
245 struct mbhc_micbias_regs mbhc_bias_regs;
246 u8 cfilt_k_value;
247 bool mbhc_micbias_switched;
248
249 /* track PA/DAC state */
250 unsigned long hph_pa_dac_state;
251
252 /*track sitar interface type*/
253 u8 intf_type;
254
255 u32 hph_status; /* track headhpone status */
256 /* define separate work for left and right headphone OCP to avoid
257 * additional checking on which OCP event to report so no locking
258 * to ensure synchronization is required
259 */
260 struct work_struct hphlocp_work; /* reporting left hph ocp off */
261 struct work_struct hphrocp_work; /* reporting right hph ocp off */
262
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530263 u8 hphlocp_cnt; /* headphone left ocp retry */
264 u8 hphrocp_cnt; /* headphone right ocp retry */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800265
266 /* Callback function to enable MCLK */
267 int (*mclk_cb) (struct snd_soc_codec*, int);
268
269 /* Work to perform MBHC Firmware Read */
270 struct delayed_work mbhc_firmware_dwork;
271 const struct firmware *mbhc_fw;
272
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530273 /* num of slim ports required */
Kuirong Wang906ac472012-07-09 12:54:44 -0700274 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700275
276 /* Currently, only used for mbhc purpose, to protect
277 * concurrent execution of mbhc threaded irq handlers and
278 * kill race between DAPM and MBHC.But can serve as a
279 * general lock to protect codec resource
280 */
281 struct mutex codec_resource_lock;
282
283 struct sitar_mbhc_config mbhc_cfg;
284 bool in_gpio_handler;
285 u8 current_plug;
286 bool lpi_enabled;
287 enum sitar_mbhc_state mbhc_state;
288 struct work_struct hs_correct_plug_work;
289 bool hs_detect_work_stop;
290 struct delayed_work mbhc_btn_dwork;
291 unsigned long mbhc_last_resume; /* in jiffies */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530292};
293
294#ifdef CONFIG_DEBUG_FS
295struct sitar_priv *debug_sitar_priv;
296#endif
297
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700298static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
299 struct snd_ctl_elem_value *ucontrol)
300{
301 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
302 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
303 ucontrol->value.integer.value[0] = sitar->anc_slot;
304 return 0;
305}
306
307static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
308 struct snd_ctl_elem_value *ucontrol)
309{
310 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
311 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
312 sitar->anc_slot = ucontrol->value.integer.value[0];
313 return 0;
314}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530315
316static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
317 struct snd_ctl_elem_value *ucontrol)
318{
319 u8 ear_pa_gain;
320 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
321
322 ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
323
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700324 ear_pa_gain &= 0xE0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530325
326 if (ear_pa_gain == 0x00) {
327 ucontrol->value.integer.value[0] = 0;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700328 } else if (ear_pa_gain == 0x80) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530329 ucontrol->value.integer.value[0] = 1;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700330 } else if (ear_pa_gain == 0xA0) {
331 ucontrol->value.integer.value[0] = 2;
332 } else if (ear_pa_gain == 0xE0) {
333 ucontrol->value.integer.value[0] = 3;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530334 } else {
335 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
336 __func__, ear_pa_gain);
337 return -EINVAL;
338 }
339
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530340 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530341
342 return 0;
343}
344
345static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
346 struct snd_ctl_elem_value *ucontrol)
347{
348 u8 ear_pa_gain;
349 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
350
351 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
352 ucontrol->value.integer.value[0]);
353
354 switch (ucontrol->value.integer.value[0]) {
355 case 0:
356 ear_pa_gain = 0x00;
357 break;
358 case 1:
359 ear_pa_gain = 0x80;
360 break;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700361 case 2:
362 ear_pa_gain = 0xA0;
363 break;
364 case 3:
365 ear_pa_gain = 0xE0;
366 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530367 default:
368 return -EINVAL;
369 }
370
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700371 snd_soc_update_bits(codec, SITAR_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530372 return 0;
373}
374
375static int sitar_get_iir_enable_audio_mixer(
376 struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
378{
379 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
380 int iir_idx = ((struct soc_multi_mixer_control *)
381 kcontrol->private_value)->reg;
382 int band_idx = ((struct soc_multi_mixer_control *)
383 kcontrol->private_value)->shift;
384
385 ucontrol->value.integer.value[0] =
386 snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
387 (1 << band_idx);
388
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530389 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530390 iir_idx, band_idx,
391 (uint32_t)ucontrol->value.integer.value[0]);
392 return 0;
393}
394
395static int sitar_put_iir_enable_audio_mixer(
396 struct snd_kcontrol *kcontrol,
397 struct snd_ctl_elem_value *ucontrol)
398{
399 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
400 int iir_idx = ((struct soc_multi_mixer_control *)
401 kcontrol->private_value)->reg;
402 int band_idx = ((struct soc_multi_mixer_control *)
403 kcontrol->private_value)->shift;
404 int value = ucontrol->value.integer.value[0];
405
406 /* Mask first 5 bits, 6-8 are reserved */
407 snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
408 (1 << band_idx), (value << band_idx));
409
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530410 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530411 iir_idx, band_idx, value);
412 return 0;
413}
414static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
415 int iir_idx, int band_idx,
416 int coeff_idx)
417{
418 /* Address does not automatically update if reading */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530419 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530420 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530421 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530422
423 /* Mask bits top 2 bits since they are reserved */
424 return ((snd_soc_read(codec,
425 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
426 (snd_soc_read(codec,
427 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
428 (snd_soc_read(codec,
429 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
430 (snd_soc_read(codec,
431 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
432 0x3FFFFFFF;
433}
434
435static int sitar_get_iir_band_audio_mixer(
436 struct snd_kcontrol *kcontrol,
437 struct snd_ctl_elem_value *ucontrol)
438{
439 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
440 int iir_idx = ((struct soc_multi_mixer_control *)
441 kcontrol->private_value)->reg;
442 int band_idx = ((struct soc_multi_mixer_control *)
443 kcontrol->private_value)->shift;
444
445 ucontrol->value.integer.value[0] =
446 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
447 ucontrol->value.integer.value[1] =
448 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
449 ucontrol->value.integer.value[2] =
450 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
451 ucontrol->value.integer.value[3] =
452 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
453 ucontrol->value.integer.value[4] =
454 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
455
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530456 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530457 "%s: IIR #%d band #%d b1 = 0x%x\n"
458 "%s: IIR #%d band #%d b2 = 0x%x\n"
459 "%s: IIR #%d band #%d a1 = 0x%x\n"
460 "%s: IIR #%d band #%d a2 = 0x%x\n",
461 __func__, iir_idx, band_idx,
462 (uint32_t)ucontrol->value.integer.value[0],
463 __func__, iir_idx, band_idx,
464 (uint32_t)ucontrol->value.integer.value[1],
465 __func__, iir_idx, band_idx,
466 (uint32_t)ucontrol->value.integer.value[2],
467 __func__, iir_idx, band_idx,
468 (uint32_t)ucontrol->value.integer.value[3],
469 __func__, iir_idx, band_idx,
470 (uint32_t)ucontrol->value.integer.value[4]);
471 return 0;
472}
473
474static void set_iir_band_coeff(struct snd_soc_codec *codec,
475 int iir_idx, int band_idx,
476 int coeff_idx, uint32_t value)
477{
478 /* Mask top 3 bits, 6-8 are reserved */
479 /* Update address manually each time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530480 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530481 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530482 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530483
484 /* Mask top 2 bits, 7-8 are reserved */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530485 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530486 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530487 (value >> 24) & 0x3F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530488
489 /* Isolate 8bits at a time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530490 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530491 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530492 (value >> 16) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530493
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530494 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530495 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530496 (value >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530497
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530498 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530499 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530500 value & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530501}
502
503static int sitar_put_iir_band_audio_mixer(
504 struct snd_kcontrol *kcontrol,
505 struct snd_ctl_elem_value *ucontrol)
506{
507 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
508 int iir_idx = ((struct soc_multi_mixer_control *)
509 kcontrol->private_value)->reg;
510 int band_idx = ((struct soc_multi_mixer_control *)
511 kcontrol->private_value)->shift;
512
513 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
514 ucontrol->value.integer.value[0]);
515 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
516 ucontrol->value.integer.value[1]);
517 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
518 ucontrol->value.integer.value[2]);
519 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
520 ucontrol->value.integer.value[3]);
521 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
522 ucontrol->value.integer.value[4]);
523
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530524 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530525 "%s: IIR #%d band #%d b1 = 0x%x\n"
526 "%s: IIR #%d band #%d b2 = 0x%x\n"
527 "%s: IIR #%d band #%d a1 = 0x%x\n"
528 "%s: IIR #%d band #%d a2 = 0x%x\n",
529 __func__, iir_idx, band_idx,
530 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
531 __func__, iir_idx, band_idx,
532 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
533 __func__, iir_idx, band_idx,
534 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
535 __func__, iir_idx, band_idx,
536 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
537 __func__, iir_idx, band_idx,
538 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
539 return 0;
540}
541
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700542static const char * const sitar_ear_pa_gain_text[] = {"POS_6_DB",
543 "POS_2_DB", "NEG_2P5_DB", "NEG_12_DB"};
544
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530545static const struct soc_enum sitar_ear_pa_gain_enum[] = {
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700546 SOC_ENUM_SINGLE_EXT(4, sitar_ear_pa_gain_text),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530547};
548
549/*cut of frequency for high pass filter*/
550static const char *cf_text[] = {
551 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
552};
553
554static const struct soc_enum cf_dec1_enum =
555 SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
556
557static const struct soc_enum cf_rxmix1_enum =
558 SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
559
560static const struct snd_kcontrol_new sitar_snd_controls[] = {
561
562 SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
563 sitar_pa_gain_get, sitar_pa_gain_put),
564
565 SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
566 line_gain),
567 SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
568 line_gain),
569
570 SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
571 line_gain),
572 SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
573 line_gain),
574
575 SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
576 -84, 40, digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800577 SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
578 -84, 40, digital_gain),
579 SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
580 -84, 40, digital_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530581
582 SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
583 digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800584 SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
585 digital_gain),
586 SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
587 digital_gain),
588 SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
589 digital_gain),
590
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530591 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
592 40, digital_gain),
593 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
594 40, digital_gain),
595 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
596 40, digital_gain),
597 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
598 40, digital_gain),
599 SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
600 SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800601 SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530602
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700603 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
604 sitar_put_anc_slot),
605
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530606 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
607
608 SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
609
610 SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
611
612 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
613
614 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
615 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
616 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
617 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
618 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
619 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
620 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
621 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
622 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
623 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
624 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
625 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
626 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
627 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
628 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
629 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
630 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
631 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
632 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
633 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
634
635 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
636 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
637 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
638 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
639 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
640 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
641 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
642 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
643 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
644 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
645 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
646 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
647 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
648 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
649 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
650 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
651 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
652 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
653 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
654 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
655};
656
657static const char *rx_mix1_text[] = {
658 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
659 "RX5"
660};
661
662static const char *rx_dac1_text[] = {
663 "ZERO", "RX1", "RX2"
664};
665
666static const char *rx_dac2_text[] = {
667 "ZERO", "RX1",
668};
669
670static const char *rx_dac3_text[] = {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800671 "ZERO", "RX1", "INV_RX1", "RX2"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530672};
673
674static const char *rx_dac4_text[] = {
675 "ZERO", "ON"
676};
677
678static const char *sb_tx1_mux_text[] = {
679 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
680 "DEC1"
681};
682
683static const char *sb_tx2_mux_text[] = {
684 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
685 "DEC2"
686};
687
688static const char *sb_tx3_mux_text[] = {
689 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
690 "DEC3"
691};
692
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800693static const char *sb_tx4_mux_text[] = {
694 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
695 "DEC4"
696};
697
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530698static const char *sb_tx5_mux_text[] = {
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -0700699 "ZERO", "RMIX1", "RMIX2", "RMIX3", "DEC1", "DEC2", "DEC3", "DEC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530700};
701
702static const char *dec1_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700703 "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530704};
705
706static const char *dec2_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700707 "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530708};
709
710static const char *dec3_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -0700711 "ZERO", "DMIC3", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC2", "DMIC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530712};
713
714static const char *dec4_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -0700715 "ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530716};
717
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700718static const char const *anc_mux_text[] = {
719 "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
720 "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
721};
722
723static const char const *anc1_fb_mux_text[] = {
724 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
725};
726
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530727static const char const *iir_inp1_text[] = {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530728 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
729 "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
730};
731
732static const struct soc_enum rx_mix1_inp1_chain_enum =
733 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
734
735static const struct soc_enum rx_mix1_inp2_chain_enum =
736 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
737
738static const struct soc_enum rx2_mix1_inp1_chain_enum =
739 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
740
741static const struct soc_enum rx2_mix1_inp2_chain_enum =
742 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
743
744static const struct soc_enum rx3_mix1_inp1_chain_enum =
745 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
746
747static const struct soc_enum rx3_mix1_inp2_chain_enum =
748 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
749
750static const struct soc_enum rx_dac1_enum =
751 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
752
753static const struct soc_enum rx_dac2_enum =
754 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
755
756static const struct soc_enum rx_dac3_enum =
757 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
758
759static const struct soc_enum rx_dac4_enum =
760 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
761
762static const struct soc_enum sb_tx5_mux_enum =
763 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
764
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800765static const struct soc_enum sb_tx4_mux_enum =
766 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
767
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530768static const struct soc_enum sb_tx3_mux_enum =
769 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
770
771static const struct soc_enum sb_tx2_mux_enum =
772 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
773
774static const struct soc_enum sb_tx1_mux_enum =
775 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
776
777static const struct soc_enum dec1_mux_enum =
778 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
779
780static const struct soc_enum dec2_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800781 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530782
783static const struct soc_enum dec3_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800784 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530785
786static const struct soc_enum dec4_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800787 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530788
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700789static const struct soc_enum anc1_mux_enum =
790 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
791
792static const struct soc_enum anc2_mux_enum =
793 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
794
795static const struct soc_enum anc1_fb_mux_enum =
796 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
797
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530798static const struct soc_enum iir1_inp1_mux_enum =
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530799 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir_inp1_text);
800
801static const struct soc_enum iir2_inp1_mux_enum =
802 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ2_B1_CTL, 0, 16, iir_inp1_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530803
804static const struct snd_kcontrol_new rx_mix1_inp1_mux =
805 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
806
807static const struct snd_kcontrol_new rx_mix1_inp2_mux =
808 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
809
810static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
811 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
812
813static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
814 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
815
816static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
817 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
818
819static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
820 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
821
822static const struct snd_kcontrol_new rx_dac1_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800823 SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530824
825static const struct snd_kcontrol_new rx_dac2_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800826 SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530827
828static const struct snd_kcontrol_new rx_dac3_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800829 SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530830
831static const struct snd_kcontrol_new rx_dac4_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800832 SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530833
834static const struct snd_kcontrol_new sb_tx5_mux =
835 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
836
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800837static const struct snd_kcontrol_new sb_tx4_mux =
838 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
839
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530840static const struct snd_kcontrol_new sb_tx3_mux =
841 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
842
843static const struct snd_kcontrol_new sb_tx2_mux =
844 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
845
846static const struct snd_kcontrol_new sb_tx1_mux =
847 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
848
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530849static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
850 struct snd_ctl_elem_value *ucontrol)
851 {
852 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
853 struct snd_soc_dapm_widget *w = wlist->widgets[0];
854 struct snd_soc_codec *codec = w->codec;
855 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
856 unsigned int dec_mux, decimator;
857 char *dec_name = NULL;
858 char *widget_name = NULL;
859 char *temp;
860 u16 tx_mux_ctl_reg;
861 u8 adc_dmic_sel = 0x0;
862 int ret = 0;
863
864 if (ucontrol->value.enumerated.item[0] > e->max - 1)
865 return -EINVAL;
866
867 dec_mux = ucontrol->value.enumerated.item[0];
868
869 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
870 if (!widget_name)
871 return -ENOMEM;
872 temp = widget_name;
873
874 dec_name = strsep(&widget_name, " ");
875 widget_name = temp;
876 if (!dec_name) {
877 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
878 ret = -EINVAL;
879 goto out;
880 }
881
882 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
883 if (ret < 0) {
884 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
885 ret = -EINVAL;
886 goto out;
887 }
888
889 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
890 "dec_mux = %u\n", __func__, w->name, dec_name, decimator,
891 dec_mux);
892
893
894 switch (decimator) {
895 case 1:
896 case 2:
897 if ((dec_mux == 1) || (dec_mux == 6))
898 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
899 else
900 adc_dmic_sel = ADC_DMIC_SEL_ADC;
901 break;
902 case 3:
903 if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
904 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
905 else
906 adc_dmic_sel = ADC_DMIC_SEL_ADC;
907 break;
908 case 4:
909 if ((dec_mux == 1) || (dec_mux == 5)
910 || (dec_mux == 6) || (dec_mux == 7))
911 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
912 else
913 adc_dmic_sel = ADC_DMIC_SEL_ADC;
914 break;
915 default:
916 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
917 ret = -EINVAL;
918 goto out;
919 }
920
921 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
922
923 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
924
925 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
926out:
927 kfree(widget_name);
928 return ret;
929}
930
931#define WCD9304_DEC_ENUM(xname, xenum) \
932{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
933 .info = snd_soc_info_enum_double, \
934 .get = snd_soc_dapm_get_enum_double, \
935 .put = wcd9304_put_dec_enum, \
936 .private_value = (unsigned long)&xenum }
937
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530938static const struct snd_kcontrol_new dec1_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530939 WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530940
941static const struct snd_kcontrol_new dec2_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530942 WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530943
944static const struct snd_kcontrol_new dec3_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530945 WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530946
947static const struct snd_kcontrol_new dec4_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530948 WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530949
950static const struct snd_kcontrol_new iir1_inp1_mux =
951 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
952
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530953static const struct snd_kcontrol_new iir2_inp1_mux =
954 SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
955
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700956static const struct snd_kcontrol_new anc1_mux =
957 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
958
959static const struct snd_kcontrol_new anc2_mux =
960 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
961
962static const struct snd_kcontrol_new anc1_fb_mux =
963 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
964
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530965static const struct snd_kcontrol_new dac1_switch[] = {
966 SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
967};
968
Kuirong Wang906ac472012-07-09 12:54:44 -0700969static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
970 struct snd_ctl_elem_value *ucontrol)
971{
972 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
973 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
974
975 ucontrol->value.integer.value[0] = widget->value;
976 return 0;
977}
978
979static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
980 struct snd_ctl_elem_value *ucontrol)
981{
982 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
983 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
984 struct snd_soc_codec *codec = widget->codec;
985 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
986 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
987 struct soc_multi_mixer_control *mixer =
988 ((struct soc_multi_mixer_control *)kcontrol->private_value);
989 u32 dai_id = widget->shift;
990 u32 port_id = mixer->shift;
991 u32 enable = ucontrol->value.integer.value[0];
992
993 mutex_lock(&codec->mutex);
994
995 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
996 if (dai_id != AIF1_CAP) {
997 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
998 __func__);
999 mutex_unlock(&codec->mutex);
1000 return -EINVAL;
1001 }
1002 }
1003
1004 switch (dai_id) {
1005 case AIF1_CAP:
1006 if (enable && !(widget->value & 1 << port_id)) {
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001007 if (wcd9xxx_tx_vport_validation(
1008 vport_check_table[dai_id],
1009 port_id,
1010 sitar_p->dai)) {
Kuirong Wang906ac472012-07-09 12:54:44 -07001011 pr_info("%s: TX%u is used by other virtual port\n",
1012 __func__, port_id + 1);
1013 mutex_unlock(&codec->mutex);
1014 return -EINVAL;
1015 }
1016 widget->value |= 1 << port_id;
1017 list_add_tail(&core->tx_chs[port_id].list,
1018 &sitar_p->dai[dai_id].wcd9xxx_ch_list);
1019 } else if (!enable && (widget->value & 1 << port_id)) {
1020 widget->value &= ~(1<<port_id);
1021 list_del_init(&core->tx_chs[port_id].list);
1022 } else {
1023 if (enable)
1024 pr_info("%s: TX%u port is used by this virtual port\n",
1025 __func__, port_id + 1);
1026 else
1027 pr_info("%s: TX%u port is not used by this virtual port\n",
1028 __func__, port_id + 1);
1029 /* avoid update power function */
1030 mutex_unlock(&codec->mutex);
1031 return 0;
1032 }
1033 break;
1034 default:
1035 pr_err("Unknown AIF %d\n", dai_id);
1036 mutex_unlock(&codec->mutex);
1037 return -EINVAL;
1038 }
1039
1040 pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
1041 widget->name, widget->sname, widget->value, widget->shift);
1042 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1043 mutex_unlock(&codec->mutex);
1044 return 0;
1045}
1046
1047static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1048 struct snd_ctl_elem_value *ucontrol)
1049{
1050 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1051 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1052
1053 ucontrol->value.enumerated.item[0] = widget->value;
1054 return 0;
1055}
1056
1057static const char * const slim_rx_mux_text[] = {
1058 "ZERO", "AIF1_PB"
1059};
1060
1061static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1062 struct snd_ctl_elem_value *ucontrol)
1063{
1064 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1065 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1066 struct snd_soc_codec *codec = widget->codec;
1067 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
1068 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1069 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1070 u32 port_id = widget->shift;
1071
1072 widget->value = ucontrol->value.enumerated.item[0];
1073
1074 mutex_lock(&codec->mutex);
1075
1076 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1077 if (widget->value > 1) {
1078 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1079 __func__);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001080 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001081 }
1082 }
1083
1084 switch (widget->value) {
1085 case 0:
1086 list_del_init(&core->rx_chs[port_id].list);
1087 break;
1088 case 1:
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001089 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
1090 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list))
1091 goto pr_err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001092 list_add_tail(&core->rx_chs[port_id].list,
1093 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
1094 break;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001095 break;
Kuirong Wang906ac472012-07-09 12:54:44 -07001096 default:
1097 pr_err("Unknown AIF %d\n", widget->value);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001098 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001099 }
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001100
1101
Kuirong Wang906ac472012-07-09 12:54:44 -07001102 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001103
Kuirong Wang906ac472012-07-09 12:54:44 -07001104 mutex_unlock(&codec->mutex);
1105 return 0;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001106pr_err:
1107 pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
1108 __func__, port_id + 1);
1109err:
1110 mutex_unlock(&codec->mutex);
1111 return -EINVAL;
Kuirong Wang906ac472012-07-09 12:54:44 -07001112}
1113
1114static const struct soc_enum slim_rx_mux_enum =
1115 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1116
1117static const struct snd_kcontrol_new sitar_aif_pb_mux[SITAR_RX_MAX] = {
1118 SOC_DAPM_ENUM_EXT("SLIM RX1 MUX", slim_rx_mux_enum,
1119 slim_rx_mux_get, slim_rx_mux_put),
1120 SOC_DAPM_ENUM_EXT("SLIM RX2 MUX", slim_rx_mux_enum,
1121 slim_rx_mux_get, slim_rx_mux_put),
1122 SOC_DAPM_ENUM_EXT("SLIM RX3 MUX", slim_rx_mux_enum,
1123 slim_rx_mux_get, slim_rx_mux_put),
1124 SOC_DAPM_ENUM_EXT("SLIM RX4 MUX", slim_rx_mux_enum,
1125 slim_rx_mux_get, slim_rx_mux_put),
1126 SOC_DAPM_ENUM_EXT("SLIM RX5 MUX", slim_rx_mux_enum,
1127 slim_rx_mux_get, slim_rx_mux_put)
1128};
1129
1130static const struct snd_kcontrol_new sitar_aif_cap_mixer[SITAR_TX_MAX] = {
1131 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, SITAR_TX1, 1, 0,
1132 slim_tx_mixer_get, slim_tx_mixer_put),
1133 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, SITAR_TX2, 1, 0,
1134 slim_tx_mixer_get, slim_tx_mixer_put),
1135 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, SITAR_TX3, 1, 0,
1136 slim_tx_mixer_get, slim_tx_mixer_put),
1137 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, SITAR_TX4, 1, 0,
1138 slim_tx_mixer_get, slim_tx_mixer_put),
1139 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, SITAR_TX5, 1, 0,
1140 slim_tx_mixer_get, slim_tx_mixer_put),
1141};
1142
1143
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301144static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
1145 int enable)
1146{
1147 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1148
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301149 pr_debug("%s %d\n", __func__, enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301150
1151 if (enable) {
1152 sitar->adc_count++;
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001153 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL,
1154 0x02, 0x02);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301155 } else {
1156 sitar->adc_count--;
1157 if (!sitar->adc_count) {
1158 if (!sitar->mbhc_polling_active)
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001159 snd_soc_update_bits(codec,
1160 SITAR_A_CDC_CLK_OTHR_CTL, 0xE0, 0x0);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301161 }
1162 }
1163}
1164
1165static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
1166 struct snd_kcontrol *kcontrol, int event)
1167{
1168 struct snd_soc_codec *codec = w->codec;
1169 u16 adc_reg;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001170 u8 init_bit_shift;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301171
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301172 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301173
1174 if (w->reg == SITAR_A_TX_1_2_EN)
1175 adc_reg = SITAR_A_TX_1_2_TEST_CTL;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001176 else if (w->reg == SITAR_A_TX_3_EN)
1177 adc_reg = SITAR_A_TX_3_TEST_CTL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301178 else {
1179 pr_err("%s: Error, invalid adc register\n", __func__);
1180 return -EINVAL;
1181 }
1182
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001183 if (w->shift == 3)
1184 init_bit_shift = 6;
1185 else if (w->shift == 7)
1186 init_bit_shift = 7;
1187 else {
1188 pr_err("%s: Error, invalid init bit postion adc register\n",
1189 __func__);
1190 return -EINVAL;
1191 }
1192
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301193 switch (event) {
1194 case SND_SOC_DAPM_PRE_PMU:
1195 sitar_codec_enable_adc_block(codec, 1);
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001196 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1197 1 << init_bit_shift);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301198 break;
1199 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001200
1201 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1202
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301203 break;
1204 case SND_SOC_DAPM_POST_PMD:
1205 sitar_codec_enable_adc_block(codec, 0);
1206 break;
1207 }
1208 return 0;
1209}
1210
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001211static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
1212 struct snd_kcontrol *kcontrol, int event)
1213{
1214 struct snd_soc_codec *codec = w->codec;
1215
1216 pr_debug("%s %s %d\n", __func__, w->name, event);
1217
1218 switch (event) {
1219 case SND_SOC_DAPM_PRE_PMU:
1220 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1221 break;
1222
1223 case SND_SOC_DAPM_POST_PMD:
1224 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1225 break;
1226 }
1227 return 0;
1228}
1229
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001230static void sitar_enable_classg(struct snd_soc_codec *codec,
1231 bool enable)
1232{
1233
1234 if (enable) {
1235 snd_soc_update_bits(codec,
1236 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x00);
1237 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x00);
1238 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
1239 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
1240
1241 } else {
1242 snd_soc_update_bits(codec,
1243 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x10);
1244 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x03);
1245 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
1246 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
1247 }
1248}
1249
1250static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
1251{
1252 u8 hph_reg_val = 0;
1253 hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
1254
1255 return (hph_reg_val & 0x30) ? true : false;
1256}
1257
1258static bool sitar_is_line_pa_on(struct snd_soc_codec *codec)
1259{
1260 u8 line_reg_val = 0;
1261 line_reg_val = snd_soc_read(codec, SITAR_A_RX_LINE_CNP_EN);
1262
1263 return (line_reg_val & 0x03) ? true : false;
1264}
1265
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301266static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1267 struct snd_kcontrol *kcontrol, int event)
1268{
1269 struct snd_soc_codec *codec = w->codec;
1270 u16 lineout_gain_reg;
1271
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301272 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301273
1274 switch (w->shift) {
1275 case 0:
1276 lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
1277 break;
1278 case 1:
1279 lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
1280 break;
1281 default:
1282 pr_err("%s: Error, incorrect lineout register value\n",
1283 __func__);
1284 return -EINVAL;
1285 }
1286
1287 switch (event) {
1288 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001289 if (sitar_is_hph_pa_on(codec)) {
1290 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1291 0x20, 0x00);
1292 sitar_enable_classg(codec, false);
1293 } else {
1294 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1295 0x20, 0x20);
1296 sitar_enable_classg(codec, true);
1297 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001298 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301299 break;
1300 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001301 pr_debug("%s: sleeping 32 ms after %s PA turn on\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301302 __func__, w->name);
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001303 usleep_range(32000, 32000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301304 break;
1305 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001306 if (sitar_is_hph_pa_on(codec))
1307 sitar_enable_classg(codec, true);
1308 else
1309 sitar_enable_classg(codec, false);
1310
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001311 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301312 break;
1313 }
1314 return 0;
1315}
1316
1317static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1318 struct snd_kcontrol *kcontrol, int event)
1319{
1320 struct snd_soc_codec *codec = w->codec;
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301321 u16 tx_dmic_ctl_reg;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301322 u8 dmic_clk_sel, dmic_clk_en;
1323 unsigned int dmic;
1324 int ret;
1325
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001326 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301327 if (ret < 0) {
1328 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1329 return -EINVAL;
1330 }
1331
1332 switch (dmic) {
1333 case 1:
1334 case 2:
1335 dmic_clk_sel = 0x02;
1336 dmic_clk_en = 0x01;
1337 break;
1338 case 3:
1339 case 4:
1340 dmic_clk_sel = 0x08;
1341 dmic_clk_en = 0x04;
1342 break;
1343
1344 break;
1345
1346 default:
1347 pr_err("%s: Invalid DMIC Selection\n", __func__);
1348 return -EINVAL;
1349 }
1350
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301351 tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1352
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301353 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301354
1355 switch (event) {
1356 case SND_SOC_DAPM_PRE_PMU:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301357 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1358 dmic_clk_sel, dmic_clk_sel);
1359
1360 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1361
1362 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1363 dmic_clk_en, dmic_clk_en);
1364 break;
1365 case SND_SOC_DAPM_POST_PMD:
1366 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1367 dmic_clk_en, 0);
1368 break;
1369 }
1370 return 0;
1371}
1372
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001373static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
1374 struct snd_kcontrol *kcontrol, int event)
1375{
1376 struct snd_soc_codec *codec = w->codec;
1377 const char *filename;
1378 const struct firmware *fw;
1379 int i;
1380 int ret;
1381 int num_anc_slots;
1382 struct anc_header *anc_head;
1383 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1384 u32 anc_writes_size = 0;
1385 int anc_size_remaining;
1386 u32 *anc_ptr;
1387 u16 reg;
1388 u8 mask, val, old_val;
1389
1390 pr_debug("%s %d\n", __func__, event);
1391 switch (event) {
1392 case SND_SOC_DAPM_PRE_PMU:
1393
1394 /* Use the same firmware file as that of WCD9310,
1395 * since the register sequences are same for
1396 * WCD9310 and WCD9304
1397 */
1398 filename = "wcd9310/wcd9310_anc.bin";
1399
1400 ret = request_firmware(&fw, filename, codec->dev);
1401 if (ret != 0) {
1402 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1403 ret);
1404 return -ENODEV;
1405 }
1406
1407 if (fw->size < sizeof(struct anc_header)) {
1408 dev_err(codec->dev, "Not enough data\n");
1409 release_firmware(fw);
1410 return -ENOMEM;
1411 }
1412
1413 /* First number is the number of register writes */
1414 anc_head = (struct anc_header *)(fw->data);
1415 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1416 anc_size_remaining = fw->size - sizeof(struct anc_header);
1417 num_anc_slots = anc_head->num_anc_slots;
1418
1419 if (sitar->anc_slot >= num_anc_slots) {
1420 dev_err(codec->dev, "Invalid ANC slot selected\n");
1421 release_firmware(fw);
1422 return -EINVAL;
1423 }
1424
1425 for (i = 0; i < num_anc_slots; i++) {
1426
1427 if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
1428 dev_err(codec->dev, "Invalid register format\n");
1429 release_firmware(fw);
1430 return -EINVAL;
1431 }
1432 anc_writes_size = (u32)(*anc_ptr);
1433 anc_size_remaining -= sizeof(u32);
1434 anc_ptr += 1;
1435
1436 if (anc_writes_size * SITAR_PACKED_REG_SIZE
1437 > anc_size_remaining) {
1438 dev_err(codec->dev, "Invalid register format\n");
1439 release_firmware(fw);
1440 return -ENOMEM;
1441 }
1442
1443 if (sitar->anc_slot == i)
1444 break;
1445
1446 anc_size_remaining -= (anc_writes_size *
1447 SITAR_PACKED_REG_SIZE);
1448 anc_ptr += anc_writes_size;
1449 }
1450 if (i == num_anc_slots) {
1451 dev_err(codec->dev, "Selected ANC slot not present\n");
1452 release_firmware(fw);
1453 return -ENOMEM;
1454 }
1455
1456 for (i = 0; i < anc_writes_size; i++) {
1457 SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1458 mask, val);
1459 old_val = snd_soc_read(codec, reg);
1460 snd_soc_write(codec, reg, (old_val & ~mask) |
1461 (val & mask));
1462 }
1463
1464 release_firmware(fw);
1465
1466 /* For Sitar, it is required to enable both Feed-forward
1467 * and Feed back clocks to enable ANC
1468 */
1469 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
1470
1471 break;
1472
1473 case SND_SOC_DAPM_POST_PMD:
1474 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1475 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
1476 break;
1477 }
1478 return 0;
1479}
1480
1481
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301482static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
1483{
1484 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001485 int mbhc_state = sitar->mbhc_state;
1486
1487 pr_debug("%s: enter\n", __func__);
1488 if (!sitar->mbhc_polling_active) {
1489 pr_debug("Polling is not active, do not start polling\n");
1490 return;
1491 }
1492 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
1493
1494
1495 if (!sitar->no_mic_headset_override) {
1496 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1497 pr_debug("%s recovering MBHC state macine\n", __func__);
1498 sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
1499 /* set to max button press threshold */
1500 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
1501 0x7F);
1502 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
1503 0xFF);
1504 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
1505 0x7F);
1506 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
1507 0xFF);
1508 /* set to max */
1509 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
1510 0x7F);
1511 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
1512 0xFF);
1513 }
1514 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301515
1516 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001517 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
1518 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1519 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301520}
1521
1522static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
1523{
1524 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1525
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001526 pr_debug("%s: enter\n", __func__);
1527 if (!sitar->mbhc_polling_active) {
1528 pr_debug("polling not active, nothing to pause\n");
1529 return;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301530 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001531
1532 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1533 pr_debug("%s: leave\n", __func__);
1534
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301535}
1536
1537static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1538 int mode)
1539{
1540 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1541 u8 reg_mode_val, cur_mode_val;
1542 bool mbhc_was_polling = false;
1543
1544 if (mode)
1545 reg_mode_val = SITAR_CFILT_FAST_MODE;
1546 else
1547 reg_mode_val = SITAR_CFILT_SLOW_MODE;
1548
1549 cur_mode_val = snd_soc_read(codec,
1550 sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
1551
1552 if (cur_mode_val != reg_mode_val) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001553 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301554 if (sitar->mbhc_polling_active) {
1555 sitar_codec_pause_hs_polling(codec);
1556 mbhc_was_polling = true;
1557 }
1558 snd_soc_update_bits(codec,
1559 sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1560 if (mbhc_was_polling)
1561 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001562 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301563 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301564 cur_mode_val, reg_mode_val);
1565 } else {
1566 pr_err("%s: CFILT Value is already %x\n",
1567 __func__, cur_mode_val);
1568 }
1569}
1570
1571static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1572 u8 cfilt_sel, int inc)
1573{
1574 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1575 u32 *cfilt_cnt_ptr = NULL;
1576 u16 micb_cfilt_reg;
1577
1578 switch (cfilt_sel) {
1579 case SITAR_CFILT1_SEL:
1580 cfilt_cnt_ptr = &sitar->cfilt1_cnt;
1581 micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
1582 break;
1583 case SITAR_CFILT2_SEL:
1584 cfilt_cnt_ptr = &sitar->cfilt2_cnt;
1585 micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
1586 break;
1587 default:
1588 return; /* should not happen */
1589 }
1590
1591 if (inc) {
1592 if (!(*cfilt_cnt_ptr)++) {
1593 /* Switch CFILT to slow mode if MBHC CFILT being used */
1594 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1595 sitar_codec_switch_cfilt_mode(codec, 0);
1596
1597 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1598 }
1599 } else {
1600 /* check if count not zero, decrement
1601 * then check if zero, go ahead disable cfilter
1602 */
1603 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1604 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1605
1606 /* Switch CFILT to fast mode if MBHC CFILT being used */
1607 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1608 sitar_codec_switch_cfilt_mode(codec, 1);
1609 }
1610 }
1611}
1612
1613static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1614{
1615 int rc = -EINVAL;
1616 unsigned min_mv, max_mv;
1617
1618 switch (ldoh_v) {
1619 case SITAR_LDOH_1P95_V:
1620 min_mv = 160;
1621 max_mv = 1800;
1622 break;
1623 case SITAR_LDOH_2P35_V:
1624 min_mv = 200;
1625 max_mv = 2200;
1626 break;
1627 case SITAR_LDOH_2P75_V:
1628 min_mv = 240;
1629 max_mv = 2600;
1630 break;
1631 case SITAR_LDOH_2P85_V:
1632 min_mv = 250;
1633 max_mv = 2700;
1634 break;
1635 default:
1636 goto done;
1637 }
1638
1639 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1640 goto done;
1641
1642 for (rc = 4; rc <= 44; rc++) {
1643 min_mv = max_mv * (rc) / 44;
1644 if (min_mv >= cfilt_mv) {
1645 rc -= 4;
1646 break;
1647 }
1648 }
1649done:
1650 return rc;
1651}
1652
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301653static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1654{
1655 u8 hph_reg_val = 0;
1656 if (left)
1657 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001658 SITAR_A_RX_HPH_L_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301659 else
1660 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001661 SITAR_A_RX_HPH_R_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301662
1663 return (hph_reg_val & 0xC0) ? true : false;
1664}
1665
1666static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
1667 int vddio_switch)
1668{
1669 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1670 int cfilt_k_val;
1671 bool mbhc_was_polling = false;
1672
1673 switch (vddio_switch) {
1674 case 1:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001675 if (sitar->mbhc_micbias_switched == 0 &&
1676 sitar->mbhc_polling_active) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301677
1678 sitar_codec_pause_hs_polling(codec);
1679 /* Enable Mic Bias switch to VDDIO */
1680 sitar->cfilt_k_value = snd_soc_read(codec,
1681 sitar->mbhc_bias_regs.cfilt_val);
1682 cfilt_k_val = sitar_find_k_value(
1683 sitar->pdata->micbias.ldoh_v, 1800);
1684 snd_soc_update_bits(codec,
1685 sitar->mbhc_bias_regs.cfilt_val,
1686 0xFC, (cfilt_k_val << 2));
1687
1688 snd_soc_update_bits(codec,
1689 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1690 snd_soc_update_bits(codec,
1691 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1692 sitar_codec_start_hs_polling(codec);
1693
1694 sitar->mbhc_micbias_switched = true;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301695 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301696 __func__);
1697 }
1698 break;
1699
1700 case 0:
1701 if (sitar->mbhc_micbias_switched) {
1702 if (sitar->mbhc_polling_active) {
1703 sitar_codec_pause_hs_polling(codec);
1704 mbhc_was_polling = true;
1705 }
1706 /* Disable Mic Bias switch to VDDIO */
1707 if (sitar->cfilt_k_value != 0)
1708 snd_soc_update_bits(codec,
1709 sitar->mbhc_bias_regs.cfilt_val, 0XFC,
1710 sitar->cfilt_k_value);
1711 snd_soc_update_bits(codec,
1712 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1713 snd_soc_update_bits(codec,
1714 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1715
1716 if (mbhc_was_polling)
1717 sitar_codec_start_hs_polling(codec);
1718
1719 sitar->mbhc_micbias_switched = false;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301720 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301721 __func__);
1722 }
1723 break;
1724 }
1725}
1726
1727static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1728 struct snd_kcontrol *kcontrol, int event)
1729{
1730 struct snd_soc_codec *codec = w->codec;
1731 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1732 u16 micb_int_reg;
1733 int micb_line;
1734 u8 cfilt_sel_val = 0;
1735 char *internal1_text = "Internal1";
1736 char *internal2_text = "Internal2";
1737
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301738 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301739 switch (w->reg) {
1740 case SITAR_A_MICB_1_CTL:
1741 micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
1742 cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
1743 micb_line = SITAR_MICBIAS1;
1744 break;
1745 case SITAR_A_MICB_2_CTL:
1746 micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
1747 cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
1748 micb_line = SITAR_MICBIAS2;
1749 break;
1750 default:
1751 pr_err("%s: Error, invalid micbias register\n", __func__);
1752 return -EINVAL;
1753 }
1754
1755 switch (event) {
1756 case SND_SOC_DAPM_PRE_PMU:
1757 /* Decide whether to switch the micbias for MBHC */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001758 if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
1759 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301760 sitar_codec_switch_micbias(codec, 0);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001761 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1762 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301763
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001764 snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301765 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
1766
1767 if (strnstr(w->name, internal1_text, 30))
1768 snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
1769 else if (strnstr(w->name, internal2_text, 30))
1770 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1771 break;
1772 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001773
1774 usleep_range(20000, 20000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301775 if (sitar->mbhc_polling_active &&
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001776 sitar->mbhc_cfg.micbias == micb_line) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001777 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301778 sitar_codec_pause_hs_polling(codec);
1779 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001780 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301781 }
1782 break;
1783 case SND_SOC_DAPM_POST_PMD:
1784
1785 if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
1786 && sitar_is_hph_pa_on(codec))
1787 sitar_codec_switch_micbias(codec, 1);
1788
1789 if (strnstr(w->name, internal1_text, 30))
1790 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1791 else if (strnstr(w->name, internal2_text, 30))
1792 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1793 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
1794 break;
1795 }
1796
1797 return 0;
1798}
1799
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001800static void tx_hpf_corner_freq_callback(struct work_struct *work)
1801{
1802 struct delayed_work *hpf_delayed_work;
1803 struct hpf_work *hpf_work;
1804 struct sitar_priv *sitar;
1805 struct snd_soc_codec *codec;
1806 u16 tx_mux_ctl_reg;
1807 u8 hpf_cut_of_freq;
1808
1809 hpf_delayed_work = to_delayed_work(work);
1810 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1811 sitar = hpf_work->sitar;
1812 codec = hpf_work->sitar->codec;
1813 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1814
1815 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL +
1816 (hpf_work->decimator - 1) * 8;
1817
1818 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
1819 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1820
1821 snd_soc_update_bits(codec, tx_mux_ctl_reg,
1822 CUT_OF_FREQ_MASK, hpf_cut_of_freq << 4);
1823}
1824
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301825static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
1826 struct snd_kcontrol *kcontrol, int event)
1827{
1828 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001829 u16 dec_reset_reg, gain_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1830 unsigned int decimator;
1831 char *dec_name = NULL;
1832 char *widget_name = NULL;
1833 char *temp;
1834 int ret = 0;
1835 u8 dec_hpf_cut_of_freq, current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301836
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301837 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301838
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001839 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1840 if (!widget_name)
1841 return -ENOMEM;
1842 temp = widget_name;
1843
1844 dec_name = strsep(&widget_name, " ");
1845 widget_name = temp;
1846 if (!dec_name) {
1847 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1848 ret = -EINVAL;
1849 goto out;
1850 }
1851
1852 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1853 if (ret < 0) {
1854 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1855 ret = -EINVAL;
1856 goto out;
1857 }
1858
1859 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1860 w->name, dec_name, decimator);
1861
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301862 if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1863 dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
1864 else {
1865 pr_err("%s: Error, incorrect dec\n", __func__);
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001866 ret = EINVAL;
1867 goto out;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301868 }
1869
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001870 tx_vol_ctl_reg = SITAR_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
1871 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1872
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301873 switch (event) {
1874 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001875 /* Enable TX Digital Mute */
1876 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1877
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301878 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1879 1 << w->shift);
1880 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001881
1882 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1883 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq &
1884 CUT_OF_FREQ_MASK) >> 4;
1885
1886 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1887 dec_hpf_cut_of_freq;
1888
1889 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1890 /* Set cut off freq to CF_MIN_3DB_150HZ (0x01) */
1891 snd_soc_update_bits(codec, tx_mux_ctl_reg,
1892 CUT_OF_FREQ_MASK, CF_MIN_3DB_150HZ << 4);
1893 }
1894
1895 /* enable HPF */
1896 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
1897
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301898 break;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001899
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001900 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001901 /* Disable TX Digital Mute */
1902 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1903
1904 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1905 CF_MIN_3DB_150HZ) {
1906 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1907 msecs_to_jiffies(300));
1908 }
1909
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001910 /* Reprogram the digital gain after power up of Decimator */
1911 gain_reg = SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * w->shift);
1912 current_gain = snd_soc_read(codec, gain_reg);
1913 snd_soc_write(codec, gain_reg, current_gain);
1914 break;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001915
1916 case SND_SOC_DAPM_PRE_PMD:
1917 /* Enable Digital Mute, Cancel possibly scheduled work */
1918 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1919 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1920
1921 break;
1922
1923 case SND_SOC_DAPM_POST_PMD:
1924 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1925 snd_soc_update_bits(codec, tx_mux_ctl_reg, CUT_OF_FREQ_MASK,
1926 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1927 break;
1928
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301929 }
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07001930
1931out:
1932 kfree(widget_name);
1933 return ret;
1934
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301935}
1936
1937static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
1938 struct snd_kcontrol *kcontrol, int event)
1939{
1940 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001941 u16 gain_reg;
1942 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301943
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301944 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301945
1946 switch (event) {
1947 case SND_SOC_DAPM_PRE_PMU:
1948 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1949 1 << w->shift, 1 << w->shift);
1950 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1951 1 << w->shift, 0x0);
1952 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001953 case SND_SOC_DAPM_POST_PMU:
1954 /* Reprogram gain after power up interpolator */
1955 gain_reg = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * w->shift);
1956 current_gain = snd_soc_read(codec, gain_reg);
1957 snd_soc_write(codec, gain_reg, current_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301958 }
1959 return 0;
1960}
1961
1962static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1963 struct snd_kcontrol *kcontrol, int event)
1964{
1965 switch (event) {
1966 case SND_SOC_DAPM_POST_PMU:
1967 case SND_SOC_DAPM_POST_PMD:
1968 usleep_range(1000, 1000);
1969 pr_debug("LDO_H\n");
1970 break;
1971 }
1972 return 0;
1973}
1974
1975static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1976{
1977 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1978
1979 if (enable) {
1980 sitar->rx_bias_count++;
1981 if (sitar->rx_bias_count == 1)
1982 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1983 0x80, 0x80);
1984 } else {
1985 sitar->rx_bias_count--;
1986 if (!sitar->rx_bias_count)
1987 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1988 0x80, 0x00);
1989 }
1990}
1991
1992static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1993 struct snd_kcontrol *kcontrol, int event)
1994{
1995 struct snd_soc_codec *codec = w->codec;
1996
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301997 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301998
1999 switch (event) {
2000 case SND_SOC_DAPM_PRE_PMU:
2001 sitar_enable_rx_bias(codec, 1);
2002 break;
2003 case SND_SOC_DAPM_POST_PMD:
2004 sitar_enable_rx_bias(codec, 0);
2005 break;
2006 }
2007 return 0;
2008}
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002009static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302010 struct snd_kcontrol *kcontrol, int event)
2011{
2012 struct snd_soc_codec *codec = w->codec;
2013
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302014 pr_debug("%s %s %d\n", __func__, w->name, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302015
2016 switch (event) {
2017 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002018 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
2019 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2020 0x30, 0x20);
2021 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2022 0x0C, 0x08);
2023 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302024 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2025 break;
2026 case SND_SOC_DAPM_POST_PMD:
2027 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002028 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
2029 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2030 0x30, 0x10);
2031 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2032 0x0C, 0x04);
2033 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302034 break;
2035 }
2036 return 0;
2037}
2038
2039static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
2040 struct snd_soc_jack *jack, int status,
2041 int mask)
2042{
2043 /* XXX: wake_lock_timeout()? */
Laxminath Kasamc24dc6f2012-12-07 11:10:35 +05302044 snd_soc_jack_report_no_dapm(jack, status, mask);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302045}
2046
2047static void hphocp_off_report(struct sitar_priv *sitar,
2048 u32 jack_status, int irq)
2049{
2050 struct snd_soc_codec *codec;
2051
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002052 if (!sitar) {
2053 pr_err("%s: Bad sitar private data\n", __func__);
2054 return;
2055 }
2056
2057 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
2058 codec = sitar->codec;
2059 if (sitar->hph_status & jack_status) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302060 sitar->hph_status &= ~jack_status;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002061 if (sitar->mbhc_cfg.headset_jack)
2062 sitar_snd_soc_jack_report(sitar,
2063 sitar->mbhc_cfg.headset_jack,
2064 sitar->hph_status,
2065 SITAR_JACK_MASK);
2066 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2067 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302068 /* reset retry counter as PA is turned off signifying
2069 * start of new OCP detection session
2070 */
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002071 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302072 sitar->hphlocp_cnt = 0;
2073 else
2074 sitar->hphrocp_cnt = 0;
2075 wcd9xxx_enable_irq(codec->control_data, irq);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302076 }
2077}
2078
2079static void hphlocp_off_report(struct work_struct *work)
2080{
2081 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
2082 hphlocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002083 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
2084 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302085}
2086
2087static void hphrocp_off_report(struct work_struct *work)
2088{
2089 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
2090 hphrocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002091 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
2092 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302093}
2094
2095static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
2096 struct snd_kcontrol *kcontrol, int event)
2097{
2098 struct snd_soc_codec *codec = w->codec;
2099 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2100 u8 mbhc_micb_ctl_val;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302101 pr_debug("%s: event = %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302102
2103 switch (event) {
2104 case SND_SOC_DAPM_PRE_PMU:
2105 mbhc_micb_ctl_val = snd_soc_read(codec,
2106 sitar->mbhc_bias_regs.ctl_reg);
2107
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002108 if (!(mbhc_micb_ctl_val & 0x80)) {
2109 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302110 sitar_codec_switch_micbias(codec, 1);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002111 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
2112 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302113
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002114 if (sitar_is_line_pa_on(codec))
2115 sitar_enable_classg(codec, false);
2116 else
2117 sitar_enable_classg(codec, true);
2118
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302119 break;
2120
2121 case SND_SOC_DAPM_POST_PMD:
2122 /* schedule work is required because at the time HPH PA DAPM
2123 * event callback is called by DAPM framework, CODEC dapm mutex
2124 * would have been locked while snd_soc_jack_report also
2125 * attempts to acquire same lock.
2126 */
2127 if (w->shift == 5) {
2128 clear_bit(SITAR_HPHL_PA_OFF_ACK,
2129 &sitar->hph_pa_dac_state);
2130 clear_bit(SITAR_HPHL_DAC_OFF_ACK,
2131 &sitar->hph_pa_dac_state);
2132 if (sitar->hph_status & SND_JACK_OC_HPHL)
2133 schedule_work(&sitar->hphlocp_work);
2134 } else if (w->shift == 4) {
2135 clear_bit(SITAR_HPHR_PA_OFF_ACK,
2136 &sitar->hph_pa_dac_state);
2137 clear_bit(SITAR_HPHR_DAC_OFF_ACK,
2138 &sitar->hph_pa_dac_state);
2139 if (sitar->hph_status & SND_JACK_OC_HPHR)
2140 schedule_work(&sitar->hphrocp_work);
2141 }
2142
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002143 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
2144 sitar_codec_switch_micbias(codec, 0);
2145 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302146
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302147 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302148 w->name);
2149 usleep_range(10000, 10000);
2150
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002151 if (sitar_is_line_pa_on(codec))
2152 sitar_enable_classg(codec, true);
2153 else
2154 sitar_enable_classg(codec, false);
2155
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302156 break;
2157 }
2158 return 0;
2159}
2160
2161static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
2162 struct mbhc_micbias_regs *micbias_regs)
2163{
2164 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302165 unsigned int cfilt;
2166
Patrick Laia5062da2012-05-11 17:55:09 -07002167 switch (sitar->mbhc_cfg.micbias) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302168 case SITAR_MICBIAS1:
2169 cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
2170 micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
2171 micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
2172 micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
2173 break;
2174 case SITAR_MICBIAS2:
2175 cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
2176 micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
2177 micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
2178 micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
2179 break;
2180 default:
2181 /* Should never reach here */
2182 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
2183 return;
2184 }
2185
2186 micbias_regs->cfilt_sel = cfilt;
2187
2188 switch (cfilt) {
2189 case SITAR_CFILT1_SEL:
2190 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
2191 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002192 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302193 break;
2194 case SITAR_CFILT2_SEL:
2195 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
2196 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002197 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302198 break;
2199 }
2200}
2201
2202static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
2203 struct snd_kcontrol *kcontrol, int event)
2204{
2205 struct snd_soc_codec *codec = w->codec;
2206
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302207 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302208 switch (event) {
2209 case SND_SOC_DAPM_POST_PMU:
2210 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2211 0x01);
2212 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
2213 usleep_range(200, 200);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302214 break;
2215 case SND_SOC_DAPM_PRE_PMD:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302216 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002217 /*
2218 * This delay is for the class G controller to settle down
2219 * after turn OFF. The delay is as per the hardware spec for
2220 * the codec
2221 */
2222 usleep_range(20, 20);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302223 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2224 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302225 break;
2226 }
2227 return 0;
2228}
2229
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002230static int sitar_ear_pa_event(struct snd_soc_dapm_widget *w,
2231 struct snd_kcontrol *kcontrol, int event)
2232{
2233 switch (event) {
2234 case SND_SOC_DAPM_POST_PMU:
2235 pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
2236 __func__);
2237 msleep(20);
2238 break;
2239 case SND_SOC_DAPM_POST_PMD:
2240 pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
2241 __func__);
2242 msleep(20);
2243 break;
2244 }
2245 return 0;
2246}
2247
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302248static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
2249 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
2250 4, 0, NULL, 0),
2251 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
2252 0, NULL, 0),
2253};
2254
2255static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
2256 /*RX stuff */
2257 SND_SOC_DAPM_OUTPUT("EAR"),
2258
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002259 SND_SOC_DAPM_PGA_E("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0,
2260 sitar_ear_pa_event, SND_SOC_DAPM_POST_PMU |
2261 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302262 SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
2263 ARRAY_SIZE(dac1_switch)),
2264 SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07002265
2266 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
2267 AIF1_PB, 0, sitar_codec_enable_slimrx,
2268 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2269
2270 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, SITAR_RX1, 0,
2271 &sitar_aif_pb_mux[SITAR_RX1]),
2272 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, SITAR_RX2, 0,
2273 &sitar_aif_pb_mux[SITAR_RX2]),
2274 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, SITAR_RX3, 0,
2275 &sitar_aif_pb_mux[SITAR_RX3]),
2276 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, SITAR_RX4, 0,
2277 &sitar_aif_pb_mux[SITAR_RX4]),
2278 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, SITAR_RX5, 0,
2279 &sitar_aif_pb_mux[SITAR_RX5]),
2280
2281 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2282 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
2283 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
2284 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
2285 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302286
2287 /* Headphone */
2288 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2289 SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
2290 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2291 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302292
2293 SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
2294 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2295 SND_SOC_DAPM_POST_PMD),
2296
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002297 SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
2298 sitar_hph_dac_event,
2299 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302300 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002301 sitar_hph_dac_event,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302302 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2303
2304 /* Speaker */
2305 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
2306 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
2307
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002308 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
2309 , sitar_lineout_dac_event,
2310 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2311 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
2312 , sitar_lineout_dac_event,
2313 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2314
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302315 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
2316 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2317 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2318 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
2319 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2320 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2321
2322 SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002323 0, sitar_codec_reset_interpolator,
2324 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302325 SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002326 0, sitar_codec_reset_interpolator,
2327 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302328 SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002329 0, sitar_codec_reset_interpolator,
2330 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302331
2332 SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
2333 &rx_dac1_mux),
2334 SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
2335 &rx_dac2_mux),
2336 SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
2337 &rx_dac3_mux),
2338 SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
2339 &rx_dac4_mux),
2340
2341 SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
2342 SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
2343 SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
2344
2345 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2346 &rx_mix1_inp1_mux),
2347 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2348 &rx_mix1_inp2_mux),
2349 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2350 &rx2_mix1_inp1_mux),
2351 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2352 &rx2_mix1_inp2_mux),
2353 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2354 &rx3_mix1_inp1_mux),
2355 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2356 &rx3_mix1_inp2_mux),
2357
2358 SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
2359 sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2360 SND_SOC_DAPM_PRE_PMD),
2361 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2362 sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2363 SND_SOC_DAPM_POST_PMD),
2364
2365 SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
2366 sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2367 /* TX */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002368
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302369 SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2370 0),
2371 SND_SOC_DAPM_INPUT("AMIC1"),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002372 SND_SOC_DAPM_INPUT("AMIC2"),
2373 SND_SOC_DAPM_INPUT("AMIC3"),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302374 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
2375 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2376 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2377 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
2378 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2379 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2380
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302381 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
2382 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2383 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2384 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
2385 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2386 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2387 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
2388 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2389 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2390
2391 SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
2392 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2393 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2394 SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
2395 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2396 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002397 SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
2398 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2399 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302400
2401 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 -07002402 &dec1_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002403 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2404 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2405
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002406 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 -07002407 &dec2_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002408 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2409 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2410
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002411 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 -07002412 &dec3_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002413 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2414 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2415
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002416 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 -07002417 &dec4_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002418 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2419 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302420
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002421 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2422 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2423
2424 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2425 sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2426 SND_SOC_DAPM_POST_PMD),
2427
2428 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2429
Kuirong Wang906ac472012-07-09 12:54:44 -07002430 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
2431 AIF1_CAP, 0, sitar_codec_enable_slimtx,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302432 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2433
Kuirong Wang906ac472012-07-09 12:54:44 -07002434 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
2435 sitar_aif_cap_mixer, ARRAY_SIZE(sitar_aif_cap_mixer)),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302436
Kuirong Wang906ac472012-07-09 12:54:44 -07002437 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, SITAR_TX1, 0,
2438 &sb_tx1_mux),
2439 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, SITAR_TX2, 0,
2440 &sb_tx2_mux),
2441 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2442 &sb_tx3_mux),
2443 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2444 &sb_tx4_mux),
2445 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2446 &sb_tx5_mux),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302447
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002448 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
2449 0, sitar_codec_enable_slimtx,
2450 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2451
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302452 /* Digital Mic Inputs */
2453 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2454 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2455 SND_SOC_DAPM_POST_PMD),
2456 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2457 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2458 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302459 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2460 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2461 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302462 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2463 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2464 SND_SOC_DAPM_POST_PMD),
2465
2466 /* Sidetone */
2467 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2468 SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302469 SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
2470 SND_SOC_DAPM_PGA("IIR2", SITAR_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302471
2472};
2473
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302474static const struct snd_soc_dapm_route audio_i2s_map[] = {
2475 {"RX_I2S_CLK", NULL, "CP"},
2476 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2477 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2478 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2479 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2480 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2481
2482 {"SLIM TX1", NULL, "TX_I2S_CLK"},
2483 {"SLIM TX2", NULL, "TX_I2S_CLK"},
2484 {"SLIM TX3", NULL, "TX_I2S_CLK"},
2485 {"SLIM TX4", NULL, "TX_I2S_CLK"},
2486};
Kuirong Wang906ac472012-07-09 12:54:44 -07002487#define SLIM_MIXER(x) (\
2488 {x, "SLIM TX1", "SLIM TX1 MUX"}, \
2489 {x, "SLIM TX2", "SLIM TX2 MUX"}, \
2490 {x, "SLIM TX3", "SLIM TX3 MUX"}, \
2491 {x, "SLIM TX4", "SLIM TX4 MUX"})
2492
2493
2494#define SLIM_MUX(x, y) (\
2495 {"SLIM RX1 MUX", x, y}, \
2496 {"SLIM RX2 MUX", x, y}, \
2497 {"SLIM RX3 MUX", x, y}, \
2498 {"SLIM RX4 MUX", x, y})
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302499
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302500static const struct snd_soc_dapm_route audio_map[] = {
2501 /* Earpiece (RX MIX1) */
2502 {"EAR", NULL, "EAR PA"},
2503 {"EAR PA", "NULL", "DAC1"},
2504 {"DAC1", "Switch", "DAC1 MUX"},
2505 {"DAC1", NULL, "CP"},
2506 {"DAC1", NULL, "EAR DRIVER"},
2507
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002508 {"CP", NULL, "RX_BIAS"},
2509
2510 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2511 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302512
2513 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002514 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002515 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2516 {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302517
2518 {"LINEOUT1", NULL, "LINEOUT1 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002519 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002520 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2521 {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
2522
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002523 {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
2524 {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
2525 {"ANC", NULL, "ANC1 FB MUX"},
2526
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302527
2528 /* Headset (RX MIX1 and RX MIX2) */
2529 {"HEADPHONE", NULL, "HPHL"},
2530 {"HEADPHONE", NULL, "HPHR"},
2531
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002532
Patrick Lai9b250b72012-05-24 14:45:57 -07002533 {"HPHL DAC", NULL, "CP"},
2534 {"HPHR DAC", NULL, "CP"},
2535
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302536 {"HPHL", NULL, "HPHL DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002537 {"HPHL DAC", "NULL", "RX2 CHAIN"},
2538 {"RX2 CHAIN", NULL, "DAC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302539 {"HPHR", NULL, "HPHR DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002540 {"HPHR DAC", NULL, "RX3 CHAIN"},
2541 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302542
2543 {"DAC1 MUX", "RX1", "RX1 CHAIN"},
2544 {"DAC2 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002545
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302546 {"DAC3 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002547 {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302548 {"DAC3 MUX", "RX2", "RX2 MIX1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002549
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302550 {"DAC4 MUX", "ON", "RX2 MIX1"},
2551
2552 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2553
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302554 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2555 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2556 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2557 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2558 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2559 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2560
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002561 /* ANC */
2562 {"ANC", NULL, "ANC1 MUX"},
2563 {"ANC", NULL, "ANC2 MUX"},
2564 {"ANC1 MUX", "ADC1", "ADC1"},
2565 {"ANC1 MUX", "ADC2", "ADC2"},
2566 {"ANC1 MUX", "ADC3", "ADC3"},
2567 {"ANC2 MUX", "ADC1", "ADC1"},
2568 {"ANC2 MUX", "ADC2", "ADC2"},
2569 {"ANC2 MUX", "ADC3", "ADC3"},
2570
2571 {"ANC", NULL, "CDC_CONN"},
2572
2573 {"RX2 MIX1", NULL, "ANC"},
2574 {"RX3 MIX1", NULL, "ANC"},
2575
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302576 /* SLIMBUS Connections */
Kuirong Wang906ac472012-07-09 12:54:44 -07002577 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2578
2579 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2580 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2581 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2582 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2583 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2584 /* SLIM_MUX("AIF1_PB", "AIF1 PB"), */
2585 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2586 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2587 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2588 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2589
2590 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2591 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2592 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2593 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302594
2595 /* Slimbus port 5 is non functional in Sitar 1.0 */
2596 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2597 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2598 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2599 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2600 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302601 {"RX1 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302602 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2603 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2604 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2605 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2606 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302607 {"RX1 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302608 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2609 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2610 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2611 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2612 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302613 {"RX2 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302614 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2615 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2616 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2617 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2618 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302619 {"RX2 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302620 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2621 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2622 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2623 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2624 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302625 {"RX3 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302626 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2627 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2628 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2629 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2630 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302631 {"RX3 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302632
2633
2634 /* TX */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302635 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2636 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
2637 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002638 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002639 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
2640 {"SLIM TX5 MUX", "DEC2", "DEC2 MUX"},
2641 {"SLIM TX5 MUX", "DEC3", "DEC3 MUX"},
2642 {"SLIM TX5 MUX", "DEC4", "DEC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302643
2644 /* Decimator Inputs */
2645 {"DEC1 MUX", "DMIC1", "DMIC1"},
2646 {"DEC1 MUX", "DMIC4", "DMIC4"},
2647 {"DEC1 MUX", "ADC1", "ADC1"},
2648 {"DEC1 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002649 {"DEC1 MUX", "ADC3", "ADC3"},
2650 {"DEC1 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302651 {"DEC2 MUX", "DMIC2", "DMIC2"},
2652 {"DEC2 MUX", "DMIC3", "DMIC3"},
2653 {"DEC2 MUX", "ADC1", "ADC1"},
2654 {"DEC2 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002655 {"DEC2 MUX", "ADC3", "ADC3"},
2656 {"DEC2 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302657 {"DEC3 MUX", "DMIC3", "DMIC3"},
2658 {"DEC3 MUX", "ADC1", "ADC1"},
2659 {"DEC3 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002660 {"DEC3 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302661 {"DEC3 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07002662 {"DEC3 MUX", "DMIC4", "DMIC4"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002663 {"DEC3 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302664 {"DEC4 MUX", "DMIC4", "DMIC4"},
2665 {"DEC4 MUX", "ADC1", "ADC1"},
2666 {"DEC4 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002667 {"DEC4 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302668 {"DEC4 MUX", "DMIC3", "DMIC3"},
2669 {"DEC4 MUX", "DMIC2", "DMIC2"},
2670 {"DEC4 MUX", "DMIC1", "DMIC1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002671 {"DEC4 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302672
2673 /* ADC Connections */
2674 {"ADC1", NULL, "AMIC1"},
2675 {"ADC2", NULL, "AMIC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002676 {"ADC3", NULL, "AMIC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302677
2678 /* IIR */
2679 {"IIR1", NULL, "IIR1 INP1 MUX"},
2680 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302681 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2682 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2683 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2684 {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
2685 {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
2686 {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
2687 {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
2688 {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
2689
2690 {"IIR2", NULL, "IIR2 INP1 MUX"},
2691 {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
2692 {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
2693 {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
2694 {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
2695 {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
2696 {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
2697 {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
2698 {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
2699 {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
2700
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302701 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2702 {"MIC BIAS1 External", NULL, "LDO_H"},
2703 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2704 {"MIC BIAS2 External", NULL, "LDO_H"},
2705};
2706
2707static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
2708{
2709 return sitar_reg_readable[reg];
2710}
2711
2712static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2713{
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002714 int i;
2715
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302716 /* Registers lower than 0x100 are top level registers which can be
2717 * written by the Sitar core driver.
2718 */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302719 if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2720 return 1;
2721
2722 /* IIR Coeff registers are not cacheable */
2723 if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
2724 (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
2725 return 1;
2726
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002727 for (i = 0; i < NUM_DECIMATORS; i++) {
2728 if (reg == SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * i))
2729 return 1;
2730 }
2731
2732 for (i = 0; i < NUM_INTERPOLATORS; i++) {
2733 if (reg == SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * i))
2734 return 1;
2735 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302736 return 0;
2737}
2738
2739#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2740static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
2741 unsigned int value)
2742{
2743 int ret;
2744
Kuirong Wang906ac472012-07-09 12:54:44 -07002745 if (reg == SND_SOC_NOPM)
2746 return 0;
2747
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302748 BUG_ON(reg > SITAR_MAX_REGISTER);
2749
2750 if (!sitar_volatile(codec, reg)) {
2751 ret = snd_soc_cache_write(codec, reg, value);
2752 if (ret != 0)
2753 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2754 reg, ret);
2755 }
2756
2757 return wcd9xxx_reg_write(codec->control_data, reg, value);
2758}
2759static unsigned int sitar_read(struct snd_soc_codec *codec,
2760 unsigned int reg)
2761{
2762 unsigned int val;
2763 int ret;
2764
Kuirong Wang906ac472012-07-09 12:54:44 -07002765 if (reg == SND_SOC_NOPM)
2766 return 0;
2767
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302768 BUG_ON(reg > SITAR_MAX_REGISTER);
2769
2770 if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
2771 reg < codec->driver->reg_cache_size) {
2772 ret = snd_soc_cache_read(codec, reg, &val);
2773 if (ret >= 0) {
2774 return val;
2775 } else
2776 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2777 reg, ret);
2778 }
2779
2780 val = wcd9xxx_reg_read(codec->control_data, reg);
2781 return val;
2782}
2783
2784static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2785{
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002786 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302787
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002788 if (SITAR_IS_1P0(sitar_core->version))
2789 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
2790
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002791 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302792 usleep_range(1000, 1000);
2793 snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
2794 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2795 0x80);
2796 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
2797 0x04);
2798 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
2799 0x01);
2800 usleep_range(1000, 1000);
2801 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2802 0x00);
2803}
2804
2805static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
2806 enum sitar_bandgap_type choice)
2807{
2808 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002809 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302810
2811 /* TODO lock resources accessed by audio streams and threaded
2812 * interrupt handlers
2813 */
2814
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302815 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302816 sitar->bandgap_type);
2817
2818 if (sitar->bandgap_type == choice)
2819 return;
2820
2821 if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
2822 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2823 sitar_codec_enable_audio_mode_bandgap(codec);
2824 } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
Bhalchandra Gajare7708ee32012-05-24 17:37:37 -07002825 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302826 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
2827 0x2);
2828 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2829 0x80);
2830 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
2831 0x4);
2832 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
2833 0x1);
2834 usleep_range(1000, 1000);
2835 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2836 0x00);
2837 } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
2838 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2839 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
2840 usleep_range(100, 100);
2841 sitar_codec_enable_audio_mode_bandgap(codec);
2842 } else if (choice == SITAR_BANDGAP_OFF) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002843 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302844 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002845 if (SITAR_IS_1P0(sitar_core->version))
2846 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
Asish Bhattacharya63032b42012-08-16 20:57:01 +05302847 0xF3, 0x61);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002848 usleep_range(1000, 1000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302849 } else {
2850 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2851 }
2852 sitar->bandgap_type = choice;
2853}
2854
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002855static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
2856 int enable)
2857{
2858 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2859
2860 if (enable) {
2861 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
2862 snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
2863 usleep_range(5, 5);
2864 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
2865 0x80);
2866 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
2867 0x80);
2868 usleep_range(10, 10);
2869 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
2870 usleep_range(20, 20);
2871 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
2872 } else {
2873 snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
2874 0);
2875 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
2876 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2877 }
2878 sitar->config_mode_active = enable ? true : false;
2879
2880 return 0;
2881}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302882
2883static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
2884 int config_mode)
2885{
2886 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2887
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302888 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302889
2890 if (config_mode) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002891 sitar_codec_enable_config_mode(codec, 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302892 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
2893 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2894 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
2895 usleep_range(1000, 1000);
2896 } else
2897 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2898
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002899 if (!config_mode && sitar->mbhc_polling_active) {
2900 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2901 sitar_codec_enable_config_mode(codec, 0);
2902
2903 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302904
2905 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
2906 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
2907 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302908 usleep_range(50, 50);
2909 sitar->clock_active = true;
2910 return 0;
2911}
2912static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
2913{
2914 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302915 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302916 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
2917 ndelay(160);
2918 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
2919 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
2920 sitar->clock_active = false;
2921}
2922
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002923static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
2924{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002925 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002926 return 0;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002927 else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002928 return 1;
2929 else {
2930 BUG_ON(1);
2931 return -EINVAL;
2932 }
2933}
2934
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302935static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2936{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002937 u8 *n_ready, *n_cic;
2938 struct sitar_mbhc_btn_detect_cfg *btn_det;
2939 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302940
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002941 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302942
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002943 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
2944 sitar->mbhc_data.v_ins_hu & 0xFF);
2945 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
2946 (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302947
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002948 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
2949 sitar->mbhc_data.v_b1_hu & 0xFF);
2950 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
2951 (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
2952
2953 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
2954 sitar->mbhc_data.v_b1_h & 0xFF);
2955 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
2956 (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
2957
2958 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
2959 sitar->mbhc_data.v_brh & 0xFF);
2960 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
2961 (sitar->mbhc_data.v_brh >> 8) & 0xFF);
2962
2963 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
2964 sitar->mbhc_data.v_brl & 0xFF);
2965 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
2966 (sitar->mbhc_data.v_brl >> 8) & 0xFF);
2967
2968 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
2969 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
2970 n_ready[sitar_codec_mclk_index(sitar)]);
2971 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
2972 sitar->mbhc_data.npoll);
2973 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
2974 sitar->mbhc_data.nbounce_wait);
2975 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
2976 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
2977 n_cic[sitar_codec_mclk_index(sitar)]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302978}
2979
2980static int sitar_startup(struct snd_pcm_substream *substream,
2981 struct snd_soc_dai *dai)
2982{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08002983 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
2984 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
2985 (wcd9xxx->dev->parent != NULL))
2986 pm_runtime_get_sync(wcd9xxx->dev->parent);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302987 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302988 substream->name, substream->stream);
2989
2990 return 0;
2991}
2992
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07002993static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
2994{
2995 if (sitar->dev != NULL &&
2996 sitar->dev->parent != NULL) {
2997 pm_runtime_mark_last_busy(sitar->dev->parent);
2998 pm_runtime_put(sitar->dev->parent);
2999 }
3000}
3001
3002static void sitar_shutdown(struct snd_pcm_substream *substream,
3003 struct snd_soc_dai *dai)
3004{
3005 struct wcd9xxx *sitar_core = dev_get_drvdata(dai->codec->dev->parent);
3006 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3007 u32 active = 0;
3008
3009 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3010 substream->name, substream->stream);
3011 if (sitar->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3012 return;
3013
3014 if (dai->id <= NUM_CODEC_DAIS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003015 if (sitar->dai[dai->id].ch_mask) {
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003016 active = 1;
Joonwoo Park9bbb4d12012-11-09 19:58:11 -08003017 pr_debug("%s(): Codec DAI: chmask[%d] = 0x%lx\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003018 __func__, dai->id,
3019 sitar->dai[dai->id].ch_mask);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003020 }
3021 }
3022
3023 if (sitar_core != NULL && active == 0)
3024 sitar_codec_pm_runtime_put(sitar_core);
3025}
3026
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003027int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303028{
3029 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3030
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303031 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303032
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003033 if (dapm)
3034 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303035 if (mclk_enable) {
3036 sitar->mclk_enabled = true;
3037
3038 if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
3039 sitar_codec_pause_hs_polling(codec);
3040 sitar_codec_enable_bandgap(codec,
3041 SITAR_BANDGAP_AUDIO_MODE);
3042 sitar_codec_enable_clock_block(codec, 0);
3043 sitar_codec_calibrate_hs_polling(codec);
3044 sitar_codec_start_hs_polling(codec);
3045 } else {
3046 sitar_codec_enable_bandgap(codec,
3047 SITAR_BANDGAP_AUDIO_MODE);
3048 sitar_codec_enable_clock_block(codec, 0);
3049 }
3050 } else {
3051
3052 if (!sitar->mclk_enabled) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003053 if (dapm)
3054 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303055 pr_err("Error, MCLK already diabled\n");
3056 return -EINVAL;
3057 }
3058 sitar->mclk_enabled = false;
3059
3060 if (sitar->mbhc_polling_active) {
3061 if (!sitar->mclk_enabled) {
3062 sitar_codec_pause_hs_polling(codec);
3063 sitar_codec_enable_bandgap(codec,
3064 SITAR_BANDGAP_MBHC_MODE);
3065 sitar_enable_rx_bias(codec, 1);
3066 sitar_codec_enable_clock_block(codec, 1);
3067 sitar_codec_calibrate_hs_polling(codec);
3068 sitar_codec_start_hs_polling(codec);
3069 }
3070 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
3071 0x05, 0x01);
3072 } else {
3073 sitar_codec_disable_clock_block(codec);
3074 sitar_codec_enable_bandgap(codec,
3075 SITAR_BANDGAP_OFF);
3076 }
3077 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003078 if (dapm)
3079 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303080 return 0;
3081}
3082
3083static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
3084 int clk_id, unsigned int freq, int dir)
3085{
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303086 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303087 return 0;
3088}
3089
3090static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3091{
3092 u8 val = 0;
3093 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3094
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303095 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303096 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3097 case SND_SOC_DAIFMT_CBS_CFS:
3098 /* CPU is master */
3099 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3100 if (dai->id == AIF1_CAP)
3101 snd_soc_update_bits(dai->codec,
3102 SITAR_A_CDC_CLK_TX_I2S_CTL,
3103 SITAR_I2S_MASTER_MODE_MASK, 0);
3104 else if (dai->id == AIF1_PB)
3105 snd_soc_update_bits(dai->codec,
3106 SITAR_A_CDC_CLK_RX_I2S_CTL,
3107 SITAR_I2S_MASTER_MODE_MASK, 0);
3108 }
3109 break;
3110 case SND_SOC_DAIFMT_CBM_CFM:
3111 /* CPU is slave */
3112 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3113 val = SITAR_I2S_MASTER_MODE_MASK;
3114 if (dai->id == AIF1_CAP)
3115 snd_soc_update_bits(dai->codec,
3116 SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
3117 else if (dai->id == AIF1_PB)
3118 snd_soc_update_bits(dai->codec,
3119 SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
3120 }
3121 break;
3122 default:
3123 return -EINVAL;
3124 }
3125 return 0;
3126}
3127static int sitar_set_channel_map(struct snd_soc_dai *dai,
3128 unsigned int tx_num, unsigned int *tx_slot,
3129 unsigned int rx_num, unsigned int *rx_slot)
3130
3131{
3132 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003133 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303134 if (!tx_slot && !rx_slot) {
3135 pr_err("%s: Invalid\n", __func__);
3136 return -EINVAL;
3137 }
3138 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3139
Kuirong Wang906ac472012-07-09 12:54:44 -07003140 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3141 wcd9xxx_init_slimslave(core, core->slim->laddr,
3142 tx_num, tx_slot, rx_num, rx_slot);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303143 return 0;
3144}
3145
3146static int sitar_get_channel_map(struct snd_soc_dai *dai,
3147 unsigned int *tx_num, unsigned int *tx_slot,
3148 unsigned int *rx_num, unsigned int *rx_slot)
3149
3150{
Kuirong Wang906ac472012-07-09 12:54:44 -07003151 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(dai->codec);
3152 u32 i = 0;
3153 struct wcd9xxx_ch *ch;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303154
Kuirong Wang906ac472012-07-09 12:54:44 -07003155 switch (dai->id) {
3156 case AIF1_PB:
3157 if (!rx_slot || !rx_num) {
3158 pr_err("%s: Invalid rx_slot 0x%x or rx_num 0x%x\n",
3159 __func__, (u32) rx_slot, (u32) rx_num);
3160 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303161 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003162 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3163 list) {
3164 rx_slot[i++] = ch->ch_num;
3165 }
3166 *rx_num = i;
3167 break;
3168 case AIF1_CAP:
3169 if (!tx_slot || !tx_num) {
3170 pr_err("%s: Invalid tx_slot 0x%x or tx_num 0x%x\n",
3171 __func__, (u32) tx_slot, (u32) tx_num);
3172 return -EINVAL;
3173 }
3174 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3175 list) {
3176 tx_slot[i++] = ch->ch_num;
3177 }
3178 *tx_num = i;
3179 break;
3180 default:
3181 pr_err("%s: Invalid dai %d", __func__, dai->id);
3182 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303183 }
3184 return 0;
3185}
3186
3187static int sitar_hw_params(struct snd_pcm_substream *substream,
3188 struct snd_pcm_hw_params *params,
3189 struct snd_soc_dai *dai)
3190{
3191 struct snd_soc_codec *codec = dai->codec;
3192 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3193 u8 path, shift;
3194 u16 tx_fs_reg, rx_fs_reg;
3195 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
3196
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303197 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303198
3199 switch (params_rate(params)) {
3200 case 8000:
3201 tx_fs_rate = 0x00;
3202 rx_fs_rate = 0x00;
3203 break;
3204 case 16000:
3205 tx_fs_rate = 0x01;
3206 rx_fs_rate = 0x20;
3207 break;
3208 case 32000:
3209 tx_fs_rate = 0x02;
3210 rx_fs_rate = 0x40;
3211 break;
3212 case 48000:
3213 tx_fs_rate = 0x03;
3214 rx_fs_rate = 0x60;
3215 break;
3216 default:
3217 pr_err("%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07003218 params_rate(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303219 return -EINVAL;
3220 }
3221
3222
3223 /**
3224 * If current dai is a tx dai, set sample rate to
3225 * all the txfe paths that are currently not active
3226 */
3227 if (dai->id == AIF1_CAP) {
3228
3229 tx_state = snd_soc_read(codec,
3230 SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3231
3232 for (path = 1, shift = 0;
3233 path <= NUM_DECIMATORS; path++, shift++) {
3234
3235 if (!(tx_state & (1 << shift))) {
3236 tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
3237 + (BITS_PER_REG*(path-1));
3238 snd_soc_update_bits(codec, tx_fs_reg,
3239 0x03, tx_fs_rate);
3240 }
3241 }
3242 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3243 switch (params_format(params)) {
3244 case SNDRV_PCM_FORMAT_S16_LE:
3245 snd_soc_update_bits(codec,
3246 SITAR_A_CDC_CLK_TX_I2S_CTL,
3247 0x20, 0x20);
3248 break;
3249 case SNDRV_PCM_FORMAT_S32_LE:
3250 snd_soc_update_bits(codec,
3251 SITAR_A_CDC_CLK_TX_I2S_CTL,
3252 0x20, 0x00);
3253 break;
3254 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003255 pr_err("%s: Unsupport format %d\n", __func__,
3256 params_format(params));
3257 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303258 }
3259 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
3260 0x03, tx_fs_rate);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303261 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003262 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303263 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303264 }
3265
3266 /**
3267 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3268 * with varying sample rates
3269 */
3270
3271 /**
3272 * If current dai is a rx dai, set sample rate to
3273 * all the rx paths that are currently not active
3274 */
3275 if (dai->id == AIF1_PB) {
3276
3277 rx_state = snd_soc_read(codec,
3278 SITAR_A_CDC_CLK_RX_B1_CTL);
3279
3280 for (path = 1, shift = 0;
3281 path <= NUM_INTERPOLATORS; path++, shift++) {
3282
3283 if (!(rx_state & (1 << shift))) {
3284 rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
3285 + (BITS_PER_REG*(path-1));
3286 snd_soc_update_bits(codec, rx_fs_reg,
3287 0xE0, rx_fs_rate);
3288 }
3289 }
3290 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3291 switch (params_format(params)) {
3292 case SNDRV_PCM_FORMAT_S16_LE:
3293 snd_soc_update_bits(codec,
3294 SITAR_A_CDC_CLK_RX_I2S_CTL,
3295 0x20, 0x20);
3296 break;
3297 case SNDRV_PCM_FORMAT_S32_LE:
3298 snd_soc_update_bits(codec,
3299 SITAR_A_CDC_CLK_RX_I2S_CTL,
3300 0x20, 0x00);
3301 break;
3302 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003303 pr_err("%s: Unsupport format %d\n", __func__,
3304 params_format(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303305 break;
3306 }
3307 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
3308 0x03, (rx_fs_rate >> 0x05));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303309 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003310 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303311 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303312 }
3313
3314 return 0;
3315}
3316
3317static struct snd_soc_dai_ops sitar_dai_ops = {
3318 .startup = sitar_startup,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003319 .shutdown = sitar_shutdown,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303320 .hw_params = sitar_hw_params,
3321 .set_sysclk = sitar_set_dai_sysclk,
3322 .set_fmt = sitar_set_dai_fmt,
3323 .set_channel_map = sitar_set_channel_map,
3324 .get_channel_map = sitar_get_channel_map,
3325};
3326
3327static struct snd_soc_dai_driver sitar_dai[] = {
3328 {
3329 .name = "sitar_rx1",
3330 .id = AIF1_PB,
3331 .playback = {
3332 .stream_name = "AIF1 Playback",
3333 .rates = WCD9304_RATES,
3334 .formats = SITAR_FORMATS,
3335 .rate_max = 48000,
3336 .rate_min = 8000,
3337 .channels_min = 1,
3338 .channels_max = 2,
3339 },
3340 .ops = &sitar_dai_ops,
3341 },
3342 {
3343 .name = "sitar_tx1",
3344 .id = AIF1_CAP,
3345 .capture = {
3346 .stream_name = "AIF1 Capture",
3347 .rates = WCD9304_RATES,
3348 .formats = SITAR_FORMATS,
3349 .rate_max = 48000,
3350 .rate_min = 8000,
3351 .channels_min = 1,
3352 .channels_max = 2,
3353 },
3354 .ops = &sitar_dai_ops,
3355 },
3356};
3357
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303358static struct snd_soc_dai_driver sitar_i2s_dai[] = {
3359 {
3360 .name = "sitar_i2s_rx1",
3361 .id = AIF1_PB,
3362 .playback = {
3363 .stream_name = "AIF1 Playback",
3364 .rates = WCD9304_RATES,
3365 .formats = SITAR_FORMATS,
3366 .rate_max = 192000,
3367 .rate_min = 8000,
3368 .channels_min = 1,
3369 .channels_max = 4,
3370 },
3371 .ops = &sitar_dai_ops,
3372 },
3373 {
3374 .name = "sitar_i2s_tx1",
3375 .id = AIF1_CAP,
3376 .capture = {
3377 .stream_name = "AIF1 Capture",
3378 .rates = WCD9304_RATES,
3379 .formats = SITAR_FORMATS,
3380 .rate_max = 192000,
3381 .rate_min = 8000,
3382 .channels_min = 1,
3383 .channels_max = 4,
3384 },
3385 .ops = &sitar_dai_ops,
3386 },
3387};
3388
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003389static int sitar_codec_enable_chmask(struct sitar_priv *sitar,
3390 int event, int index)
3391{
Kuirong Wang906ac472012-07-09 12:54:44 -07003392 int ret = 0;
3393 struct wcd9xxx_ch *ch;
3394
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003395 switch (event) {
3396 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003397 list_for_each_entry(ch,
3398 &sitar->dai[index].wcd9xxx_ch_list, list) {
3399 ret = wcd9xxx_get_slave_port(ch->ch_num);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003400 if (ret < 0) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003401 pr_err("%s: Invalid slave port ID: %d\n",
3402 __func__, ret);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003403 ret = -EINVAL;
3404 break;
3405 }
3406 sitar->dai[index].ch_mask |= 1 << ret;
3407 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003408 break;
3409 case SND_SOC_DAPM_POST_PMD:
3410 ret = wait_event_timeout(sitar->dai[index].dai_wait,
3411 (sitar->dai[index].ch_mask == 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07003412 msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003413 if (!ret) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003414 pr_err("%s: Slim close tx/rx wait timeout\n",
3415 __func__);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003416 ret = -EINVAL;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003417 } else {
3418 ret = 0;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003419 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003420 break;
3421 }
3422 return ret;
3423}
3424
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303425static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3426 struct snd_kcontrol *kcontrol, int event)
3427{
Kuirong Wang906ac472012-07-09 12:54:44 -07003428 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303429 struct snd_soc_codec *codec = w->codec;
3430 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003431 int ret = 0;
3432 struct wcd9xxx_codec_dai_data *dai;
3433
3434 core = dev_get_drvdata(codec->dev->parent);
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003435
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303436 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003437 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003438 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3439 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303440 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003441 }
3442
Kuirong Wang906ac472012-07-09 12:54:44 -07003443 dai = &sitar_p->dai[w->shift];
3444
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303445 switch (event) {
3446 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003447 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3448 w->shift);
3449 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3450 dai->rate, dai->bit_width,
3451 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303452 break;
3453 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003454 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3455 dai->grph);
3456 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3457 w->shift);
3458 if (ret < 0) {
3459 ret = wcd9xxx_disconnect_port(core,
3460 &dai->wcd9xxx_ch_list,
3461 dai->grph);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003462 pr_info("%s: Disconnect RX port ret = %d\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003463 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303464 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003465 if (core != NULL)
3466 sitar_codec_pm_runtime_put(core);
3467 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303468 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003469 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303470}
3471
3472static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3473 struct snd_kcontrol *kcontrol, int event)
3474{
Kuirong Wang906ac472012-07-09 12:54:44 -07003475 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303476 struct snd_soc_codec *codec = w->codec;
3477 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003478 struct wcd9xxx_codec_dai_data *dai;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003479 int ret = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303480
Kuirong Wang906ac472012-07-09 12:54:44 -07003481 core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303482
3483 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003484 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003485 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3486 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303487 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003488 }
3489
Kuirong Wang906ac472012-07-09 12:54:44 -07003490 dai = &sitar_p->dai[w->shift];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303491 switch (event) {
3492 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003493 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3494 w->shift);
3495 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3496 dai->rate, dai->bit_width,
3497 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303498 break;
3499 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003500 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3501 dai->grph);
3502 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3503 w->shift);
3504 if (ret < 0) {
3505 ret = wcd9xxx_disconnect_port(core,
3506 &dai->wcd9xxx_ch_list,
3507 dai->grph);
3508 pr_info("%s: Disconnect RX port ret = %d\n",
3509 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303510 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003511 if (core != NULL)
3512 sitar_codec_pm_runtime_put(core);
3513 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303514 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003515 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303516}
3517
3518
3519static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
3520{
3521 u8 bias_msb, bias_lsb;
3522 short bias_value;
3523
3524 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
3525 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
3526 bias_value = (bias_msb << 8) | bias_lsb;
3527 return bias_value;
3528}
3529
3530static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
3531{
3532 u8 bias_msb, bias_lsb;
3533 short bias_value;
3534
3535 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
3536 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
3537 bias_value = (bias_msb << 8) | bias_lsb;
3538 return bias_value;
3539}
3540
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003541static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
3542 bool on)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303543{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003544 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
3545}
3546
3547static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3548 bool override_bypass, bool noreldetection)
3549{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303550 short bias_value;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003551 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3552
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003553 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003554 if (noreldetection)
3555 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303556
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003557 /* Turn on the override */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003558 if (!override_bypass)
3559 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303560 if (dce) {
3561 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3562 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
3563 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003564 usleep_range(sitar->mbhc_data.t_sta_dce,
3565 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303566 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003567 usleep_range(sitar->mbhc_data.t_dce,
3568 sitar->mbhc_data.t_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303569 bias_value = sitar_codec_read_dce_result(codec);
3570 } else {
3571 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3572 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
3573 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003574 usleep_range(sitar->mbhc_data.t_sta_dce,
3575 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303576 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003577 usleep_range(sitar->mbhc_data.t_sta,
3578 sitar->mbhc_data.t_sta);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303579 bias_value = sitar_codec_read_sta_result(codec);
3580 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3581 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
3582 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003583 /* Turn off the override after measuring mic voltage */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003584 if (!override_bypass)
3585 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3586
3587 if (noreldetection)
3588 sitar_turn_onoff_rel_detection(codec, true);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003589 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303590
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303591 return bias_value;
3592}
3593
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003594static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3595 bool norel)
3596{
3597 return __sitar_codec_sta_dce(codec, dce, false, norel);
3598}
3599
3600static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3601{
3602 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3603 const struct sitar_mbhc_general_cfg *generic =
3604 SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3605
3606 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
3607 sitar_codec_enable_config_mode(codec, 1);
3608
3609 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3610 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
3611
3612 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
3613
3614 usleep_range(generic->t_shutdown_plug_rem,
3615 generic->t_shutdown_plug_rem);
3616
3617 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
3618 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
3619 sitar_codec_enable_config_mode(codec, 0);
3620
3621 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
3622}
3623
3624static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
3625{
3626 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3627
3628 sitar_codec_shutdown_hs_removal_detect(codec);
3629
3630 if (!sitar->mclk_enabled) {
3631 sitar_codec_disable_clock_block(codec);
3632 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
3633 }
3634
3635 sitar->mbhc_polling_active = false;
3636 sitar->mbhc_state = MBHC_STATE_NONE;
3637}
3638
3639/* called only from interrupt which is under codec_resource_lock acquisition */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303640static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
3641{
3642 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303643 short bias_value;
3644 u8 cfilt_mode;
3645
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003646 if (!sitar->mbhc_cfg.calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303647 pr_err("Error, no sitar calibration\n");
3648 return -ENODEV;
3649 }
3650
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303651 if (!sitar->mclk_enabled) {
3652 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
3653 sitar_enable_rx_bias(codec, 1);
3654 sitar_codec_enable_clock_block(codec, 1);
3655 }
3656
3657 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
3658
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303659 /* Make sure CFILT is in fast mode, save current mode */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003660 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
3661 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
3662
3663 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303664
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303665 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3666 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
3667
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003668 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
3669 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
3670 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
3671
3672 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303673 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3674 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
3675
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003676 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303677 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3678
3679 sitar_codec_calibrate_hs_polling(codec);
3680
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003681 /* don't flip override */
3682 bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003683 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
3684 cfilt_mode);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303685 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
3686
3687 return bias_value;
3688}
3689
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003690static int sitar_cancel_btn_work(struct sitar_priv *sitar)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303691{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003692 int r = 0;
3693 struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303694
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003695 if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
3696 /* if scheduled mbhc_btn_dwork is canceled from here,
3697 * we have to unlock from here instead btn_work */
3698 wcd9xxx_unlock_sleep(core);
3699 r = 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303700 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003701 return r;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303702}
3703
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003704
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003705static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3706 s16 vin_mv)
3707{
3708 short diff, zero;
3709 struct sitar_priv *sitar;
3710 u32 mb_mv, in;
3711
3712 sitar = snd_soc_codec_get_drvdata(codec);
3713 mb_mv = sitar->mbhc_data.micb_mv;
3714
3715 if (mb_mv == 0) {
3716 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3717 return -EINVAL;
3718 }
3719
3720 if (dce) {
3721 diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
3722 zero = sitar->mbhc_data.dce_z;
3723 } else {
3724 diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
3725 zero = sitar->mbhc_data.sta_z;
3726 }
3727 in = (u32) diff * vin_mv;
3728
3729 return (u16) (in / mb_mv) + zero;
3730}
3731
3732static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3733 u16 bias_value)
3734{
3735 struct sitar_priv *sitar;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003736 s16 value, z, mb;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003737 s32 mv;
3738
3739 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003740 value = bias_value;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003741
3742 if (dce) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003743 z = (sitar->mbhc_data.dce_z);
3744 mb = (sitar->mbhc_data.dce_mb);
3745 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003746 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003747 z = (sitar->mbhc_data.sta_z);
3748 mb = (sitar->mbhc_data.sta_mb);
3749 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003750 }
3751
3752 return mv;
3753}
3754
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003755static void btn_lpress_fn(struct work_struct *work)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303756{
3757 struct delayed_work *delayed_work;
3758 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003759 short bias_value;
3760 int dce_mv, sta_mv;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003761 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303762
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003763 pr_debug("%s:\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303764
3765 delayed_work = to_delayed_work(work);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003766 sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003767 core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303768
3769 if (sitar) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003770 if (sitar->mbhc_cfg.button_jack) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003771 bias_value = sitar_codec_read_sta_result(sitar->codec);
3772 sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003773 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003774 bias_value = sitar_codec_read_dce_result(sitar->codec);
3775 dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003776 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003777 pr_debug("%s: Reporting long button press event"
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003778 " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
3779 sitar_snd_soc_jack_report(sitar,
3780 sitar->mbhc_cfg.button_jack,
3781 sitar->buttons_pressed,
3782 sitar->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303783 }
3784 } else {
3785 pr_err("%s: Bad sitar private data\n", __func__);
3786 }
3787
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003788 pr_debug("%s: leave\n", __func__);
3789 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303790}
3791
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003792
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003793void sitar_mbhc_cal(struct snd_soc_codec *codec)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303794{
3795 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003796 struct sitar_mbhc_btn_detect_cfg *btn_det;
3797 u8 cfilt_mode, bg_mode;
3798 u8 ncic, nmeas, navg;
3799 u32 mclk_rate;
3800 u32 dce_wait, sta_wait;
3801 u8 *n_cic;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003802 void *calibration;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003803
3804 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003805 calibration = sitar->mbhc_cfg.calibration;
3806
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003807 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003808 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003809
3810 /* First compute the DCE / STA wait times
3811 * depending on tunable parameters.
3812 * The value is computed in microseconds
3813 */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003814 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003815 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3816 ncic = n_cic[sitar_codec_mclk_index(sitar)];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003817 nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
3818 navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
3819 mclk_rate = sitar->mbhc_cfg.mclk_rate;
3820 dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003821 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
3822
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003823 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
3824 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003825
3826 /* LDOH and CFILT are already configured during pdata handling.
3827 * Only need to make sure CFILT and bandgap are in Fast mode.
3828 * Need to restore defaults once calculation is done.
3829 */
3830 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
3831 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3832 bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
3833 0x02);
3834
3835 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3836 * to perform ADC calibration
3837 */
3838 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003839 sitar->mbhc_cfg.micbias << 5);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003840 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3841 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003842 snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003843 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3844
3845 /* DCE measurement for 0 volts */
3846 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3847 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3848 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3849 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
3850 usleep_range(100, 100);
3851 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3852 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
3853 sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
3854
3855 /* DCE measurment for MB voltage */
3856 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3857 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3858 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
3859 usleep_range(100, 100);
3860 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3861 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
3862 sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
3863
3864 /* Sta measuremnt for 0 volts */
3865 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3866 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3867 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3868 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
3869 usleep_range(100, 100);
3870 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3871 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
3872 sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
3873
3874 /* STA Measurement for MB Voltage */
3875 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
3876 usleep_range(100, 100);
3877 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3878 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
3879 sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
3880
3881 /* Restore default settings. */
3882 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3883 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
3884 cfilt_mode);
3885 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3886
3887 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
3888 usleep_range(100, 100);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003889
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003890 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003891 sitar_turn_onoff_rel_detection(codec, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003892}
3893
3894void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
3895 const enum sitar_mbhc_btn_det_mem mem)
3896{
3897 void *ret = &btn_det->_v_btn_low;
3898
3899 switch (mem) {
3900 case SITAR_BTN_DET_GAIN:
3901 ret += sizeof(btn_det->_n_cic);
3902 case SITAR_BTN_DET_N_CIC:
3903 ret += sizeof(btn_det->_n_ready);
3904 case SITAR_BTN_DET_N_READY:
3905 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3906 case SITAR_BTN_DET_V_BTN_HIGH:
3907 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3908 case SITAR_BTN_DET_V_BTN_LOW:
3909 /* do nothing */
3910 break;
3911 default:
3912 ret = NULL;
3913 }
3914
3915 return ret;
3916}
3917
3918static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
3919{
3920 struct sitar_priv *sitar;
3921 s16 btn_mv = 0, btn_delta_mv;
3922 struct sitar_mbhc_btn_detect_cfg *btn_det;
3923 struct sitar_mbhc_plug_type_cfg *plug_type;
3924 u16 *btn_high;
3925 u8 *n_ready;
3926 int i;
3927
3928 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003929 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
3930 plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003931
3932 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003933 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003934 sitar->mbhc_data.npoll = 9;
3935 sitar->mbhc_data.nbounce_wait = 30;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003936 } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003937 sitar->mbhc_data.npoll = 7;
3938 sitar->mbhc_data.nbounce_wait = 23;
3939 }
3940
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003941 sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
3942 (sitar->mbhc_cfg.mclk_rate / 1000) *
3943 n_ready[sitar_codec_mclk_index(sitar)]) +
3944 10;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003945 sitar->mbhc_data.v_ins_hu =
3946 sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3947 sitar->mbhc_data.v_ins_h =
3948 sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3949
3950 btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
3951 for (i = 0; i < btn_det->num_btn; i++)
3952 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3953
3954 sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
3955 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3956
3957 sitar->mbhc_data.v_b1_hu =
3958 sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
3959
3960 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3961
3962 sitar->mbhc_data.v_b1_huc =
3963 sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3964
3965 sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003966 sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003967
3968 sitar->mbhc_data.v_no_mic =
3969 sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3970}
3971
3972void sitar_mbhc_init(struct snd_soc_codec *codec)
3973{
3974 struct sitar_priv *sitar;
3975 struct sitar_mbhc_general_cfg *generic;
3976 struct sitar_mbhc_btn_detect_cfg *btn_det;
3977 int n;
3978 u8 *n_cic, *gain;
3979
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003980 pr_err("%s(): ENTER\n", __func__);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003981 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003982 generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3983 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003984
3985 for (n = 0; n < 8; n++) {
3986 if (n != 7) {
3987 snd_soc_update_bits(codec,
3988 SITAR_A_CDC_MBHC_FIR_B1_CFG,
3989 0x07, n);
3990 snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
3991 btn_det->c[n]);
3992 }
3993 }
3994 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
3995 btn_det->nc);
3996
3997 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3998 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
3999 n_cic[sitar_codec_mclk_index(sitar)]);
4000
4001 gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
4002 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
4003 gain[sitar_codec_mclk_index(sitar)] << 3);
4004
4005 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4006 generic->mbhc_nsa << 4);
4007
4008 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4009 btn_det->n_meas);
4010
4011 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4012
4013 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4014
4015 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
4016 btn_det->mbhc_nsc << 3);
4017
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004018 snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
4019 sitar->mbhc_cfg.micbias);
4020
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004021 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004022
4023 snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
4024
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004025}
4026
4027static bool sitar_mbhc_fw_validate(const struct firmware *fw)
4028{
4029 u32 cfg_offset;
4030 struct sitar_mbhc_imped_detect_cfg *imped_cfg;
4031 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
4032
4033 if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
4034 return false;
4035
4036 /* previous check guarantees that there is enough fw data up
4037 * to num_btn
4038 */
4039 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
4040 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4041 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
4042 return false;
4043
4044 /* previous check guarantees that there is enough fw data up
4045 * to start of impedance detection configuration
4046 */
4047 imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
4048 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4049
4050 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
4051 return false;
4052
4053 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
4054 return false;
4055
4056 return true;
4057}
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004058
4059
4060static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
4061{
4062 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
4063}
4064
4065/* called under codec_resource_lock acquisition */
4066void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
4067{
4068 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4069 u8 wg_time;
4070
4071 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
4072 wg_time += 1;
4073
4074 /* If headphone PA is on, check if userspace receives
4075 * removal event to sync-up PA's state */
4076 if (sitar_is_hph_pa_on(codec)) {
4077 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4078 set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
4079 set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
4080 } else {
4081 pr_debug("%s PA is off\n", __func__);
4082 }
4083
4084 if (sitar_is_hph_dac_on(codec, 1))
4085 set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
4086 if (sitar_is_hph_dac_on(codec, 0))
4087 set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
4088
4089 snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
4090 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
4091 0xC0, 0x00);
4092 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
4093 0xC0, 0x00);
4094 usleep_range(wg_time * 1000, wg_time * 1000);
4095}
4096
4097static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
4098{
4099 bool pa_turned_on = false;
4100 struct snd_soc_codec *codec = sitar->codec;
4101 u8 wg_time;
4102
4103 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
4104 wg_time += 1;
4105
4106 if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
4107 &sitar->hph_pa_dac_state)) {
4108 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4109 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
4110 0xC0, 0xC0);
4111 }
4112 if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
4113 &sitar->hph_pa_dac_state)) {
4114 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4115 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
4116 0xC0, 0xC0);
4117 }
4118
4119 if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
4120 &sitar->hph_pa_dac_state)) {
4121 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4122 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
4123 1 << 4);
4124 pa_turned_on = true;
4125 }
4126 if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
4127 &sitar->hph_pa_dac_state)) {
4128 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4129 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
4130 1 << 5);
4131 pa_turned_on = true;
4132 }
4133
4134 if (pa_turned_on) {
4135 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4136 __func__);
4137 usleep_range(wg_time * 1000, wg_time * 1000);
4138 }
4139}
4140
4141static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4142 enum snd_jack_types jack_type)
4143{
4144 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4145
4146 if (!insertion) {
4147 /* Report removal */
4148 sitar->hph_status &= ~jack_type;
4149 if (sitar->mbhc_cfg.headset_jack) {
4150 /* cancel possibly scheduled btn work and
4151 * report release if we reported button press */
4152 if (sitar_cancel_btn_work(sitar)) {
4153 pr_debug("%s: button press is canceled\n",
4154 __func__);
4155 } else if (sitar->buttons_pressed) {
4156 pr_debug("%s: Reporting release for reported "
4157 "button press %d\n", __func__,
4158 jack_type);
4159 sitar_snd_soc_jack_report(sitar,
4160 sitar->mbhc_cfg.button_jack, 0,
4161 sitar->buttons_pressed);
4162 sitar->buttons_pressed &=
4163 ~SITAR_JACK_BUTTON_MASK;
4164 }
4165 pr_debug("%s: Reporting removal %d\n", __func__,
4166 jack_type);
4167 sitar_snd_soc_jack_report(sitar,
4168 sitar->mbhc_cfg.headset_jack,
4169 sitar->hph_status,
4170 SITAR_JACK_MASK);
4171 }
4172 sitar_set_and_turnoff_hph_padac(codec);
4173 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004174 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004175 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004176 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004177 sitar->current_plug = PLUG_TYPE_NONE;
4178 sitar->mbhc_polling_active = false;
4179 } else {
4180 /* Report insertion */
4181 sitar->hph_status |= jack_type;
4182
4183 if (jack_type == SND_JACK_HEADPHONE)
4184 sitar->current_plug = PLUG_TYPE_HEADPHONE;
4185 else if (jack_type == SND_JACK_HEADSET) {
4186 sitar->mbhc_polling_active = true;
4187 sitar->current_plug = PLUG_TYPE_HEADSET;
4188 }
4189 if (sitar->mbhc_cfg.headset_jack) {
4190 pr_debug("%s: Reporting insertion %d\n", __func__,
4191 jack_type);
4192 sitar_snd_soc_jack_report(sitar,
4193 sitar->mbhc_cfg.headset_jack,
4194 sitar->hph_status,
4195 SITAR_JACK_MASK);
4196 }
4197 sitar_clr_and_turnon_hph_padac(sitar);
4198 }
4199}
4200
4201
4202static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
4203{
4204 return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
4205 sitar->mbhc_cfg.gpio_level_insert);
4206}
4207
4208static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
4209 int mic_volt, int mic_volt_prev)
4210{
4211 int delta = abs(mic_volt - mic_volt_prev);
4212 if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
4213 pr_debug("%s: volt delta %dmv\n", __func__, delta);
4214 return true;
4215 }
4216 return false;
4217}
4218
4219static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
4220 s32 mic_volt)
4221{
4222 bool invalid = false;
4223
4224 if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
4225 && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
4226 invalid = true;
4227 }
4228
4229 return invalid;
4230}
4231
4232static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
4233 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
4234 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
4235{
4236 int i;
4237 bool r = false;
4238 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4239 struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
4240 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4241
4242 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
4243 if (mic_mv[i] < plug_type_ptr->v_no_mic)
4244 plug_type[i] = PLUG_TYPE_HEADPHONE;
4245 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
4246 plug_type[i] = PLUG_TYPE_HEADSET;
4247 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
4248 plug_type[i] = PLUG_TYPE_HIGH_HPH;
4249
4250 r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
4251 if (!r && i > 0) {
4252 if (plug_type[i-1] != plug_type[i])
4253 r = true;
4254 else
4255 r = sitar_is_invalid_insert_delta(codec,
4256 mic_mv[i],
4257 mic_mv[i - 1]);
4258 }
4259 }
4260
4261 return r;
4262}
4263
4264/* called under codec_resource_lock acquisition */
4265void sitar_find_plug_and_report(struct snd_soc_codec *codec,
4266 enum sitar_mbhc_plug_type plug_type)
4267{
4268 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4269
4270 if (plug_type == PLUG_TYPE_HEADPHONE
4271 && sitar->current_plug == PLUG_TYPE_NONE) {
4272 /* Nothing was reported previously
4273 * reporte a headphone
4274 */
4275 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4276 sitar_codec_cleanup_hs_polling(codec);
4277 } else if (plug_type == PLUG_TYPE_HEADSET) {
4278 /* If Headphone was reported previously, this will
4279 * only report the mic line
4280 */
4281 sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
4282 msleep(100);
4283 sitar_codec_start_hs_polling(codec);
4284 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
4285 if (sitar->current_plug == PLUG_TYPE_NONE)
4286 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4287 sitar_codec_cleanup_hs_polling(codec);
4288 pr_debug("setup mic trigger for further detection\n");
4289 sitar->lpi_enabled = true;
4290 /* TODO ::: sitar_codec_enable_hs_detect */
4291 pr_err("%s(): High impedence hph not supported\n", __func__);
4292 }
4293}
4294
4295/* should be called under interrupt context that hold suspend */
4296static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
4297{
4298 pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
4299 sitar->hs_detect_work_stop = false;
4300 wcd9xxx_lock_sleep(sitar->codec->control_data);
4301 schedule_work(&sitar->hs_correct_plug_work);
4302}
4303
4304/* called under codec_resource_lock acquisition */
4305static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
4306{
4307 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
4308 sitar->hs_detect_work_stop = true;
4309 wmb();
4310 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4311 if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
4312 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
4313 wcd9xxx_unlock_sleep(sitar->codec->control_data);
4314 }
4315 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4316}
4317
4318static void sitar_hs_correct_gpio_plug(struct work_struct *work)
4319{
4320 struct sitar_priv *sitar;
4321 struct snd_soc_codec *codec;
4322 int retry = 0, i;
4323 bool correction = false;
4324 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4325 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4326 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4327 unsigned long timeout;
4328
4329 sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
4330 codec = sitar->codec;
4331
4332 pr_debug("%s: enter\n", __func__);
4333 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4334
4335 /* Keep override on during entire plug type correction work.
4336 *
4337 * This is okay under the assumption that any GPIO irqs which use
4338 * MBHC block cancel and sync this work so override is off again
4339 * prior to GPIO interrupt handler's MBHC block usage.
4340 * Also while this correction work is running, we can guarantee
4341 * DAPM doesn't use any MBHC block as this work only runs with
4342 * headphone detection.
4343 */
4344 sitar_turn_onoff_override(codec, true);
4345
4346 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4347 while (!time_after(jiffies, timeout)) {
4348 ++retry;
4349 rmb();
4350 if (sitar->hs_detect_work_stop) {
4351 pr_debug("%s: stop requested\n", __func__);
4352 break;
4353 }
4354
4355 msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
4356 if (sitar_hs_gpio_level_remove(sitar)) {
4357 pr_debug("%s: GPIO value is low\n", __func__);
4358 break;
4359 }
4360
4361 /* can race with removal interrupt */
4362 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4363 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4364 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4365 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4366 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
4367 __func__, retry, mic_mv[i], mb_v[i]);
4368 }
4369 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4370
4371 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4372 pr_debug("Invalid plug in attempt # %d\n", retry);
4373 if (retry == NUM_ATTEMPTS_TO_REPORT &&
4374 sitar->current_plug == PLUG_TYPE_NONE) {
4375 sitar_codec_report_plug(codec, 1,
4376 SND_JACK_HEADPHONE);
4377 }
4378 } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
4379 plug_type) &&
4380 plug_type[0] == PLUG_TYPE_HEADPHONE) {
4381 pr_debug("Good headphone detected, continue polling mic\n");
4382 if (sitar->current_plug == PLUG_TYPE_NONE) {
4383 sitar_codec_report_plug(codec, 1,
4384 SND_JACK_HEADPHONE);
4385 }
4386 } else {
4387 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4388 /* Turn off override */
4389 sitar_turn_onoff_override(codec, false);
4390 sitar_find_plug_and_report(codec, plug_type[0]);
4391 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4392 pr_debug("Attempt %d found correct plug %d\n", retry,
4393 plug_type[0]);
4394 correction = true;
4395 break;
4396 }
4397 }
4398
4399 /* Turn off override */
4400 if (!correction)
4401 sitar_turn_onoff_override(codec, false);
4402
4403 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4404 pr_debug("%s: leave\n", __func__);
4405 /* unlock sleep */
4406 wcd9xxx_unlock_sleep(sitar->codec->control_data);
4407}
4408
4409/* called under codec_resource_lock acquisition */
4410static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
4411{
4412 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4413 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4414 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4415 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4416 int i;
4417
4418 pr_debug("%s: enter\n", __func__);
4419
4420 sitar_turn_onoff_override(codec, true);
4421 mb_v[0] = sitar_codec_setup_hs_polling(codec);
4422 mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
4423 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
4424
4425 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4426 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4427 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4428 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
4429 mic_mv[i]);
4430 }
4431 sitar_turn_onoff_override(codec, false);
4432
4433 if (sitar_hs_gpio_level_remove(sitar)) {
4434 pr_debug("%s: GPIO value is low when determining plug\n",
4435 __func__);
4436 return;
4437 }
4438
4439 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4440 sitar_schedule_hs_detect_plug(sitar);
4441 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
4442 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4443 sitar_schedule_hs_detect_plug(sitar);
4444 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
4445 pr_debug("%s: Valid plug found, determine plug type\n",
4446 __func__);
4447 sitar_find_plug_and_report(codec, plug_type[0]);
4448 }
4449
4450}
4451
4452/* called under codec_resource_lock acquisition */
4453static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
4454{
4455 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4456 const struct sitar_mbhc_plug_detect_cfg *plug_det =
4457 SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
4458
4459 if (plug_det->t_ins_complete > 20)
4460 msleep(plug_det->t_ins_complete);
4461 else
4462 usleep_range(plug_det->t_ins_complete * 1000,
4463 plug_det->t_ins_complete * 1000);
4464
4465 if (sitar_hs_gpio_level_remove(sitar))
4466 pr_debug("%s: GPIO value is low when determining "
4467 "plug\n", __func__);
4468 else
4469 sitar_codec_decide_gpio_plug(codec);
4470
4471 return;
4472}
4473
4474static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
4475{
4476 bool insert;
4477 struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
4478 bool is_removed = false;
4479
4480 pr_debug("%s: enter\n", __func__);
4481
4482 priv->in_gpio_handler = true;
4483 /* Wait here for debounce time */
4484 usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
4485 SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
4486
4487 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4488
4489 /* cancel pending button press */
4490 if (sitar_cancel_btn_work(priv))
4491 pr_debug("%s: button press is canceled\n", __func__);
4492
4493 insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4494 priv->mbhc_cfg.gpio_level_insert);
4495 if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
4496 priv->lpi_enabled = false;
4497 wmb();
4498
4499 /* cancel detect plug */
4500 sitar_cancel_hs_detect_plug(priv);
4501
4502 /* Disable Mic Bias pull down and HPH Switch to GND */
4503 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
4504 0x00);
4505 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
4506 sitar_codec_detect_plug_type(codec);
4507 } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
4508 priv->lpi_enabled = false;
4509 wmb();
4510
4511 /* cancel detect plug */
4512 sitar_cancel_hs_detect_plug(priv);
4513
4514 if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
4515 sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
4516 is_removed = true;
4517 } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
4518 sitar_codec_pause_hs_polling(codec);
4519 sitar_codec_cleanup_hs_polling(codec);
4520 sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
4521 is_removed = true;
4522 }
4523
4524 if (is_removed) {
4525 /* Enable Mic Bias pull down and HPH Switch to GND */
4526 snd_soc_update_bits(codec,
4527 priv->mbhc_bias_regs.ctl_reg, 0x01,
4528 0x01);
4529 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
4530 0x01);
4531 /* Make sure mic trigger is turned off */
4532 snd_soc_update_bits(codec,
4533 priv->mbhc_bias_regs.ctl_reg,
4534 0x01, 0x01);
4535 snd_soc_update_bits(codec,
4536 priv->mbhc_bias_regs.mbhc_reg,
4537 0x90, 0x00);
4538 /* Reset MBHC State Machine */
4539 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4540 0x08, 0x08);
4541 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4542 0x08, 0x00);
4543 /* Turn off override */
4544 sitar_turn_onoff_override(codec, false);
4545 }
4546 }
4547
4548 priv->in_gpio_handler = false;
4549 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4550 pr_debug("%s: leave\n", __func__);
4551}
4552
4553static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
4554{
4555 int r = IRQ_HANDLED;
4556 struct snd_soc_codec *codec = data;
4557
4558 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
4559 pr_warn("%s(): Failed to hold suspend\n", __func__);
4560 r = IRQ_NONE;
4561 } else {
4562 sitar_hs_gpio_handler(codec);
4563 wcd9xxx_unlock_sleep(codec->control_data);
4564 }
4565 return r;
4566}
4567
4568static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
4569{
4570 int rc = 0;
4571 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4572
4573 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4574 sitar_mbhc_init(codec);
4575 sitar_mbhc_cal(codec);
4576 sitar_mbhc_calc_thres(codec);
4577 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4578 sitar_codec_calibrate_hs_polling(codec);
4579
4580 /* Enable Mic Bias pull down and HPH Switch to GND */
4581 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
4582 0x01, 0x01);
4583 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
4584 0x01, 0x01);
4585
4586 rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
4587 NULL,
4588 sitar_mechanical_plug_detect_irq,
4589 (IRQF_TRIGGER_RISING |
4590 IRQF_TRIGGER_FALLING),
4591 "sitar-hs-gpio", codec);
4592
4593 if (!IS_ERR_VALUE(rc)) {
4594 rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
4595 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
4596 0x10, 0x10);
4597 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004598 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004599 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004600 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004601 /* Bootup time detection */
4602 sitar_hs_gpio_handler(codec);
4603 }
4604
4605 return rc;
4606}
4607
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004608static void mbhc_fw_read(struct work_struct *work)
4609{
4610 struct delayed_work *dwork;
4611 struct sitar_priv *sitar;
4612 struct snd_soc_codec *codec;
4613 const struct firmware *fw;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004614 int ret = -1, retry = 0;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004615
4616 dwork = to_delayed_work(work);
4617 sitar = container_of(dwork, struct sitar_priv,
4618 mbhc_firmware_dwork);
4619 codec = sitar->codec;
4620
4621 while (retry < MBHC_FW_READ_ATTEMPTS) {
4622 retry++;
4623 pr_info("%s:Attempt %d to request MBHC firmware\n",
4624 __func__, retry);
4625 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
4626 codec->dev);
4627
4628 if (ret != 0) {
4629 usleep_range(MBHC_FW_READ_TIMEOUT,
4630 MBHC_FW_READ_TIMEOUT);
4631 } else {
4632 pr_info("%s: MBHC Firmware read succesful\n", __func__);
4633 break;
4634 }
4635 }
4636
4637 if (ret != 0) {
4638 pr_err("%s: Cannot load MBHC firmware use default cal\n",
4639 __func__);
4640 } else if (sitar_mbhc_fw_validate(fw) == false) {
4641 pr_err("%s: Invalid MBHC cal data size use default cal\n",
4642 __func__);
4643 release_firmware(fw);
4644 } else {
4645 sitar->calibration = (void *)fw->data;
4646 sitar->mbhc_fw = fw;
4647 }
4648
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004649 sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004650}
4651
4652int sitar_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004653 const struct sitar_mbhc_config *cfg)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004654{
4655 struct sitar_priv *sitar;
4656 int rc = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304657
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004658 if (!codec || !cfg->calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304659 pr_err("Error: no codec or calibration\n");
4660 return -EINVAL;
4661 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004662
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004663 if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
4664 if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004665 pr_err("Error: clock rate %dHz is not yet supported\n",
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004666 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004667 else
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004668 pr_err("Error: unsupported clock rate %d\n",
4669 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004670 return -EINVAL;
4671 }
4672
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304673 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004674 sitar->mbhc_cfg = *cfg;
4675 sitar->in_gpio_handler = false;
4676 sitar->current_plug = PLUG_TYPE_NONE;
4677 sitar->lpi_enabled = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304678 sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
4679
4680 /* Put CFILT in fast mode by default */
4681 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004682 0x40, SITAR_CFILT_FAST_MODE);
4683
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004684 INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004685 INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304686 INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
4687 INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004688 INIT_WORK(&sitar->hs_correct_plug_work,
4689 sitar_hs_correct_gpio_plug);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004690
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004691 if (!sitar->mbhc_cfg.read_fw_bin) {
4692 rc = sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004693 } else {
4694 schedule_delayed_work(&sitar->mbhc_firmware_dwork,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004695 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304696 }
4697
4698 return rc;
4699}
4700EXPORT_SYMBOL_GPL(sitar_hs_detect);
4701
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004702static int sitar_determine_button(const struct sitar_priv *priv,
4703 const s32 bias_mv)
4704{
4705 s16 *v_btn_low, *v_btn_high;
4706 struct sitar_mbhc_btn_detect_cfg *btn_det;
4707 int i, btn = -1;
4708
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004709 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004710 v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
4711 v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
4712 SITAR_BTN_DET_V_BTN_HIGH);
4713 for (i = 0; i < btn_det->num_btn; i++) {
4714 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4715 btn = i;
4716 break;
4717 }
4718 }
4719
4720 if (btn == -1)
4721 pr_debug("%s: couldn't find button number for mic mv %d\n",
4722 __func__, bias_mv);
4723
4724 return btn;
4725}
4726
4727static int sitar_get_button_mask(const int btn)
4728{
4729 int mask = 0;
4730 switch (btn) {
4731 case 0:
4732 mask = SND_JACK_BTN_0;
4733 break;
4734 case 1:
4735 mask = SND_JACK_BTN_1;
4736 break;
4737 case 2:
4738 mask = SND_JACK_BTN_2;
4739 break;
4740 case 3:
4741 mask = SND_JACK_BTN_3;
4742 break;
4743 case 4:
4744 mask = SND_JACK_BTN_4;
4745 break;
4746 case 5:
4747 mask = SND_JACK_BTN_5;
4748 break;
4749 case 6:
4750 mask = SND_JACK_BTN_6;
4751 break;
4752 case 7:
4753 mask = SND_JACK_BTN_7;
4754 break;
4755 }
4756 return mask;
4757}
4758
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004759
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304760static irqreturn_t sitar_dce_handler(int irq, void *data)
4761{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004762 int i, mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004763 short dce, sta, bias_value_dce;
4764 s32 mv, stamv, bias_mv_dce;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004765 int btn = -1, meas = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304766 struct sitar_priv *priv = data;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004767 const struct sitar_mbhc_btn_detect_cfg *d =
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004768 SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004769 short btnmeas[d->n_btn_meas + 1];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304770 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08004771 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004772 int n_btn_meas = d->n_btn_meas;
4773 u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304774
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004775 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304776
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004777 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4778 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
4779 pr_debug("%s: mbhc is being recovered, skip button press\n",
4780 __func__);
4781 goto done;
4782 }
4783
4784 priv->mbhc_state = MBHC_STATE_POTENTIAL;
4785
4786 if (!priv->mbhc_polling_active) {
4787 pr_warn("%s: mbhc polling is not active, skip button press\n",
4788 __func__);
4789 goto done;
4790 }
4791
4792 dce = sitar_codec_read_dce_result(codec);
4793 mv = sitar_codec_sta_dce_v(codec, 1, dce);
4794
4795 /* If GPIO interrupt already kicked in, ignore button press */
4796 if (priv->in_gpio_handler) {
4797 pr_debug("%s: GPIO State Changed, ignore button press\n",
4798 __func__);
4799 btn = -1;
4800 goto done;
4801 }
4802
4803 if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
4804 if (priv->mbhc_last_resume &&
4805 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
4806 pr_debug("%s: Button is already released shortly after "
4807 "resume\n", __func__);
4808 n_btn_meas = 0;
4809 } else {
4810 pr_debug("%s: Button is already released without "
4811 "resume", __func__);
4812 sta = sitar_codec_read_sta_result(codec);
4813 stamv = sitar_codec_sta_dce_v(codec, 0, sta);
4814 btn = sitar_determine_button(priv, mv);
4815 if (btn != sitar_determine_button(priv, stamv))
4816 btn = -1;
4817 goto done;
4818 }
4819 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304820
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004821 /* determine pressed button */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004822 btnmeas[meas++] = sitar_determine_button(priv, mv);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004823 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004824 meas - 1, dce, mv, btnmeas[meas - 1]);
4825 if (n_btn_meas == 0)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004826 btn = btnmeas[0];
4827 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004828 bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004829 bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
4830 btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
4831 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
4832 __func__, meas, bias_value_dce, bias_mv_dce,
4833 btnmeas[meas]);
4834 /* if large enough measurements are collected,
4835 * start to check if last all n_btn_con measurements were
4836 * in same button low/high range */
4837 if (meas + 1 >= d->n_btn_con) {
4838 for (i = 0; i < d->n_btn_con; i++)
4839 if ((btnmeas[meas] < 0) ||
4840 (btnmeas[meas] != btnmeas[meas - i]))
4841 break;
4842 if (i == d->n_btn_con) {
4843 /* button pressed */
4844 btn = btnmeas[meas];
4845 break;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004846 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
4847 /* if left measurements are less than n_btn_con,
4848 * it's impossible to find button number */
4849 break;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004850 }
4851 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004852 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304853
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004854 if (btn >= 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004855 if (priv->in_gpio_handler) {
4856 pr_debug("%s: GPIO already triggered, ignore button "
4857 "press\n", __func__);
4858 goto done;
4859 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004860 mask = sitar_get_button_mask(btn);
4861 priv->buttons_pressed |= mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004862 wcd9xxx_lock_sleep(core);
4863 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
4864 msecs_to_jiffies(400)) == 0) {
4865 WARN(1, "Button pressed twice without release"
4866 "event\n");
4867 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004868 }
4869 } else {
4870 pr_debug("%s: bogus button press, too short press?\n",
4871 __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304872 }
4873
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004874 done:
4875 pr_debug("%s: leave\n", __func__);
4876 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304877 return IRQ_HANDLED;
4878}
4879
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004880static int sitar_is_fake_press(struct sitar_priv *priv)
4881{
4882 int i;
4883 int r = 0;
4884 struct snd_soc_codec *codec = priv->codec;
4885 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
4886 short mb_v;
4887
4888 for (i = 0; i < dces; i++) {
4889 usleep_range(10000, 10000);
4890 if (i == 0) {
4891 mb_v = sitar_codec_sta_dce(codec, 0, true);
4892 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
4893 sitar_codec_sta_dce_v(codec, 0, mb_v));
4894 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4895 mb_v > (short)priv->mbhc_data.v_ins_hu) {
4896 r = 1;
4897 break;
4898 }
4899 } else {
4900 mb_v = sitar_codec_sta_dce(codec, 1, true);
4901 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
4902 sitar_codec_sta_dce_v(codec, 1, mb_v));
4903 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
4904 mb_v > (short)priv->mbhc_data.v_ins_h) {
4905 r = 1;
4906 break;
4907 }
4908 }
4909 }
4910
4911 return r;
4912}
4913
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304914static irqreturn_t sitar_release_handler(int irq, void *data)
4915{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004916 int ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304917 struct sitar_priv *priv = data;
4918 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304919
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004920 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304921
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004922 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4923 priv->mbhc_state = MBHC_STATE_RELEASE;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304924
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004925 if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
4926 ret = sitar_cancel_btn_work(priv);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304927 if (ret == 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004928 pr_debug("%s: Reporting long button release event\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004929 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004930 if (priv->mbhc_cfg.button_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304931 sitar_snd_soc_jack_report(priv,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004932 priv->mbhc_cfg.button_jack, 0,
4933 priv->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304934 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004935 if (sitar_is_fake_press(priv)) {
4936 pr_debug("%s: Fake button press interrupt\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004937 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004938 } else if (priv->mbhc_cfg.button_jack) {
4939 if (priv->in_gpio_handler) {
4940 pr_debug("%s: GPIO kicked in, ignore\n",
4941 __func__);
4942 } else {
4943 pr_debug("%s: Reporting short button 0 "
4944 "press and release\n",
4945 __func__);
4946 sitar_snd_soc_jack_report(priv,
4947 priv->mbhc_cfg.button_jack,
4948 priv->buttons_pressed,
4949 priv->buttons_pressed);
4950 sitar_snd_soc_jack_report(priv,
4951 priv->mbhc_cfg.button_jack, 0,
4952 priv->buttons_pressed);
4953 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304954 }
4955 }
4956
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004957 priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
4958 }
4959
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004960 sitar_codec_calibrate_hs_polling(codec);
4961
4962 if (priv->mbhc_cfg.gpio)
4963 msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
4964
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304965 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004966
4967 pr_debug("%s: leave\n", __func__);
4968 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4969
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304970 return IRQ_HANDLED;
4971}
4972
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304973static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
4974{
4975 struct sitar_priv *sitar = data;
4976 struct snd_soc_codec *codec;
4977
4978 pr_info("%s: received HPHL OCP irq\n", __func__);
4979
4980 if (sitar) {
4981 codec = sitar->codec;
4982 if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
4983 pr_info("%s: retry\n", __func__);
4984 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004985 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304986 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004987 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304988 } else {
4989 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004990 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304991 sitar->hphlocp_cnt = 0;
4992 sitar->hph_status |= SND_JACK_OC_HPHL;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004993 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304994 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004995 sitar->mbhc_cfg.headset_jack,
4996 sitar->hph_status,
4997 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304998 }
4999 } else {
5000 pr_err("%s: Bad sitar private data\n", __func__);
5001 }
5002
5003 return IRQ_HANDLED;
5004}
5005
5006static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
5007{
5008 struct sitar_priv *sitar = data;
5009 struct snd_soc_codec *codec;
5010
5011 pr_info("%s: received HPHR OCP irq\n", __func__);
5012
5013 if (sitar) {
5014 codec = sitar->codec;
5015 if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
5016 pr_info("%s: retry\n", __func__);
5017 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
5018 0x00);
5019 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
5020 0x10);
5021 } else {
5022 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005023 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305024 sitar->hphrocp_cnt = 0;
5025 sitar->hph_status |= SND_JACK_OC_HPHR;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005026 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305027 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005028 sitar->mbhc_cfg.headset_jack,
5029 sitar->hph_status,
5030 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305031 }
5032 } else {
5033 pr_err("%s: Bad sitar private data\n", __func__);
5034 }
5035
5036 return IRQ_HANDLED;
5037}
5038
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305039static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
5040{
5041 struct sitar_priv *priv = data;
5042 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305043
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005044 pr_debug("%s: enter\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005045 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005046 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305047
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305048 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5049
5050 /* Turn off both HPH and MIC line schmitt triggers */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005051 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305052 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005053 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305054
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005055 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305056
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005057 rmb();
5058 if (priv->lpi_enabled)
5059 msleep(100);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305060
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005061 rmb();
5062 if (!priv->lpi_enabled) {
5063 pr_debug("%s: lpi is disabled\n", __func__);
5064 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5065 priv->mbhc_cfg.gpio_level_insert) {
5066 pr_debug("%s: Valid insertion, "
5067 "detect plug type\n", __func__);
5068 sitar_codec_decide_gpio_plug(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305069 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005070 pr_debug("%s: Invalid insertion, "
5071 "stop plug detection\n", __func__);
5072 }
5073 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
5074 return IRQ_HANDLED;
5075}
5076
5077static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5078{
5079 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5080 struct sitar_mbhc_plug_type_cfg *plug_type =
5081 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
5082
5083 return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
5084 && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
5085 && (mic_mv > plug_type->v_no_mic)
5086 && (mic_mv < plug_type->v_hs_max)) ? true : false;
5087}
5088
5089/* called under codec_resource_lock acquisition
5090 * returns true if mic voltage range is back to normal insertion
5091 * returns false either if timedout or removed */
5092static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
5093{
5094 int i;
5095 bool timedout, settled = false;
5096 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5097 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5098 unsigned long retry = 0, timeout;
5099 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5100
5101 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
5102 while (!(timedout = time_after(jiffies, timeout))) {
5103 retry++;
5104 if (sitar_hs_gpio_level_remove(sitar)) {
5105 pr_debug("%s: GPIO indicates removal\n", __func__);
5106 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305107 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005108
5109 if (retry > 1)
5110 msleep(250);
5111 else
5112 msleep(50);
5113
5114 if (sitar_hs_gpio_level_remove(sitar)) {
5115 pr_debug("%s: GPIO indicates removal\n", __func__);
5116 break;
5117 }
5118
5119 sitar_turn_onoff_override(codec, true);
5120 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5121 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
5122 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
5123 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
5124 __func__, retry, mic_mv[i], mb_v[i]);
5125 }
5126 sitar_turn_onoff_override(codec, false);
5127
5128 if (sitar_hs_gpio_level_remove(sitar)) {
5129 pr_debug("%s: GPIO indicates removal\n", __func__);
5130 break;
5131 }
5132
5133 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5134 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5135 break;
5136
5137 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5138 pr_debug("%s: MIC voltage settled\n", __func__);
5139 settled = true;
5140 msleep(200);
5141 break;
5142 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305143 }
5144
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005145 if (timedout)
5146 pr_debug("%s: Microphone did not settle in %d seconds\n",
5147 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
5148 return settled;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305149}
5150
5151static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
5152{
5153 struct sitar_priv *priv = data;
5154 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305155
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005156 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305157
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005158 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5159 if (sitar_hs_remove_settle(codec))
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305160 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005161 pr_debug("%s: remove settle done\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305162
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005163 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305164 return IRQ_HANDLED;
5165}
5166
5167
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305168
5169static irqreturn_t sitar_slimbus_irq(int irq, void *data)
5170{
5171 struct sitar_priv *priv = data;
5172 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005173 unsigned long slimbus_value;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005174 int i, j, k, port_id, ch_mask_temp;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305175 u8 val;
5176
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305177
5178 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
5179 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
5180 SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
5181 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005182 port_id = i*8 + j;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305183 val = wcd9xxx_interface_reg_read(codec->control_data,
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005184 SITAR_SLIM_PGD_PORT_INT_SOURCE0 + port_id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305185 if (val & 0x1)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005186 pr_err_ratelimited("overflow error on port %x, value %x\n",
5187 port_id, val);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305188 if (val & 0x2)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005189 pr_err_ratelimited("underflow error on port %x,value %x\n",
5190 port_id, val);
5191 if (val & 0x4) {
5192 pr_debug("%s: port %x disconnect value %x\n",
5193 __func__, port_id, val);
5194 for (k = 0; k < ARRAY_SIZE(sitar_dai); k++) {
5195 ch_mask_temp = 1 << port_id;
5196 if (ch_mask_temp &
5197 priv->dai[k].ch_mask) {
5198 priv->dai[k].ch_mask &=
5199 ~ch_mask_temp;
5200 if (!priv->dai[k].ch_mask)
5201 wake_up(
5202 &priv->dai[k].dai_wait);
5203 }
5204 }
5205 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305206 }
5207 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005208 SITAR_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
5209 val = 0x0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305210 }
5211
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305212 return IRQ_HANDLED;
5213}
5214
5215
5216static int sitar_handle_pdata(struct sitar_priv *sitar)
5217{
5218 struct snd_soc_codec *codec = sitar->codec;
5219 struct wcd9xxx_pdata *pdata = sitar->pdata;
5220 int k1, k2, rc = 0;
5221 u8 leg_mode = pdata->amic_settings.legacy_mode;
5222 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
5223 u8 txfe_buff = pdata->amic_settings.txfe_buff;
5224 u8 flag = pdata->amic_settings.use_pdata;
5225 u8 i = 0, j = 0;
5226 u8 val_txfe = 0, value = 0;
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305227 int amic_reg_count = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305228
5229 if (!pdata) {
5230 rc = -ENODEV;
5231 goto done;
5232 }
5233
5234 /* Make sure settings are correct */
5235 if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
5236 (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
5237 (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
5238 rc = -EINVAL;
5239 goto done;
5240 }
5241
5242 /* figure out k value */
5243 k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
5244 pdata->micbias.cfilt1_mv);
5245 k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
5246 pdata->micbias.cfilt2_mv);
5247
5248 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
5249 rc = -EINVAL;
5250 goto done;
5251 }
5252
5253 /* Set voltage level and always use LDO */
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07005254 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
5255 (pdata->micbias.ldoh_v << 2));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305256
5257 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
5258 (k1 << 2));
5259 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
5260 (k2 << 2));
5261
5262 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
5263 (pdata->micbias.bias1_cfilt_sel << 5));
5264 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
5265 (pdata->micbias.bias2_cfilt_sel << 5));
5266
Bhalchandra Gajare15dbeaa2012-06-26 12:53:07 -07005267 /* Set micbias capless mode */
5268 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x10,
5269 (pdata->micbias.bias1_cap_mode << 4));
5270 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
5271 (pdata->micbias.bias2_cap_mode << 4));
5272
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305273 amic_reg_count = (NUM_AMIC % 2) ? NUM_AMIC + 1 : NUM_AMIC;
5274 for (i = 0; i < amic_reg_count; j++, i += 2) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305275 if (flag & (0x01 << i)) {
5276 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
5277 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
5278 val_txfe = val_txfe |
5279 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
5280 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5281 0x10, value);
5282 snd_soc_update_bits(codec,
5283 SITAR_A_TX_1_2_TEST_EN + j * 10,
5284 0x30, val_txfe);
5285 }
5286 if (flag & (0x01 << (i + 1))) {
5287 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
5288 val_txfe = (txfe_bypass &
5289 (0x01 << (i + 1))) ? 0x02 : 0x00;
5290 val_txfe |= (txfe_buff &
5291 (0x01 << (i + 1))) ? 0x01 : 0x00;
5292 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5293 0x01, value);
5294 snd_soc_update_bits(codec,
5295 SITAR_A_TX_1_2_TEST_EN + j * 10,
5296 0x03, val_txfe);
5297 }
5298 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005299 if (flag & 0x40) {
5300 value = (leg_mode & 0x40) ? 0x10 : 0x00;
5301 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
5302 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
5303 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
5304 0x13, value);
5305 }
5306
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305307
5308 if (pdata->ocp.use_pdata) {
5309 /* not defined in CODEC specification */
5310 if (pdata->ocp.hph_ocp_limit == 1 ||
5311 pdata->ocp.hph_ocp_limit == 5) {
5312 rc = -EINVAL;
5313 goto done;
5314 }
5315 snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
5316 0x0F, pdata->ocp.num_attempts);
5317 snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
5318 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
5319 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
5320 0xE0, (pdata->ocp.hph_ocp_limit << 5));
5321 }
5322done:
5323 return rc;
5324}
5325
5326static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
5327
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305328 SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
5329 SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
5330
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305331 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
5332 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
5333
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305334 SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
5335 SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
5336 SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
5337
Simmi Pateriya6dc02f72012-10-08 13:28:31 +05305338 SITAR_REG_VAL(SITAR_A_RX_LINE_BIAS_PA, 0xA7),
5339
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305340 SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
Asish Bhattacharya2e1d7522012-05-25 15:08:40 +05305341 SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
5342 SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305343
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305344 SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
5345
5346 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
Bhalchandra Gajare8a0bb372012-10-03 18:41:01 -07005347 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x5B),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305348
5349};
5350
5351static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
5352{
5353 u32 i;
5354 for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
5355 snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
5356 sitar_1_1_reg_defaults[i].val);
5357
5358}
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305359
5360static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
5361 {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
5362};
5363
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305364static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
5365 /* Initialize current threshold to 350MA
5366 * number of wait and run cycles to 4096
5367 */
Bhalchandra Gajare33f74302012-06-14 15:12:51 -07005368 {SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305369 {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
5370
5371 {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
5372
5373 /* Initialize gain registers to use register gain */
5374 {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
5375 {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
5376 {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
5377 {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
5378
Kuirong Wangccb29c62012-06-15 11:09:07 -07005379 /* Set the MICBIAS default output as pull down*/
5380 {SITAR_A_MICB_1_CTL, 0x01, 0x01},
5381 {SITAR_A_MICB_2_CTL, 0x01, 0x01},
5382
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305383 /* Initialize mic biases to differential mode */
5384 {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
5385 {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
5386
5387 {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
5388
5389 /* Use 16 bit sample size for TX1 to TX6 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005390 {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305391 {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
5392 {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
5393 {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
5394 {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005395 {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305396
5397 /* Use 16 bit sample size for RX */
5398 {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
5399 {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
5400
5401 /*enable HPF filter for TX paths */
5402 {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005403 {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07005404
5405 /*enable External clock select*/
5406 {SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305407};
5408
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305409static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
5410{
5411 u32 i;
5412 for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
5413 snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
5414 sitar_i2c_codec_reg_init_val[i].mask,
5415 sitar_i2c_codec_reg_init_val[i].val);
5416}
5417
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305418static void sitar_codec_init_reg(struct snd_soc_codec *codec)
5419{
5420 u32 i;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305421 for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
5422 snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
5423 sitar_codec_reg_init_val[i].mask,
5424 sitar_codec_reg_init_val[i].val);
5425}
5426
5427static int sitar_codec_probe(struct snd_soc_codec *codec)
5428{
Kuirong Wang906ac472012-07-09 12:54:44 -07005429 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305430 struct sitar_priv *sitar;
5431 struct snd_soc_dapm_context *dapm = &codec->dapm;
5432 int ret = 0;
5433 int i;
5434 u8 sitar_version;
Kuirong Wang906ac472012-07-09 12:54:44 -07005435 void *ptr = NULL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305436
5437 codec->control_data = dev_get_drvdata(codec->dev->parent);
Kuirong Wang906ac472012-07-09 12:54:44 -07005438 core = codec->control_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305439
5440 sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
5441 if (!sitar) {
5442 dev_err(codec->dev, "Failed to allocate private data\n");
5443 return -ENOMEM;
5444 }
5445
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07005446 for (i = 0; i < NUM_DECIMATORS; i++) {
5447 tx_hpf_work[i].sitar = sitar;
5448 tx_hpf_work[i].decimator = i + 1;
5449 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
5450 tx_hpf_corner_freq_callback);
5451 }
5452
5453
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305454 /* Make sure mbhc micbias register addresses are zeroed out */
5455 memset(&sitar->mbhc_bias_regs, 0,
5456 sizeof(struct mbhc_micbias_regs));
5457 sitar->cfilt_k_value = 0;
5458 sitar->mbhc_micbias_switched = false;
5459
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005460 /* Make sure mbhc intenal calibration data is zeroed out */
5461 memset(&sitar->mbhc_data, 0,
5462 sizeof(struct mbhc_internal_cal_data));
5463 sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
5464 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
5465 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305466 snd_soc_codec_set_drvdata(codec, sitar);
5467
5468 sitar->mclk_enabled = false;
5469 sitar->bandgap_type = SITAR_BANDGAP_OFF;
5470 sitar->clock_active = false;
5471 sitar->config_mode_active = false;
5472 sitar->mbhc_polling_active = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305473 sitar->no_mic_headset_override = false;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005474 mutex_init(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305475 sitar->codec = codec;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005476 sitar->mbhc_state = MBHC_STATE_NONE;
5477 sitar->mbhc_last_resume = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305478 sitar->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305479 sitar_update_reg_defaults(codec);
5480 sitar_codec_init_reg(codec);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305481 sitar->intf_type = wcd9xxx_get_intf_type();
5482 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
5483 sitar_i2c_codec_init_reg(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305484
5485 ret = sitar_handle_pdata(sitar);
5486 if (IS_ERR_VALUE(ret)) {
5487 pr_err("%s: bad pdata\n", __func__);
5488 goto err_pdata;
5489 }
5490
Steve Mucklef132c6c2012-06-06 18:30:57 -07005491 snd_soc_add_codec_controls(codec, sitar_snd_controls,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305492 ARRAY_SIZE(sitar_snd_controls));
5493 snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
5494 ARRAY_SIZE(sitar_dapm_widgets));
Kuirong Wang906ac472012-07-09 12:54:44 -07005495
5496 ptr = kmalloc((sizeof(sitar_rx_chs) +
5497 sizeof(sitar_tx_chs)), GFP_KERNEL);
5498 if (!ptr) {
5499 pr_err("%s: no mem for slim chan ctl data\n", __func__);
5500 ret = -ENOMEM;
5501 goto err_nomem_slimch;
5502 }
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305503 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
5504 snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
5505 ARRAY_SIZE(sitar_dapm_i2s_widgets));
5506 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5507 ARRAY_SIZE(audio_i2s_map));
Kuirong Wang906ac472012-07-09 12:54:44 -07005508 for (i = 0; i < ARRAY_SIZE(sitar_i2s_dai); i++)
5509 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305510 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005511 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
5512 for (i = 0; i < NUM_CODEC_DAIS; i++) {
5513 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
5514 init_waitqueue_head(&sitar->dai[i].dai_wait);
5515 }
5516 }
5517 core->num_rx_port = SITAR_RX_MAX;
5518 core->rx_chs = ptr;
5519 memcpy(core->rx_chs, sitar_rx_chs, sizeof(sitar_rx_chs));
5520 core->num_tx_port = SITAR_TX_MAX;
5521 core->tx_chs = ptr + sizeof(sitar_rx_chs);
5522 memcpy(core->tx_chs, sitar_tx_chs, sizeof(sitar_tx_chs));
5523
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305524 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
5525
5526 sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
5527 pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
5528
5529 sitar_version &= 0x1F;
5530 pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
5531
5532 snd_soc_dapm_sync(dapm);
5533
5534
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005535 ret = wcd9xxx_request_irq(codec->control_data,
5536 WCD9XXX_IRQ_MBHC_INSERTION,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305537 sitar_hs_insert_irq, "Headset insert detect", sitar);
5538 if (ret) {
5539 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005540 WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305541 goto err_insert_irq;
5542 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005543 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305544
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005545 ret = wcd9xxx_request_irq(codec->control_data,
5546 WCD9XXX_IRQ_MBHC_REMOVAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305547 sitar_hs_remove_irq, "Headset remove detect", sitar);
5548 if (ret) {
5549 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005550 WCD9XXX_IRQ_MBHC_REMOVAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305551 goto err_remove_irq;
5552 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305553
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005554 ret = wcd9xxx_request_irq(codec->control_data,
5555 WCD9XXX_IRQ_MBHC_POTENTIAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305556 sitar_dce_handler, "DC Estimation detect", sitar);
5557 if (ret) {
5558 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005559 WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305560 goto err_potential_irq;
5561 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305562
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005563 ret = wcd9xxx_request_irq(codec->control_data,
5564 WCD9XXX_IRQ_MBHC_RELEASE,
5565 sitar_release_handler,
5566 "Button Release detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305567 if (ret) {
5568 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005569 WCD9XXX_IRQ_MBHC_RELEASE);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305570 goto err_release_irq;
5571 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305572
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005573 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
5574 sitar_slimbus_irq, "SLIMBUS Slave", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305575 if (ret) {
5576 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005577 WCD9XXX_IRQ_SLIMBUS);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305578 goto err_slimbus_irq;
5579 }
5580
5581 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
5582 wcd9xxx_interface_reg_write(codec->control_data,
5583 SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
5584
5585
5586 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005587 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
5588 sitar_hphl_ocp_irq,
5589 "HPH_L OCP detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305590 if (ret) {
5591 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005592 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305593 goto err_hphl_ocp_irq;
5594 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005595 wcd9xxx_disable_irq(codec->control_data,
5596 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305597
5598 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005599 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
5600 sitar_hphr_ocp_irq, "HPH_R OCP detect",
5601 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305602 if (ret) {
5603 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005604 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305605 goto err_hphr_ocp_irq;
5606 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005607 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305608
Steve Mucklef132c6c2012-06-06 18:30:57 -07005609 codec->ignore_pmdown_time = 1;
5610
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305611#ifdef CONFIG_DEBUG_FS
5612 debug_sitar_priv = sitar;
5613#endif
5614
5615 return ret;
5616
5617err_hphr_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005618 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
5619 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305620err_hphl_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005621 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305622err_slimbus_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005623 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305624err_release_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005625 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
5626 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305627err_potential_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005628 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305629err_remove_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005630 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
5631 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305632err_insert_irq:
Kuirong Wang906ac472012-07-09 12:54:44 -07005633 kfree(ptr);
5634err_nomem_slimch:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305635err_pdata:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005636 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305637 kfree(sitar);
5638 return ret;
5639}
5640static int sitar_codec_remove(struct snd_soc_codec *codec)
5641{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305642 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005643 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
5644 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
5645 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
5646 sitar);
5647 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
5648 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
5649 sitar);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005650 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305651 sitar_codec_disable_clock_block(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005652 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305653 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005654 if (sitar->mbhc_fw)
5655 release_firmware(sitar->mbhc_fw);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005656 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305657 kfree(sitar);
5658 return 0;
5659}
5660static struct snd_soc_codec_driver soc_codec_dev_sitar = {
5661 .probe = sitar_codec_probe,
5662 .remove = sitar_codec_remove,
5663 .read = sitar_read,
5664 .write = sitar_write,
5665
5666 .readable_register = sitar_readable,
5667 .volatile_register = sitar_volatile,
5668
5669 .reg_cache_size = SITAR_CACHE_SIZE,
5670 .reg_cache_default = sitar_reg_defaults,
5671 .reg_word_size = 1,
5672};
5673
5674#ifdef CONFIG_DEBUG_FS
5675static struct dentry *debugfs_poke;
5676
5677static int codec_debug_open(struct inode *inode, struct file *file)
5678{
5679 file->private_data = inode->i_private;
5680 return 0;
5681}
5682
5683static ssize_t codec_debug_write(struct file *filp,
5684 const char __user *ubuf, size_t cnt, loff_t *ppos)
5685{
5686 char lbuf[32];
5687 char *buf;
5688 int rc;
5689
5690 if (cnt > sizeof(lbuf) - 1)
5691 return -EINVAL;
5692
5693 rc = copy_from_user(lbuf, ubuf, cnt);
5694 if (rc)
5695 return -EFAULT;
5696
5697 lbuf[cnt] = '\0';
5698 buf = (char *)lbuf;
5699 debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
5700 ? false : true;
5701
5702 return rc;
5703}
5704
5705static const struct file_operations codec_debug_ops = {
5706 .open = codec_debug_open,
5707 .write = codec_debug_write,
5708};
5709#endif
5710
5711#ifdef CONFIG_PM
5712static int sitar_suspend(struct device *dev)
5713{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005714 dev_dbg(dev, "%s: system suspend\n", __func__);
5715 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305716}
5717
5718static int sitar_resume(struct device *dev)
5719{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005720 struct platform_device *pdev = to_platform_device(dev);
5721 struct sitar_priv *sitar = platform_get_drvdata(pdev);
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005722 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005723 sitar->mbhc_last_resume = jiffies;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005724 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305725}
5726
5727static const struct dev_pm_ops sitar_pm_ops = {
5728 .suspend = sitar_suspend,
5729 .resume = sitar_resume,
5730};
5731#endif
5732
5733static int __devinit sitar_probe(struct platform_device *pdev)
5734{
5735 int ret = 0;
5736 pr_err("%s\n", __func__);
5737#ifdef CONFIG_DEBUG_FS
5738 debugfs_poke = debugfs_create_file("TRRS",
5739 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
5740
5741#endif
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305742 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5743 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305744 sitar_dai, ARRAY_SIZE(sitar_dai));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305745 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5746 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
5747 sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305748 return ret;
5749}
5750static int __devexit sitar_remove(struct platform_device *pdev)
5751{
5752 snd_soc_unregister_codec(&pdev->dev);
5753
5754#ifdef CONFIG_DEBUG_FS
5755 debugfs_remove(debugfs_poke);
5756#endif
5757 return 0;
5758}
5759static struct platform_driver sitar_codec_driver = {
5760 .probe = sitar_probe,
5761 .remove = sitar_remove,
5762 .driver = {
5763 .name = "sitar_codec",
5764 .owner = THIS_MODULE,
5765#ifdef CONFIG_PM
5766 .pm = &sitar_pm_ops,
5767#endif
5768 },
5769};
5770
5771static int __init sitar_codec_init(void)
5772{
5773 return platform_driver_register(&sitar_codec_driver);
5774}
5775
5776static void __exit sitar_codec_exit(void)
5777{
5778 platform_driver_unregister(&sitar_codec_driver);
5779}
5780
5781module_init(sitar_codec_init);
5782module_exit(sitar_codec_exit);
5783
5784MODULE_DESCRIPTION("Sitar codec driver");
5785MODULE_VERSION("1.0");
5786MODULE_LICENSE("GPL v2");