blob: 616f8d5bb503b0ff5f14832f5fc179790118295a [file] [log] [blame]
Kuirong Wang80dedd62012-12-07 19:16:24 +05301/* Copyright (c) 2012-2013, 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
Kuirong Wang80dedd62012-12-07 19:16:24 +053084#define COMP_DIGITAL_DB_GAIN_APPLY(a, b) \
85 (((a) <= 0) ? ((a) - b) : (a))
86/* The wait time value comes from codec HW specification */
87#define COMP_BRINGUP_WAIT_TIME 3000
88
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080089#define SITAR_MCLK_RATE_12288KHZ 12288000
90#define SITAR_MCLK_RATE_9600KHZ 9600000
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053091
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080092#define SITAR_FAKE_INS_THRESHOLD_MS 2500
93#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070094#define SITAR_MBHC_BUTTON_MIN 0x8000
95#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
96
97#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
98#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
99
100#define MBHC_NUM_DCE_PLUG_DETECT 3
101#define SITAR_MBHC_FAKE_INSERT_LOW 10
102#define SITAR_MBHC_FAKE_INSERT_HIGH 80
103#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
104#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
105#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
106#define NUM_ATTEMPTS_TO_REPORT 5
107#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
108#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530109
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -0700110#define CUT_OF_FREQ_MASK 0x30
111#define CF_MIN_3DB_4HZ 0x0
112#define CF_MIN_3DB_75HZ 0x01
113#define CF_MIN_3DB_150HZ 0x02
114
115
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530116static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
117static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
118static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
119static struct snd_soc_dai_driver sitar_dai[];
120static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
121 struct snd_kcontrol *kcontrol, int event);
122static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
123 struct snd_kcontrol *kcontrol, int event);
124
125enum sitar_bandgap_type {
126 SITAR_BANDGAP_OFF = 0,
127 SITAR_BANDGAP_AUDIO_MODE,
128 SITAR_BANDGAP_MBHC_MODE,
129};
130
131struct mbhc_micbias_regs {
132 u16 cfilt_val;
133 u16 cfilt_ctl;
134 u16 mbhc_reg;
135 u16 int_rbias;
136 u16 ctl_reg;
137 u8 cfilt_sel;
138};
139
140/* Codec supports 2 IIR filters */
141enum {
142 IIR1 = 0,
143 IIR2,
144 IIR_MAX,
145};
146/* Codec supports 5 bands */
147enum {
148 BAND1 = 0,
149 BAND2,
150 BAND3,
151 BAND4,
152 BAND5,
153 BAND_MAX,
154};
155
Kuirong Wang80dedd62012-12-07 19:16:24 +0530156enum {
157 COMPANDER_1 = 0,
158 COMPANDER_2,
159 COMPANDER_MAX,
160};
161
162enum {
163 COMPANDER_FS_8KHZ = 0,
164 COMPANDER_FS_16KHZ,
165 COMPANDER_FS_32KHZ,
166 COMPANDER_FS_48KHZ,
167 COMPANDER_FS_96KHZ,
168 COMPANDER_FS_192KHZ,
169 COMPANDER_FS_MAX,
170};
171
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530172/* Flags to track of PA and DAC state.
173 * PA and DAC should be tracked separately as AUXPGA loopback requires
174 * only PA to be turned on without DAC being on. */
175enum sitar_priv_ack_flags {
176 SITAR_HPHL_PA_OFF_ACK = 0,
177 SITAR_HPHR_PA_OFF_ACK,
178 SITAR_HPHL_DAC_OFF_ACK,
179 SITAR_HPHR_DAC_OFF_ACK
180};
181
Kuirong Wang80dedd62012-12-07 19:16:24 +0530182struct comp_sample_dependent_params {
183 u32 peak_det_timeout;
184 u32 rms_meter_div_fact;
185 u32 rms_meter_resamp_fact;
186};
187
188struct comp_dgtl_gain_offset {
189 u8 whole_db_gain;
190 u8 half_db_gain;
191};
192
193static const struct comp_dgtl_gain_offset comp_dgtl_gain[] = {
194 {0, 0},
195 {1, 1},
196 {3, 0},
197 {4, 1},
198 {6, 0},
199 {7, 1},
200 {9, 0},
201 {10, 1},
202 {12, 0},
203 {13, 1},
204 {15, 0},
205 {16, 1},
206 {18, 0},
207};
208
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800209/* Data used by MBHC */
210struct mbhc_internal_cal_data {
211 u16 dce_z;
212 u16 dce_mb;
213 u16 sta_z;
214 u16 sta_mb;
215 u32 t_sta_dce;
216 u32 t_dce;
217 u32 t_sta;
218 u32 micb_mv;
219 u16 v_ins_hu;
220 u16 v_ins_h;
221 u16 v_b1_hu;
222 u16 v_b1_h;
223 u16 v_b1_huc;
224 u16 v_brh;
225 u16 v_brl;
226 u16 v_no_mic;
227 u8 npoll;
228 u8 nbounce_wait;
229};
230
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700231enum sitar_mbhc_plug_type {
232 PLUG_TYPE_INVALID = -1,
233 PLUG_TYPE_NONE,
234 PLUG_TYPE_HEADSET,
235 PLUG_TYPE_HEADPHONE,
236 PLUG_TYPE_HIGH_HPH,
237};
238
239enum sitar_mbhc_state {
240 MBHC_STATE_NONE = -1,
241 MBHC_STATE_POTENTIAL,
242 MBHC_STATE_POTENTIAL_RECOVERY,
243 MBHC_STATE_RELEASE,
244};
245
Kuirong Wang906ac472012-07-09 12:54:44 -0700246static const u32 vport_check_table[NUM_CODEC_DAIS] = {
247 0, /* AIF1_PB */
248 0, /* AIF1_CAP */
249};
250
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -0700251struct hpf_work {
252 struct sitar_priv *sitar;
253 u32 decimator;
254 u8 tx_hpf_cut_of_freq;
255 struct delayed_work dwork;
256};
257
258static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
259
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530260struct sitar_priv {
261 struct snd_soc_codec *codec;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800262 u32 mclk_freq;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530263 u32 adc_count;
264 u32 cfilt1_cnt;
265 u32 cfilt2_cnt;
266 u32 cfilt3_cnt;
267 u32 rx_bias_count;
268 enum sitar_bandgap_type bandgap_type;
269 bool mclk_enabled;
270 bool clock_active;
271 bool config_mode_active;
272 bool mbhc_polling_active;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800273 unsigned long mbhc_fake_ins_start;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530274 int buttons_pressed;
275
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800276 enum sitar_micbias_num micbias;
277 /* void* calibration contains:
278 * struct sitar_mbhc_general_cfg generic;
279 * struct sitar_mbhc_plug_detect_cfg plug_det;
280 * struct sitar_mbhc_plug_type_cfg plug_type;
281 * struct sitar_mbhc_btn_detect_cfg btn_det;
282 * struct sitar_mbhc_imped_detect_cfg imped_det;
283 * Note: various size depends on btn_det->num_btn
284 */
285 void *calibration;
286 struct mbhc_internal_cal_data mbhc_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530287
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530288 struct wcd9xxx_pdata *pdata;
289 u32 anc_slot;
290
291 bool no_mic_headset_override;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530292
293 struct mbhc_micbias_regs mbhc_bias_regs;
294 u8 cfilt_k_value;
295 bool mbhc_micbias_switched;
296
297 /* track PA/DAC state */
298 unsigned long hph_pa_dac_state;
299
300 /*track sitar interface type*/
301 u8 intf_type;
302
303 u32 hph_status; /* track headhpone status */
304 /* define separate work for left and right headphone OCP to avoid
305 * additional checking on which OCP event to report so no locking
306 * to ensure synchronization is required
307 */
308 struct work_struct hphlocp_work; /* reporting left hph ocp off */
309 struct work_struct hphrocp_work; /* reporting right hph ocp off */
310
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530311 u8 hphlocp_cnt; /* headphone left ocp retry */
312 u8 hphrocp_cnt; /* headphone right ocp retry */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800313
314 /* Callback function to enable MCLK */
315 int (*mclk_cb) (struct snd_soc_codec*, int);
316
317 /* Work to perform MBHC Firmware Read */
318 struct delayed_work mbhc_firmware_dwork;
319 const struct firmware *mbhc_fw;
320
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530321 /* num of slim ports required */
Kuirong Wang906ac472012-07-09 12:54:44 -0700322 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700323
Kuirong Wang80dedd62012-12-07 19:16:24 +0530324 /*compander*/
325 int comp_enabled[COMPANDER_MAX];
326 u32 comp_fs[COMPANDER_MAX];
327 u8 comp_gain_offset[NUM_INTERPOLATORS];
328
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700329 /* Currently, only used for mbhc purpose, to protect
330 * concurrent execution of mbhc threaded irq handlers and
331 * kill race between DAPM and MBHC.But can serve as a
332 * general lock to protect codec resource
333 */
334 struct mutex codec_resource_lock;
335
336 struct sitar_mbhc_config mbhc_cfg;
337 bool in_gpio_handler;
338 u8 current_plug;
339 bool lpi_enabled;
340 enum sitar_mbhc_state mbhc_state;
341 struct work_struct hs_correct_plug_work;
342 bool hs_detect_work_stop;
343 struct delayed_work mbhc_btn_dwork;
344 unsigned long mbhc_last_resume; /* in jiffies */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530345};
346
347#ifdef CONFIG_DEBUG_FS
348struct sitar_priv *debug_sitar_priv;
349#endif
350
Kuirong Wang80dedd62012-12-07 19:16:24 +0530351static const int comp_rx_path[] = {
352 COMPANDER_2,
353 COMPANDER_1,
354 COMPANDER_1,
355 COMPANDER_MAX,
356};
357
358static const struct comp_sample_dependent_params
359 comp_samp_params[COMPANDER_FS_MAX] = {
360 {
361 .peak_det_timeout = 0x6,
362 .rms_meter_div_fact = 0x9 << 4,
363 .rms_meter_resamp_fact = 0x06,
364 },
365 {
366 .peak_det_timeout = 0x7,
367 .rms_meter_div_fact = 0xA << 4,
368 .rms_meter_resamp_fact = 0x0C,
369 },
370 {
371 .peak_det_timeout = 0x8,
372 .rms_meter_div_fact = 0xB << 4,
373 .rms_meter_resamp_fact = 0x30,
374 },
375 {
376 .peak_det_timeout = 0x9,
377 .rms_meter_div_fact = 0xB << 4,
378 .rms_meter_resamp_fact = 0x28,
379 },
380 {
381 .peak_det_timeout = 0xA,
382 .rms_meter_div_fact = 0xC << 4,
383 .rms_meter_resamp_fact = 0x50,
384 },
385 {
386 .peak_det_timeout = 0xB,
387 .rms_meter_div_fact = 0xC << 4,
388 .rms_meter_resamp_fact = 0x50,
389 },
390};
391
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700392static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
393 struct snd_ctl_elem_value *ucontrol)
394{
395 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
396 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
397 ucontrol->value.integer.value[0] = sitar->anc_slot;
398 return 0;
399}
400
401static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
402 struct snd_ctl_elem_value *ucontrol)
403{
404 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
405 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
406 sitar->anc_slot = ucontrol->value.integer.value[0];
407 return 0;
408}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530409
410static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
411 struct snd_ctl_elem_value *ucontrol)
412{
413 u8 ear_pa_gain;
414 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
415
416 ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
417
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700418 ear_pa_gain &= 0xE0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530419
420 if (ear_pa_gain == 0x00) {
421 ucontrol->value.integer.value[0] = 0;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700422 } else if (ear_pa_gain == 0x80) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530423 ucontrol->value.integer.value[0] = 1;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700424 } else if (ear_pa_gain == 0xA0) {
425 ucontrol->value.integer.value[0] = 2;
426 } else if (ear_pa_gain == 0xE0) {
427 ucontrol->value.integer.value[0] = 3;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530428 } else {
429 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
430 __func__, ear_pa_gain);
431 return -EINVAL;
432 }
433
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530434 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530435
436 return 0;
437}
438
439static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
440 struct snd_ctl_elem_value *ucontrol)
441{
442 u8 ear_pa_gain;
443 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
444
445 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
446 ucontrol->value.integer.value[0]);
447
448 switch (ucontrol->value.integer.value[0]) {
449 case 0:
450 ear_pa_gain = 0x00;
451 break;
452 case 1:
453 ear_pa_gain = 0x80;
454 break;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700455 case 2:
456 ear_pa_gain = 0xA0;
457 break;
458 case 3:
459 ear_pa_gain = 0xE0;
460 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530461 default:
462 return -EINVAL;
463 }
464
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700465 snd_soc_update_bits(codec, SITAR_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530466 return 0;
467}
468
469static int sitar_get_iir_enable_audio_mixer(
470 struct snd_kcontrol *kcontrol,
471 struct snd_ctl_elem_value *ucontrol)
472{
473 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
474 int iir_idx = ((struct soc_multi_mixer_control *)
475 kcontrol->private_value)->reg;
476 int band_idx = ((struct soc_multi_mixer_control *)
477 kcontrol->private_value)->shift;
478
479 ucontrol->value.integer.value[0] =
480 snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
481 (1 << band_idx);
482
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530483 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530484 iir_idx, band_idx,
485 (uint32_t)ucontrol->value.integer.value[0]);
486 return 0;
487}
488
489static int sitar_put_iir_enable_audio_mixer(
490 struct snd_kcontrol *kcontrol,
491 struct snd_ctl_elem_value *ucontrol)
492{
493 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
494 int iir_idx = ((struct soc_multi_mixer_control *)
495 kcontrol->private_value)->reg;
496 int band_idx = ((struct soc_multi_mixer_control *)
497 kcontrol->private_value)->shift;
498 int value = ucontrol->value.integer.value[0];
499
500 /* Mask first 5 bits, 6-8 are reserved */
501 snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
502 (1 << band_idx), (value << band_idx));
503
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530504 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530505 iir_idx, band_idx, value);
506 return 0;
507}
508static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
509 int iir_idx, int band_idx,
510 int coeff_idx)
511{
512 /* Address does not automatically update if reading */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530513 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530514 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530515 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530516
517 /* Mask bits top 2 bits since they are reserved */
518 return ((snd_soc_read(codec,
519 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
520 (snd_soc_read(codec,
521 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
522 (snd_soc_read(codec,
523 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
524 (snd_soc_read(codec,
525 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
526 0x3FFFFFFF;
527}
528
529static int sitar_get_iir_band_audio_mixer(
530 struct snd_kcontrol *kcontrol,
531 struct snd_ctl_elem_value *ucontrol)
532{
533 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
534 int iir_idx = ((struct soc_multi_mixer_control *)
535 kcontrol->private_value)->reg;
536 int band_idx = ((struct soc_multi_mixer_control *)
537 kcontrol->private_value)->shift;
538
539 ucontrol->value.integer.value[0] =
540 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
541 ucontrol->value.integer.value[1] =
542 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
543 ucontrol->value.integer.value[2] =
544 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
545 ucontrol->value.integer.value[3] =
546 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
547 ucontrol->value.integer.value[4] =
548 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
549
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530550 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530551 "%s: IIR #%d band #%d b1 = 0x%x\n"
552 "%s: IIR #%d band #%d b2 = 0x%x\n"
553 "%s: IIR #%d band #%d a1 = 0x%x\n"
554 "%s: IIR #%d band #%d a2 = 0x%x\n",
555 __func__, iir_idx, band_idx,
556 (uint32_t)ucontrol->value.integer.value[0],
557 __func__, iir_idx, band_idx,
558 (uint32_t)ucontrol->value.integer.value[1],
559 __func__, iir_idx, band_idx,
560 (uint32_t)ucontrol->value.integer.value[2],
561 __func__, iir_idx, band_idx,
562 (uint32_t)ucontrol->value.integer.value[3],
563 __func__, iir_idx, band_idx,
564 (uint32_t)ucontrol->value.integer.value[4]);
565 return 0;
566}
567
568static void set_iir_band_coeff(struct snd_soc_codec *codec,
569 int iir_idx, int band_idx,
570 int coeff_idx, uint32_t value)
571{
572 /* Mask top 3 bits, 6-8 are reserved */
573 /* Update address manually each time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530574 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530575 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530576 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530577
578 /* Mask top 2 bits, 7-8 are reserved */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530579 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530580 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530581 (value >> 24) & 0x3F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530582
583 /* Isolate 8bits at a time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530584 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530585 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530586 (value >> 16) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530587
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530588 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530589 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530590 (value >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530591
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530592 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530593 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530594 value & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530595}
596
597static int sitar_put_iir_band_audio_mixer(
598 struct snd_kcontrol *kcontrol,
599 struct snd_ctl_elem_value *ucontrol)
600{
601 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
602 int iir_idx = ((struct soc_multi_mixer_control *)
603 kcontrol->private_value)->reg;
604 int band_idx = ((struct soc_multi_mixer_control *)
605 kcontrol->private_value)->shift;
606
607 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
608 ucontrol->value.integer.value[0]);
609 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
610 ucontrol->value.integer.value[1]);
611 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
612 ucontrol->value.integer.value[2]);
613 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
614 ucontrol->value.integer.value[3]);
615 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
616 ucontrol->value.integer.value[4]);
617
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530618 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530619 "%s: IIR #%d band #%d b1 = 0x%x\n"
620 "%s: IIR #%d band #%d b2 = 0x%x\n"
621 "%s: IIR #%d band #%d a1 = 0x%x\n"
622 "%s: IIR #%d band #%d a2 = 0x%x\n",
623 __func__, iir_idx, band_idx,
624 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
625 __func__, iir_idx, band_idx,
626 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
627 __func__, iir_idx, band_idx,
628 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
629 __func__, iir_idx, band_idx,
630 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
631 __func__, iir_idx, band_idx,
632 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
633 return 0;
634}
635
Kuirong Wang80dedd62012-12-07 19:16:24 +0530636static int sitar_compander_gain_offset(
637 struct snd_soc_codec *codec, u32 enable,
638 unsigned int pa_reg, unsigned int vol_reg,
639 int mask, int event,
640 struct comp_dgtl_gain_offset *gain_offset,
641 int index)
642{
643 unsigned int pa_gain = snd_soc_read(codec, pa_reg);
644 unsigned int digital_vol = snd_soc_read(codec, vol_reg);
645 int pa_mode = pa_gain & mask;
646 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
647
648 pr_debug("%s: pa_gain(0x%x=0x%x)digital_vol(0x%x=0x%x)event(0x%x) index(%d)\n",
649 __func__, pa_reg, pa_gain, vol_reg, digital_vol, event, index);
650 if (((pa_gain & 0xF) + 1) > ARRAY_SIZE(comp_dgtl_gain) ||
651 (index >= ARRAY_SIZE(sitar->comp_gain_offset))) {
652 pr_err("%s: Out of array boundary\n", __func__);
653 return -EINVAL;
654 }
655
656 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0)) {
657 gain_offset->whole_db_gain = COMP_DIGITAL_DB_GAIN_APPLY(
658 (digital_vol - comp_dgtl_gain[pa_gain & 0xF].whole_db_gain),
659 comp_dgtl_gain[pa_gain & 0xF].half_db_gain);
660 pr_debug("%s: listed whole_db_gain:0x%x, adjusted whole_db_gain:0x%x\n",
661 __func__, comp_dgtl_gain[pa_gain & 0xF].whole_db_gain,
662 gain_offset->whole_db_gain);
663 gain_offset->half_db_gain =
664 comp_dgtl_gain[pa_gain & 0xF].half_db_gain;
665 sitar->comp_gain_offset[index] = digital_vol -
666 gain_offset->whole_db_gain ;
667 }
668 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0)) {
669 gain_offset->whole_db_gain = digital_vol +
670 sitar->comp_gain_offset[index];
671 pr_debug("%s: listed whole_db_gain:0x%x, adjusted whole_db_gain:0x%x\n",
672 __func__, comp_dgtl_gain[pa_gain & 0xF].whole_db_gain,
673 gain_offset->whole_db_gain);
674 gain_offset->half_db_gain = 0;
675 }
676
677 pr_debug("%s: half_db_gain(%d)whole_db_gain(0x%x)comp_gain_offset[%d](%d)\n",
678 __func__, gain_offset->half_db_gain,
679 gain_offset->whole_db_gain, index,
680 sitar->comp_gain_offset[index]);
681 return 0;
682}
683
684static int sitar_config_gain_compander(
685 struct snd_soc_codec *codec,
686 u32 compander, u32 enable, int event)
687{
688 int value = 0;
689 int mask = 1 << 4;
690 struct comp_dgtl_gain_offset gain_offset = {0, 0};
691 if (compander >= COMPANDER_MAX) {
692 pr_err("%s: Error, invalid compander channel\n", __func__);
693 return -EINVAL;
694 }
695
696 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
697 value = 1 << 4;
698
699 if (compander == COMPANDER_1) {
700 sitar_compander_gain_offset(codec, enable,
701 SITAR_A_RX_HPH_L_GAIN,
702 SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
703 mask, event, &gain_offset, 1);
704 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_GAIN, mask, value);
705 snd_soc_update_bits(codec, SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
706 0xFF, gain_offset.whole_db_gain);
707 snd_soc_update_bits(codec, SITAR_A_CDC_RX2_B6_CTL,
708 0x02, gain_offset.half_db_gain);
709 sitar_compander_gain_offset(codec, enable,
710 SITAR_A_RX_HPH_R_GAIN,
711 SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
712 mask, event, &gain_offset, 2);
713 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_GAIN, mask, value);
714 snd_soc_update_bits(codec, SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
715 0xFF, gain_offset.whole_db_gain);
716 snd_soc_update_bits(codec, SITAR_A_CDC_RX3_B6_CTL,
717 0x02, gain_offset.half_db_gain);
718 } else if (compander == COMPANDER_2) {
719 sitar_compander_gain_offset(codec, enable,
720 SITAR_A_RX_LINE_1_GAIN,
721 SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
722 mask, event, &gain_offset, 0);
723 snd_soc_update_bits(codec, SITAR_A_RX_LINE_1_GAIN, mask, value);
724 snd_soc_update_bits(codec, SITAR_A_RX_LINE_2_GAIN, mask, value);
725 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
726 0xFF, gain_offset.whole_db_gain);
727 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
728 0x02, gain_offset.half_db_gain);
729 }
730 return 0;
731}
732
733static int sitar_get_compander(struct snd_kcontrol *kcontrol,
734 struct snd_ctl_elem_value *ucontrol)
735{
736 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
737 int comp = ((struct soc_multi_mixer_control *)
738 kcontrol->private_value)->shift;
739 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
740
741 ucontrol->value.integer.value[0] = sitar->comp_enabled[comp];
742
743 return 0;
744}
745
746static int sitar_set_compander(struct snd_kcontrol *kcontrol,
747 struct snd_ctl_elem_value *ucontrol)
748{
749 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
750 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
751 int comp = ((struct soc_multi_mixer_control *)
752 kcontrol->private_value)->shift;
753 int value = ucontrol->value.integer.value[0];
754
755 pr_debug("%s: compander #%d enable %d\n",
756 __func__, comp + 1, value);
757 if (value == sitar->comp_enabled[comp]) {
758 pr_debug("%s: compander #%d enable %d no change\n",
759 __func__, comp + 1, value);
760 return 0;
761 }
762 sitar->comp_enabled[comp] = value;
763 return 0;
764}
765
766static int sitar_config_compander(struct snd_soc_dapm_widget *w,
767 struct snd_kcontrol *kcontrol,
768 int event)
769{
770 struct snd_soc_codec *codec = w->codec;
771 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
772 u32 rate = sitar->comp_fs[w->shift];
773 u32 value;
774
775 pr_debug("%s: compander #%d enable %d event %d widget name %s\n",
776 __func__, w->shift + 1,
777 sitar->comp_enabled[w->shift], event , w->name);
778 if (sitar->comp_enabled[w->shift] == 0)
779 goto rtn;
780 switch (event) {
781 case SND_SOC_DAPM_PRE_PMU:
782 /* Update compander sample rate */
783 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_FS_CFG +
784 w->shift * 8, 0x07, rate);
785 /* Enable compander clock */
786 snd_soc_update_bits(codec,
787 SITAR_A_CDC_CLK_RX_B2_CTL,
788 1 << w->shift,
789 1 << w->shift);
790 /* Toggle compander reset bits */
791 snd_soc_update_bits(codec,
792 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
793 1 << w->shift,
794 1 << w->shift);
795 snd_soc_update_bits(codec,
796 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
797 1 << w->shift, 0);
798 sitar_config_gain_compander(codec, w->shift, 1, event);
799 /* Compander enable -> 0x370/0x378 */
800 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B1_CTL +
801 w->shift * 8, 0x03, 0x03);
802 /* Update the RMS meter resampling */
803 snd_soc_update_bits(codec,
804 SITAR_A_CDC_COMP1_B3_CTL +
805 w->shift * 8, 0xFF, 0x01);
806 snd_soc_update_bits(codec,
807 SITAR_A_CDC_COMP1_B2_CTL +
808 w->shift * 8, 0xF0, 0x50);
809 usleep_range(COMP_BRINGUP_WAIT_TIME, COMP_BRINGUP_WAIT_TIME);
810 break;
811 case SND_SOC_DAPM_POST_PMU:
812 snd_soc_update_bits(codec,
813 SITAR_A_CDC_CLSG_CTL,
814 0x11, 0x00);
815 if (w->shift == COMPANDER_1)
816 value = 0x22;
817 else
818 value = 0x11;
819 snd_soc_write(codec,
820 SITAR_A_CDC_CONN_CLSG_CTL, value);
821
822 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B2_CTL +
823 w->shift * 8, 0x0F,
824 comp_samp_params[rate].peak_det_timeout);
825 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B2_CTL +
826 w->shift * 8, 0xF0,
827 comp_samp_params[rate].rms_meter_div_fact);
828 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B3_CTL +
829 w->shift * 8, 0xFF,
830 comp_samp_params[rate].rms_meter_resamp_fact);
831 break;
832 case SND_SOC_DAPM_POST_PMD:
833 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B1_CTL +
834 w->shift * 8, 0x03, 0x00);
835 /* Toggle compander reset bits */
836 snd_soc_update_bits(codec,
837 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
838 1 << w->shift,
839 1 << w->shift);
840 snd_soc_update_bits(codec,
841 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
842 1 << w->shift, 0);
843 /* Disable compander clock */
844 snd_soc_update_bits(codec,
845 SITAR_A_CDC_CLK_RX_B2_CTL,
846 1 << w->shift,
847 0);
848 /* Restore the gain */
849 sitar_config_gain_compander(codec, w->shift,
850 sitar->comp_enabled[w->shift],
851 event);
852 snd_soc_update_bits(codec,
853 SITAR_A_CDC_CLSG_CTL,
854 0x11, 0x11);
855 snd_soc_write(codec,
856 SITAR_A_CDC_CONN_CLSG_CTL, 0x14);
857 break;
858 }
859rtn:
860 return 0;
861}
862
863static int sitar_codec_dem_input_selection(struct snd_soc_dapm_widget *w,
864 struct snd_kcontrol *kcontrol,
865 int event)
866{
867 struct snd_soc_codec *codec = w->codec;
868 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
869 pr_debug("%s: compander#1->enable(%d) compander#2->enable(%d) reg(0x%x = 0x%x) event(%d)\n",
870 __func__, sitar->comp_enabled[COMPANDER_1],
871 sitar->comp_enabled[COMPANDER_2],
872 SITAR_A_CDC_RX1_B6_CTL + w->shift * 8,
873 snd_soc_read(codec, SITAR_A_CDC_RX1_B6_CTL + w->shift * 8),
874 event);
875 switch (event) {
876 case SND_SOC_DAPM_POST_PMU:
877 if (sitar->comp_enabled[COMPANDER_1] ||
878 sitar->comp_enabled[COMPANDER_2])
879 snd_soc_update_bits(codec,
880 SITAR_A_CDC_RX1_B6_CTL +
881 w->shift * 8,
882 1 << 5, 0);
883 else
884 snd_soc_update_bits(codec,
885 SITAR_A_CDC_RX1_B6_CTL +
886 w->shift * 8,
887 1 << 5, 0x20);
888 break;
889 case SND_SOC_DAPM_POST_PMD:
890 snd_soc_update_bits(codec,
891 SITAR_A_CDC_RX1_B6_CTL + w->shift * 8,
892 1 << 5, 0);
893 break;
894 }
895 return 0;
896}
897
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700898static const char * const sitar_ear_pa_gain_text[] = {"POS_6_DB",
899 "POS_2_DB", "NEG_2P5_DB", "NEG_12_DB"};
900
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530901static const struct soc_enum sitar_ear_pa_gain_enum[] = {
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700902 SOC_ENUM_SINGLE_EXT(4, sitar_ear_pa_gain_text),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530903};
904
905/*cut of frequency for high pass filter*/
906static const char *cf_text[] = {
907 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
908};
909
910static const struct soc_enum cf_dec1_enum =
911 SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
912
913static const struct soc_enum cf_rxmix1_enum =
914 SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
915
916static const struct snd_kcontrol_new sitar_snd_controls[] = {
917
918 SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
919 sitar_pa_gain_get, sitar_pa_gain_put),
920
921 SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
922 line_gain),
923 SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
924 line_gain),
925
926 SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
927 line_gain),
928 SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
929 line_gain),
930
931 SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
932 -84, 40, digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800933 SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
934 -84, 40, digital_gain),
935 SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
936 -84, 40, digital_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530937
938 SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
939 digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800940 SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
941 digital_gain),
942 SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
943 digital_gain),
944 SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
945 digital_gain),
946
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530947 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
948 40, digital_gain),
949 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
950 40, digital_gain),
951 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
952 40, digital_gain),
953 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
954 40, digital_gain),
955 SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
956 SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800957 SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530958
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700959 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
960 sitar_put_anc_slot),
961
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530962 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
963
964 SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
965
966 SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
967
968 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
969
970 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
971 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
972 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
973 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
974 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
975 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
976 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
977 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
978 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
979 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
980 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
981 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
982 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
983 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
984 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
985 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
986 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
987 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
988 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
989 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
990
991 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
992 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
993 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
994 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
995 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
996 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
997 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
998 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
999 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1000 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1001 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1002 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1003 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1004 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1005 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1006 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1007 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1008 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1009 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1010 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
Kuirong Wang80dedd62012-12-07 19:16:24 +05301011 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
1012 sitar_get_compander, sitar_set_compander),
1013 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
1014 sitar_get_compander, sitar_set_compander),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301015};
1016
1017static const char *rx_mix1_text[] = {
1018 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1019 "RX5"
1020};
1021
1022static const char *rx_dac1_text[] = {
1023 "ZERO", "RX1", "RX2"
1024};
1025
1026static const char *rx_dac2_text[] = {
1027 "ZERO", "RX1",
1028};
1029
1030static const char *rx_dac3_text[] = {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001031 "ZERO", "RX1", "INV_RX1", "RX2"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301032};
1033
1034static const char *rx_dac4_text[] = {
1035 "ZERO", "ON"
1036};
1037
1038static const char *sb_tx1_mux_text[] = {
1039 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1040 "DEC1"
1041};
1042
1043static const char *sb_tx2_mux_text[] = {
1044 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1045 "DEC2"
1046};
1047
1048static const char *sb_tx3_mux_text[] = {
1049 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1050 "DEC3"
1051};
1052
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001053static const char *sb_tx4_mux_text[] = {
1054 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1055 "DEC4"
1056};
1057
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301058static const char *sb_tx5_mux_text[] = {
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001059 "ZERO", "RMIX1", "RMIX2", "RMIX3", "DEC1", "DEC2", "DEC3", "DEC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301060};
1061
1062static const char *dec1_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001063 "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301064};
1065
1066static const char *dec2_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001067 "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301068};
1069
1070static const char *dec3_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001071 "ZERO", "DMIC3", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC2", "DMIC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301072};
1073
1074static const char *dec4_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001075 "ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301076};
1077
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001078static const char const *anc_mux_text[] = {
1079 "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
1080 "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
1081};
1082
1083static const char const *anc1_fb_mux_text[] = {
1084 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1085};
1086
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301087static const char const *iir_inp1_text[] = {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301088 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
1089 "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
1090};
1091
1092static const struct soc_enum rx_mix1_inp1_chain_enum =
1093 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
1094
1095static const struct soc_enum rx_mix1_inp2_chain_enum =
1096 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
1097
1098static const struct soc_enum rx2_mix1_inp1_chain_enum =
1099 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
1100
1101static const struct soc_enum rx2_mix1_inp2_chain_enum =
1102 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
1103
1104static const struct soc_enum rx3_mix1_inp1_chain_enum =
1105 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
1106
1107static const struct soc_enum rx3_mix1_inp2_chain_enum =
1108 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
1109
1110static const struct soc_enum rx_dac1_enum =
1111 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
1112
1113static const struct soc_enum rx_dac2_enum =
1114 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
1115
1116static const struct soc_enum rx_dac3_enum =
1117 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
1118
1119static const struct soc_enum rx_dac4_enum =
1120 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
1121
1122static const struct soc_enum sb_tx5_mux_enum =
1123 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1124
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001125static const struct soc_enum sb_tx4_mux_enum =
1126 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
1127
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301128static const struct soc_enum sb_tx3_mux_enum =
1129 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
1130
1131static const struct soc_enum sb_tx2_mux_enum =
1132 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
1133
1134static const struct soc_enum sb_tx1_mux_enum =
1135 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1136
1137static const struct soc_enum dec1_mux_enum =
1138 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
1139
1140static const struct soc_enum dec2_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001141 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301142
1143static const struct soc_enum dec3_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001144 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301145
1146static const struct soc_enum dec4_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001147 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301148
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001149static const struct soc_enum anc1_mux_enum =
1150 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
1151
1152static const struct soc_enum anc2_mux_enum =
1153 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
1154
1155static const struct soc_enum anc1_fb_mux_enum =
1156 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1157
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301158static const struct soc_enum iir1_inp1_mux_enum =
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301159 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir_inp1_text);
1160
1161static const struct soc_enum iir2_inp1_mux_enum =
1162 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ2_B1_CTL, 0, 16, iir_inp1_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301163
1164static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1165 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1166
1167static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1168 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1169
1170static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1171 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1172
1173static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1174 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1175
1176static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1177 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1178
1179static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1180 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1181
1182static const struct snd_kcontrol_new rx_dac1_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001183 SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301184
1185static const struct snd_kcontrol_new rx_dac2_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001186 SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301187
1188static const struct snd_kcontrol_new rx_dac3_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001189 SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301190
1191static const struct snd_kcontrol_new rx_dac4_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001192 SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301193
1194static const struct snd_kcontrol_new sb_tx5_mux =
1195 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1196
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001197static const struct snd_kcontrol_new sb_tx4_mux =
1198 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1199
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301200static const struct snd_kcontrol_new sb_tx3_mux =
1201 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1202
1203static const struct snd_kcontrol_new sb_tx2_mux =
1204 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1205
1206static const struct snd_kcontrol_new sb_tx1_mux =
1207 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1208
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301209static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
1210 struct snd_ctl_elem_value *ucontrol)
1211 {
1212 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1213 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1214 struct snd_soc_codec *codec = w->codec;
1215 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1216 unsigned int dec_mux, decimator;
1217 char *dec_name = NULL;
1218 char *widget_name = NULL;
1219 char *temp;
1220 u16 tx_mux_ctl_reg;
1221 u8 adc_dmic_sel = 0x0;
1222 int ret = 0;
1223
1224 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1225 return -EINVAL;
1226
1227 dec_mux = ucontrol->value.enumerated.item[0];
1228
1229 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1230 if (!widget_name)
1231 return -ENOMEM;
1232 temp = widget_name;
1233
1234 dec_name = strsep(&widget_name, " ");
1235 widget_name = temp;
1236 if (!dec_name) {
1237 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1238 ret = -EINVAL;
1239 goto out;
1240 }
1241
1242 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1243 if (ret < 0) {
1244 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1245 ret = -EINVAL;
1246 goto out;
1247 }
1248
1249 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
1250 "dec_mux = %u\n", __func__, w->name, dec_name, decimator,
1251 dec_mux);
1252
1253
1254 switch (decimator) {
1255 case 1:
1256 case 2:
1257 if ((dec_mux == 1) || (dec_mux == 6))
1258 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
1259 else
1260 adc_dmic_sel = ADC_DMIC_SEL_ADC;
1261 break;
1262 case 3:
1263 if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
1264 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
1265 else
1266 adc_dmic_sel = ADC_DMIC_SEL_ADC;
1267 break;
1268 case 4:
1269 if ((dec_mux == 1) || (dec_mux == 5)
1270 || (dec_mux == 6) || (dec_mux == 7))
1271 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
1272 else
1273 adc_dmic_sel = ADC_DMIC_SEL_ADC;
1274 break;
1275 default:
1276 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1277 ret = -EINVAL;
1278 goto out;
1279 }
1280
1281 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1282
1283 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1284
1285 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1286out:
1287 kfree(widget_name);
1288 return ret;
1289}
1290
1291#define WCD9304_DEC_ENUM(xname, xenum) \
1292{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1293 .info = snd_soc_info_enum_double, \
1294 .get = snd_soc_dapm_get_enum_double, \
1295 .put = wcd9304_put_dec_enum, \
1296 .private_value = (unsigned long)&xenum }
1297
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301298static const struct snd_kcontrol_new dec1_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301299 WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301300
1301static const struct snd_kcontrol_new dec2_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301302 WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301303
1304static const struct snd_kcontrol_new dec3_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301305 WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301306
1307static const struct snd_kcontrol_new dec4_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301308 WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301309
1310static const struct snd_kcontrol_new iir1_inp1_mux =
1311 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1312
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301313static const struct snd_kcontrol_new iir2_inp1_mux =
1314 SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
1315
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001316static const struct snd_kcontrol_new anc1_mux =
1317 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1318
1319static const struct snd_kcontrol_new anc2_mux =
1320 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
1321
1322static const struct snd_kcontrol_new anc1_fb_mux =
1323 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
1324
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301325static const struct snd_kcontrol_new dac1_switch[] = {
1326 SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
1327};
1328
Kuirong Wang906ac472012-07-09 12:54:44 -07001329static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1330 struct snd_ctl_elem_value *ucontrol)
1331{
1332 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1333 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1334
1335 ucontrol->value.integer.value[0] = widget->value;
1336 return 0;
1337}
1338
1339static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1340 struct snd_ctl_elem_value *ucontrol)
1341{
1342 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1343 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1344 struct snd_soc_codec *codec = widget->codec;
1345 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
1346 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1347 struct soc_multi_mixer_control *mixer =
1348 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1349 u32 dai_id = widget->shift;
1350 u32 port_id = mixer->shift;
1351 u32 enable = ucontrol->value.integer.value[0];
1352
1353 mutex_lock(&codec->mutex);
1354
1355 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1356 if (dai_id != AIF1_CAP) {
1357 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1358 __func__);
1359 mutex_unlock(&codec->mutex);
1360 return -EINVAL;
1361 }
1362 }
1363
1364 switch (dai_id) {
1365 case AIF1_CAP:
1366 if (enable && !(widget->value & 1 << port_id)) {
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001367 if (wcd9xxx_tx_vport_validation(
1368 vport_check_table[dai_id],
1369 port_id,
1370 sitar_p->dai)) {
Kuirong Wang906ac472012-07-09 12:54:44 -07001371 pr_info("%s: TX%u is used by other virtual port\n",
1372 __func__, port_id + 1);
1373 mutex_unlock(&codec->mutex);
1374 return -EINVAL;
1375 }
1376 widget->value |= 1 << port_id;
1377 list_add_tail(&core->tx_chs[port_id].list,
1378 &sitar_p->dai[dai_id].wcd9xxx_ch_list);
1379 } else if (!enable && (widget->value & 1 << port_id)) {
1380 widget->value &= ~(1<<port_id);
1381 list_del_init(&core->tx_chs[port_id].list);
1382 } else {
1383 if (enable)
1384 pr_info("%s: TX%u port is used by this virtual port\n",
1385 __func__, port_id + 1);
1386 else
1387 pr_info("%s: TX%u port is not used by this virtual port\n",
1388 __func__, port_id + 1);
1389 /* avoid update power function */
1390 mutex_unlock(&codec->mutex);
1391 return 0;
1392 }
1393 break;
1394 default:
1395 pr_err("Unknown AIF %d\n", dai_id);
1396 mutex_unlock(&codec->mutex);
1397 return -EINVAL;
1398 }
1399
1400 pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
1401 widget->name, widget->sname, widget->value, widget->shift);
1402 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1403 mutex_unlock(&codec->mutex);
1404 return 0;
1405}
1406
1407static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1408 struct snd_ctl_elem_value *ucontrol)
1409{
1410 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1411 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1412
1413 ucontrol->value.enumerated.item[0] = widget->value;
1414 return 0;
1415}
1416
1417static const char * const slim_rx_mux_text[] = {
1418 "ZERO", "AIF1_PB"
1419};
1420
1421static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1422 struct snd_ctl_elem_value *ucontrol)
1423{
1424 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1425 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1426 struct snd_soc_codec *codec = widget->codec;
1427 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
1428 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1429 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1430 u32 port_id = widget->shift;
1431
1432 widget->value = ucontrol->value.enumerated.item[0];
1433
1434 mutex_lock(&codec->mutex);
1435
1436 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1437 if (widget->value > 1) {
1438 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1439 __func__);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001440 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001441 }
1442 }
1443
1444 switch (widget->value) {
1445 case 0:
1446 list_del_init(&core->rx_chs[port_id].list);
1447 break;
1448 case 1:
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001449 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
1450 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list))
1451 goto pr_err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001452 list_add_tail(&core->rx_chs[port_id].list,
1453 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
1454 break;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001455 break;
Kuirong Wang906ac472012-07-09 12:54:44 -07001456 default:
1457 pr_err("Unknown AIF %d\n", widget->value);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001458 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001459 }
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001460
1461
Kuirong Wang906ac472012-07-09 12:54:44 -07001462 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001463
Kuirong Wang906ac472012-07-09 12:54:44 -07001464 mutex_unlock(&codec->mutex);
1465 return 0;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001466pr_err:
1467 pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
1468 __func__, port_id + 1);
1469err:
1470 mutex_unlock(&codec->mutex);
1471 return -EINVAL;
Kuirong Wang906ac472012-07-09 12:54:44 -07001472}
1473
1474static const struct soc_enum slim_rx_mux_enum =
1475 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1476
1477static const struct snd_kcontrol_new sitar_aif_pb_mux[SITAR_RX_MAX] = {
1478 SOC_DAPM_ENUM_EXT("SLIM RX1 MUX", slim_rx_mux_enum,
1479 slim_rx_mux_get, slim_rx_mux_put),
1480 SOC_DAPM_ENUM_EXT("SLIM RX2 MUX", slim_rx_mux_enum,
1481 slim_rx_mux_get, slim_rx_mux_put),
1482 SOC_DAPM_ENUM_EXT("SLIM RX3 MUX", slim_rx_mux_enum,
1483 slim_rx_mux_get, slim_rx_mux_put),
1484 SOC_DAPM_ENUM_EXT("SLIM RX4 MUX", slim_rx_mux_enum,
1485 slim_rx_mux_get, slim_rx_mux_put),
1486 SOC_DAPM_ENUM_EXT("SLIM RX5 MUX", slim_rx_mux_enum,
1487 slim_rx_mux_get, slim_rx_mux_put)
1488};
1489
1490static const struct snd_kcontrol_new sitar_aif_cap_mixer[SITAR_TX_MAX] = {
1491 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, SITAR_TX1, 1, 0,
1492 slim_tx_mixer_get, slim_tx_mixer_put),
1493 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, SITAR_TX2, 1, 0,
1494 slim_tx_mixer_get, slim_tx_mixer_put),
1495 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, SITAR_TX3, 1, 0,
1496 slim_tx_mixer_get, slim_tx_mixer_put),
1497 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, SITAR_TX4, 1, 0,
1498 slim_tx_mixer_get, slim_tx_mixer_put),
1499 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, SITAR_TX5, 1, 0,
1500 slim_tx_mixer_get, slim_tx_mixer_put),
1501};
1502
1503
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301504static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
1505 int enable)
1506{
1507 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1508
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301509 pr_debug("%s %d\n", __func__, enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301510
1511 if (enable) {
1512 sitar->adc_count++;
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001513 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL,
1514 0x02, 0x02);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301515 } else {
1516 sitar->adc_count--;
1517 if (!sitar->adc_count) {
1518 if (!sitar->mbhc_polling_active)
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001519 snd_soc_update_bits(codec,
1520 SITAR_A_CDC_CLK_OTHR_CTL, 0xE0, 0x0);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301521 }
1522 }
1523}
1524
1525static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
1526 struct snd_kcontrol *kcontrol, int event)
1527{
1528 struct snd_soc_codec *codec = w->codec;
1529 u16 adc_reg;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001530 u8 init_bit_shift;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301531
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301532 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301533
1534 if (w->reg == SITAR_A_TX_1_2_EN)
1535 adc_reg = SITAR_A_TX_1_2_TEST_CTL;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001536 else if (w->reg == SITAR_A_TX_3_EN)
1537 adc_reg = SITAR_A_TX_3_TEST_CTL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301538 else {
1539 pr_err("%s: Error, invalid adc register\n", __func__);
1540 return -EINVAL;
1541 }
1542
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001543 if (w->shift == 3)
1544 init_bit_shift = 6;
1545 else if (w->shift == 7)
1546 init_bit_shift = 7;
1547 else {
1548 pr_err("%s: Error, invalid init bit postion adc register\n",
1549 __func__);
1550 return -EINVAL;
1551 }
1552
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301553 switch (event) {
1554 case SND_SOC_DAPM_PRE_PMU:
1555 sitar_codec_enable_adc_block(codec, 1);
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001556 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1557 1 << init_bit_shift);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301558 break;
1559 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001560
1561 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1562
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301563 break;
1564 case SND_SOC_DAPM_POST_PMD:
1565 sitar_codec_enable_adc_block(codec, 0);
1566 break;
1567 }
1568 return 0;
1569}
1570
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001571static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
1572 struct snd_kcontrol *kcontrol, int event)
1573{
1574 struct snd_soc_codec *codec = w->codec;
1575
1576 pr_debug("%s %s %d\n", __func__, w->name, event);
1577
1578 switch (event) {
1579 case SND_SOC_DAPM_PRE_PMU:
1580 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1581 break;
1582
1583 case SND_SOC_DAPM_POST_PMD:
1584 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1585 break;
1586 }
1587 return 0;
1588}
1589
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001590static void sitar_enable_classg(struct snd_soc_codec *codec,
1591 bool enable)
1592{
1593
1594 if (enable) {
1595 snd_soc_update_bits(codec,
1596 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x00);
1597 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x00);
1598 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
1599 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
1600
1601 } else {
1602 snd_soc_update_bits(codec,
1603 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x10);
1604 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x03);
1605 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
1606 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
1607 }
1608}
1609
1610static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
1611{
1612 u8 hph_reg_val = 0;
1613 hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
1614
1615 return (hph_reg_val & 0x30) ? true : false;
1616}
1617
1618static bool sitar_is_line_pa_on(struct snd_soc_codec *codec)
1619{
1620 u8 line_reg_val = 0;
1621 line_reg_val = snd_soc_read(codec, SITAR_A_RX_LINE_CNP_EN);
1622
1623 return (line_reg_val & 0x03) ? true : false;
1624}
1625
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301626static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1627 struct snd_kcontrol *kcontrol, int event)
1628{
1629 struct snd_soc_codec *codec = w->codec;
Kuirong Wang80dedd62012-12-07 19:16:24 +05301630 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301631 u16 lineout_gain_reg;
1632
Kuirong Wang80dedd62012-12-07 19:16:24 +05301633 pr_debug("%s %d %s comp2 enable %d\n", __func__, event, w->name,
1634 sitar->comp_enabled[COMPANDER_2]);
1635
1636 if (sitar->comp_enabled[COMPANDER_2])
1637 goto rtn;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301638
1639 switch (w->shift) {
1640 case 0:
1641 lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
1642 break;
1643 case 1:
1644 lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
1645 break;
1646 default:
1647 pr_err("%s: Error, incorrect lineout register value\n",
1648 __func__);
1649 return -EINVAL;
1650 }
1651
1652 switch (event) {
1653 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001654 if (sitar_is_hph_pa_on(codec)) {
1655 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1656 0x20, 0x00);
1657 sitar_enable_classg(codec, false);
1658 } else {
1659 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1660 0x20, 0x20);
1661 sitar_enable_classg(codec, true);
1662 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001663 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301664 break;
1665 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001666 pr_debug("%s: sleeping 32 ms after %s PA turn on\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301667 __func__, w->name);
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001668 usleep_range(32000, 32000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301669 break;
1670 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001671 if (sitar_is_hph_pa_on(codec))
1672 sitar_enable_classg(codec, true);
1673 else
1674 sitar_enable_classg(codec, false);
1675
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001676 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301677 break;
1678 }
Kuirong Wang80dedd62012-12-07 19:16:24 +05301679rtn:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301680 return 0;
1681}
1682
1683static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1684 struct snd_kcontrol *kcontrol, int event)
1685{
1686 struct snd_soc_codec *codec = w->codec;
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301687 u16 tx_dmic_ctl_reg;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301688 u8 dmic_clk_sel, dmic_clk_en;
1689 unsigned int dmic;
1690 int ret;
1691
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001692 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301693 if (ret < 0) {
1694 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1695 return -EINVAL;
1696 }
1697
1698 switch (dmic) {
1699 case 1:
1700 case 2:
1701 dmic_clk_sel = 0x02;
1702 dmic_clk_en = 0x01;
1703 break;
1704 case 3:
1705 case 4:
1706 dmic_clk_sel = 0x08;
1707 dmic_clk_en = 0x04;
1708 break;
1709
1710 break;
1711
1712 default:
1713 pr_err("%s: Invalid DMIC Selection\n", __func__);
1714 return -EINVAL;
1715 }
1716
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301717 tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1718
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301719 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301720
1721 switch (event) {
1722 case SND_SOC_DAPM_PRE_PMU:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301723 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1724 dmic_clk_sel, dmic_clk_sel);
1725
1726 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1727
1728 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1729 dmic_clk_en, dmic_clk_en);
1730 break;
1731 case SND_SOC_DAPM_POST_PMD:
1732 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1733 dmic_clk_en, 0);
1734 break;
1735 }
1736 return 0;
1737}
1738
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001739static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
1740 struct snd_kcontrol *kcontrol, int event)
1741{
1742 struct snd_soc_codec *codec = w->codec;
1743 const char *filename;
1744 const struct firmware *fw;
1745 int i;
1746 int ret;
1747 int num_anc_slots;
1748 struct anc_header *anc_head;
1749 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1750 u32 anc_writes_size = 0;
1751 int anc_size_remaining;
1752 u32 *anc_ptr;
1753 u16 reg;
1754 u8 mask, val, old_val;
1755
1756 pr_debug("%s %d\n", __func__, event);
1757 switch (event) {
1758 case SND_SOC_DAPM_PRE_PMU:
1759
1760 /* Use the same firmware file as that of WCD9310,
1761 * since the register sequences are same for
1762 * WCD9310 and WCD9304
1763 */
1764 filename = "wcd9310/wcd9310_anc.bin";
1765
1766 ret = request_firmware(&fw, filename, codec->dev);
1767 if (ret != 0) {
1768 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1769 ret);
1770 return -ENODEV;
1771 }
1772
1773 if (fw->size < sizeof(struct anc_header)) {
1774 dev_err(codec->dev, "Not enough data\n");
1775 release_firmware(fw);
1776 return -ENOMEM;
1777 }
1778
1779 /* First number is the number of register writes */
1780 anc_head = (struct anc_header *)(fw->data);
1781 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1782 anc_size_remaining = fw->size - sizeof(struct anc_header);
1783 num_anc_slots = anc_head->num_anc_slots;
1784
1785 if (sitar->anc_slot >= num_anc_slots) {
1786 dev_err(codec->dev, "Invalid ANC slot selected\n");
1787 release_firmware(fw);
1788 return -EINVAL;
1789 }
1790
1791 for (i = 0; i < num_anc_slots; i++) {
1792
1793 if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
1794 dev_err(codec->dev, "Invalid register format\n");
1795 release_firmware(fw);
1796 return -EINVAL;
1797 }
1798 anc_writes_size = (u32)(*anc_ptr);
1799 anc_size_remaining -= sizeof(u32);
1800 anc_ptr += 1;
1801
1802 if (anc_writes_size * SITAR_PACKED_REG_SIZE
1803 > anc_size_remaining) {
1804 dev_err(codec->dev, "Invalid register format\n");
1805 release_firmware(fw);
1806 return -ENOMEM;
1807 }
1808
1809 if (sitar->anc_slot == i)
1810 break;
1811
1812 anc_size_remaining -= (anc_writes_size *
1813 SITAR_PACKED_REG_SIZE);
1814 anc_ptr += anc_writes_size;
1815 }
1816 if (i == num_anc_slots) {
1817 dev_err(codec->dev, "Selected ANC slot not present\n");
1818 release_firmware(fw);
1819 return -ENOMEM;
1820 }
1821
1822 for (i = 0; i < anc_writes_size; i++) {
1823 SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1824 mask, val);
1825 old_val = snd_soc_read(codec, reg);
1826 snd_soc_write(codec, reg, (old_val & ~mask) |
1827 (val & mask));
1828 }
1829
1830 release_firmware(fw);
1831
1832 /* For Sitar, it is required to enable both Feed-forward
1833 * and Feed back clocks to enable ANC
1834 */
1835 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
1836
1837 break;
1838
1839 case SND_SOC_DAPM_POST_PMD:
1840 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1841 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
1842 break;
1843 }
1844 return 0;
1845}
1846
1847
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301848static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
1849{
1850 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001851 int mbhc_state = sitar->mbhc_state;
1852
1853 pr_debug("%s: enter\n", __func__);
1854 if (!sitar->mbhc_polling_active) {
1855 pr_debug("Polling is not active, do not start polling\n");
1856 return;
1857 }
1858 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
1859
1860
1861 if (!sitar->no_mic_headset_override) {
1862 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1863 pr_debug("%s recovering MBHC state macine\n", __func__);
1864 sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
1865 /* set to max button press threshold */
1866 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
1867 0x7F);
1868 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
1869 0xFF);
1870 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
1871 0x7F);
1872 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
1873 0xFF);
1874 /* set to max */
1875 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
1876 0x7F);
1877 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
1878 0xFF);
1879 }
1880 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301881
1882 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001883 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
1884 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1885 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301886}
1887
1888static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
1889{
1890 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1891
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001892 pr_debug("%s: enter\n", __func__);
1893 if (!sitar->mbhc_polling_active) {
1894 pr_debug("polling not active, nothing to pause\n");
1895 return;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301896 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001897
1898 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1899 pr_debug("%s: leave\n", __func__);
1900
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301901}
1902
1903static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1904 int mode)
1905{
1906 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1907 u8 reg_mode_val, cur_mode_val;
1908 bool mbhc_was_polling = false;
1909
1910 if (mode)
1911 reg_mode_val = SITAR_CFILT_FAST_MODE;
1912 else
1913 reg_mode_val = SITAR_CFILT_SLOW_MODE;
1914
1915 cur_mode_val = snd_soc_read(codec,
1916 sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
1917
1918 if (cur_mode_val != reg_mode_val) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001919 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301920 if (sitar->mbhc_polling_active) {
1921 sitar_codec_pause_hs_polling(codec);
1922 mbhc_was_polling = true;
1923 }
1924 snd_soc_update_bits(codec,
1925 sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1926 if (mbhc_was_polling)
1927 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001928 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301929 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301930 cur_mode_val, reg_mode_val);
1931 } else {
1932 pr_err("%s: CFILT Value is already %x\n",
1933 __func__, cur_mode_val);
1934 }
1935}
1936
1937static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1938 u8 cfilt_sel, int inc)
1939{
1940 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1941 u32 *cfilt_cnt_ptr = NULL;
1942 u16 micb_cfilt_reg;
1943
1944 switch (cfilt_sel) {
1945 case SITAR_CFILT1_SEL:
1946 cfilt_cnt_ptr = &sitar->cfilt1_cnt;
1947 micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
1948 break;
1949 case SITAR_CFILT2_SEL:
1950 cfilt_cnt_ptr = &sitar->cfilt2_cnt;
1951 micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
1952 break;
1953 default:
1954 return; /* should not happen */
1955 }
1956
1957 if (inc) {
1958 if (!(*cfilt_cnt_ptr)++) {
1959 /* Switch CFILT to slow mode if MBHC CFILT being used */
1960 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1961 sitar_codec_switch_cfilt_mode(codec, 0);
1962
1963 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1964 }
1965 } else {
1966 /* check if count not zero, decrement
1967 * then check if zero, go ahead disable cfilter
1968 */
1969 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1970 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1971
1972 /* Switch CFILT to fast mode if MBHC CFILT being used */
1973 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1974 sitar_codec_switch_cfilt_mode(codec, 1);
1975 }
1976 }
1977}
1978
1979static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1980{
1981 int rc = -EINVAL;
1982 unsigned min_mv, max_mv;
1983
1984 switch (ldoh_v) {
1985 case SITAR_LDOH_1P95_V:
1986 min_mv = 160;
1987 max_mv = 1800;
1988 break;
1989 case SITAR_LDOH_2P35_V:
1990 min_mv = 200;
1991 max_mv = 2200;
1992 break;
1993 case SITAR_LDOH_2P75_V:
1994 min_mv = 240;
1995 max_mv = 2600;
1996 break;
1997 case SITAR_LDOH_2P85_V:
1998 min_mv = 250;
1999 max_mv = 2700;
2000 break;
2001 default:
2002 goto done;
2003 }
2004
2005 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2006 goto done;
2007
2008 for (rc = 4; rc <= 44; rc++) {
2009 min_mv = max_mv * (rc) / 44;
2010 if (min_mv >= cfilt_mv) {
2011 rc -= 4;
2012 break;
2013 }
2014 }
2015done:
2016 return rc;
2017}
2018
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302019static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2020{
2021 u8 hph_reg_val = 0;
2022 if (left)
2023 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002024 SITAR_A_RX_HPH_L_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302025 else
2026 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002027 SITAR_A_RX_HPH_R_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302028
2029 return (hph_reg_val & 0xC0) ? true : false;
2030}
2031
2032static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
2033 int vddio_switch)
2034{
2035 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2036 int cfilt_k_val;
2037 bool mbhc_was_polling = false;
2038
2039 switch (vddio_switch) {
2040 case 1:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002041 if (sitar->mbhc_micbias_switched == 0 &&
2042 sitar->mbhc_polling_active) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302043
2044 sitar_codec_pause_hs_polling(codec);
2045 /* Enable Mic Bias switch to VDDIO */
2046 sitar->cfilt_k_value = snd_soc_read(codec,
2047 sitar->mbhc_bias_regs.cfilt_val);
2048 cfilt_k_val = sitar_find_k_value(
2049 sitar->pdata->micbias.ldoh_v, 1800);
2050 snd_soc_update_bits(codec,
2051 sitar->mbhc_bias_regs.cfilt_val,
2052 0xFC, (cfilt_k_val << 2));
2053
2054 snd_soc_update_bits(codec,
2055 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
2056 snd_soc_update_bits(codec,
2057 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2058 sitar_codec_start_hs_polling(codec);
2059
2060 sitar->mbhc_micbias_switched = true;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302061 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302062 __func__);
2063 }
2064 break;
2065
2066 case 0:
2067 if (sitar->mbhc_micbias_switched) {
2068 if (sitar->mbhc_polling_active) {
2069 sitar_codec_pause_hs_polling(codec);
2070 mbhc_was_polling = true;
2071 }
2072 /* Disable Mic Bias switch to VDDIO */
2073 if (sitar->cfilt_k_value != 0)
2074 snd_soc_update_bits(codec,
2075 sitar->mbhc_bias_regs.cfilt_val, 0XFC,
2076 sitar->cfilt_k_value);
2077 snd_soc_update_bits(codec,
2078 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2079 snd_soc_update_bits(codec,
2080 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2081
2082 if (mbhc_was_polling)
2083 sitar_codec_start_hs_polling(codec);
2084
2085 sitar->mbhc_micbias_switched = false;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302086 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302087 __func__);
2088 }
2089 break;
2090 }
2091}
2092
2093static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2094 struct snd_kcontrol *kcontrol, int event)
2095{
2096 struct snd_soc_codec *codec = w->codec;
2097 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2098 u16 micb_int_reg;
2099 int micb_line;
2100 u8 cfilt_sel_val = 0;
2101 char *internal1_text = "Internal1";
2102 char *internal2_text = "Internal2";
2103
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302104 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302105 switch (w->reg) {
2106 case SITAR_A_MICB_1_CTL:
2107 micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
2108 cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
2109 micb_line = SITAR_MICBIAS1;
2110 break;
2111 case SITAR_A_MICB_2_CTL:
2112 micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
2113 cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
2114 micb_line = SITAR_MICBIAS2;
2115 break;
2116 default:
2117 pr_err("%s: Error, invalid micbias register\n", __func__);
2118 return -EINVAL;
2119 }
2120
2121 switch (event) {
2122 case SND_SOC_DAPM_PRE_PMU:
2123 /* Decide whether to switch the micbias for MBHC */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002124 if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
2125 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302126 sitar_codec_switch_micbias(codec, 0);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002127 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
2128 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302129
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002130 snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302131 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
2132
2133 if (strnstr(w->name, internal1_text, 30))
2134 snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
2135 else if (strnstr(w->name, internal2_text, 30))
2136 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2137 break;
2138 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002139
2140 usleep_range(20000, 20000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302141 if (sitar->mbhc_polling_active &&
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07002142 sitar->mbhc_cfg.micbias == micb_line) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002143 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302144 sitar_codec_pause_hs_polling(codec);
2145 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002146 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302147 }
2148 break;
2149 case SND_SOC_DAPM_POST_PMD:
2150
2151 if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
2152 && sitar_is_hph_pa_on(codec))
2153 sitar_codec_switch_micbias(codec, 1);
2154
2155 if (strnstr(w->name, internal1_text, 30))
2156 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
2157 else if (strnstr(w->name, internal2_text, 30))
2158 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2159 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
2160 break;
2161 }
2162
2163 return 0;
2164}
2165
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002166static void tx_hpf_corner_freq_callback(struct work_struct *work)
2167{
2168 struct delayed_work *hpf_delayed_work;
2169 struct hpf_work *hpf_work;
2170 struct sitar_priv *sitar;
2171 struct snd_soc_codec *codec;
2172 u16 tx_mux_ctl_reg;
2173 u8 hpf_cut_of_freq;
2174
2175 hpf_delayed_work = to_delayed_work(work);
2176 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2177 sitar = hpf_work->sitar;
2178 codec = hpf_work->sitar->codec;
2179 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2180
2181 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL +
2182 (hpf_work->decimator - 1) * 8;
2183
2184 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2185 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2186
2187 snd_soc_update_bits(codec, tx_mux_ctl_reg,
2188 CUT_OF_FREQ_MASK, hpf_cut_of_freq << 4);
2189}
2190
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302191static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
2192 struct snd_kcontrol *kcontrol, int event)
2193{
2194 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002195 u16 dec_reset_reg, gain_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2196 unsigned int decimator;
2197 char *dec_name = NULL;
2198 char *widget_name = NULL;
2199 char *temp;
2200 int ret = 0;
2201 u8 dec_hpf_cut_of_freq, current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302202
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302203 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302204
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002205 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2206 if (!widget_name)
2207 return -ENOMEM;
2208 temp = widget_name;
2209
2210 dec_name = strsep(&widget_name, " ");
2211 widget_name = temp;
2212 if (!dec_name) {
2213 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2214 ret = -EINVAL;
2215 goto out;
2216 }
2217
2218 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
2219 if (ret < 0) {
2220 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2221 ret = -EINVAL;
2222 goto out;
2223 }
2224
2225 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2226 w->name, dec_name, decimator);
2227
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302228 if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2229 dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
2230 else {
2231 pr_err("%s: Error, incorrect dec\n", __func__);
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002232 ret = EINVAL;
2233 goto out;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302234 }
2235
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002236 tx_vol_ctl_reg = SITAR_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
2237 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2238
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302239 switch (event) {
2240 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002241 /* Enable TX Digital Mute */
2242 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2243
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302244 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2245 1 << w->shift);
2246 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002247
2248 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2249 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq &
2250 CUT_OF_FREQ_MASK) >> 4;
2251
2252 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2253 dec_hpf_cut_of_freq;
2254
2255 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2256 /* Set cut off freq to CF_MIN_3DB_150HZ (0x01) */
2257 snd_soc_update_bits(codec, tx_mux_ctl_reg,
2258 CUT_OF_FREQ_MASK, CF_MIN_3DB_150HZ << 4);
2259 }
2260
2261 /* enable HPF */
2262 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
2263
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302264 break;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002265
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002266 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002267 /* Disable TX Digital Mute */
2268 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2269
2270 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2271 CF_MIN_3DB_150HZ) {
2272 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2273 msecs_to_jiffies(300));
2274 }
2275
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002276 /* Reprogram the digital gain after power up of Decimator */
2277 gain_reg = SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * w->shift);
2278 current_gain = snd_soc_read(codec, gain_reg);
2279 snd_soc_write(codec, gain_reg, current_gain);
2280 break;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002281
2282 case SND_SOC_DAPM_PRE_PMD:
2283 /* Enable Digital Mute, Cancel possibly scheduled work */
2284 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2285 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2286
2287 break;
2288
2289 case SND_SOC_DAPM_POST_PMD:
2290 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2291 snd_soc_update_bits(codec, tx_mux_ctl_reg, CUT_OF_FREQ_MASK,
2292 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2293 break;
2294
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302295 }
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002296
2297out:
2298 kfree(widget_name);
2299 return ret;
2300
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302301}
2302
2303static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
2304 struct snd_kcontrol *kcontrol, int event)
2305{
2306 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002307 u16 gain_reg;
2308 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302309
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302310 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302311
2312 switch (event) {
2313 case SND_SOC_DAPM_PRE_PMU:
2314 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
2315 1 << w->shift, 1 << w->shift);
2316 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
2317 1 << w->shift, 0x0);
2318 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002319 case SND_SOC_DAPM_POST_PMU:
2320 /* Reprogram gain after power up interpolator */
2321 gain_reg = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * w->shift);
2322 current_gain = snd_soc_read(codec, gain_reg);
2323 snd_soc_write(codec, gain_reg, current_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302324 }
2325 return 0;
2326}
2327
2328static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2329 struct snd_kcontrol *kcontrol, int event)
2330{
2331 switch (event) {
2332 case SND_SOC_DAPM_POST_PMU:
2333 case SND_SOC_DAPM_POST_PMD:
2334 usleep_range(1000, 1000);
2335 pr_debug("LDO_H\n");
2336 break;
2337 }
2338 return 0;
2339}
2340
2341static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
2342{
2343 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2344
2345 if (enable) {
2346 sitar->rx_bias_count++;
2347 if (sitar->rx_bias_count == 1)
2348 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
2349 0x80, 0x80);
2350 } else {
2351 sitar->rx_bias_count--;
2352 if (!sitar->rx_bias_count)
2353 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
2354 0x80, 0x00);
2355 }
2356}
2357
2358static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2359 struct snd_kcontrol *kcontrol, int event)
2360{
2361 struct snd_soc_codec *codec = w->codec;
2362
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302363 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302364
2365 switch (event) {
2366 case SND_SOC_DAPM_PRE_PMU:
2367 sitar_enable_rx_bias(codec, 1);
2368 break;
2369 case SND_SOC_DAPM_POST_PMD:
2370 sitar_enable_rx_bias(codec, 0);
2371 break;
2372 }
2373 return 0;
2374}
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002375static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302376 struct snd_kcontrol *kcontrol, int event)
2377{
2378 struct snd_soc_codec *codec = w->codec;
Kuirong Wang80dedd62012-12-07 19:16:24 +05302379 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302380
Kuirong Wang80dedd62012-12-07 19:16:24 +05302381 pr_debug("%s %s %d comp#1 enable %d\n", __func__,
2382 w->name, event, sitar->comp_enabled[COMPANDER_1]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302383
2384 switch (event) {
2385 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002386 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
Kuirong Wang80dedd62012-12-07 19:16:24 +05302387 if (!sitar->comp_enabled[COMPANDER_1]) {
2388 snd_soc_update_bits(codec,
2389 SITAR_A_CDC_CONN_CLSG_CTL,
2390 0x30, 0x20);
2391 snd_soc_update_bits(codec,
2392 SITAR_A_CDC_CONN_CLSG_CTL,
2393 0x0C, 0x08);
2394 }
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002395 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302396 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2397 break;
2398 case SND_SOC_DAPM_POST_PMD:
2399 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002400 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
2401 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2402 0x30, 0x10);
2403 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2404 0x0C, 0x04);
2405 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302406 break;
2407 }
2408 return 0;
2409}
2410
2411static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
2412 struct snd_soc_jack *jack, int status,
2413 int mask)
2414{
2415 /* XXX: wake_lock_timeout()? */
Laxminath Kasamc24dc6f2012-12-07 11:10:35 +05302416 snd_soc_jack_report_no_dapm(jack, status, mask);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302417}
2418
2419static void hphocp_off_report(struct sitar_priv *sitar,
2420 u32 jack_status, int irq)
2421{
2422 struct snd_soc_codec *codec;
2423
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002424 if (!sitar) {
2425 pr_err("%s: Bad sitar private data\n", __func__);
2426 return;
2427 }
2428
2429 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
2430 codec = sitar->codec;
2431 if (sitar->hph_status & jack_status) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302432 sitar->hph_status &= ~jack_status;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002433 if (sitar->mbhc_cfg.headset_jack)
2434 sitar_snd_soc_jack_report(sitar,
2435 sitar->mbhc_cfg.headset_jack,
2436 sitar->hph_status,
2437 SITAR_JACK_MASK);
2438 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2439 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302440 /* reset retry counter as PA is turned off signifying
2441 * start of new OCP detection session
2442 */
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002443 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302444 sitar->hphlocp_cnt = 0;
2445 else
2446 sitar->hphrocp_cnt = 0;
2447 wcd9xxx_enable_irq(codec->control_data, irq);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302448 }
2449}
2450
2451static void hphlocp_off_report(struct work_struct *work)
2452{
2453 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
2454 hphlocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002455 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
2456 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302457}
2458
2459static void hphrocp_off_report(struct work_struct *work)
2460{
2461 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
2462 hphrocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002463 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
2464 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302465}
2466
2467static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
2468 struct snd_kcontrol *kcontrol, int event)
2469{
2470 struct snd_soc_codec *codec = w->codec;
2471 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2472 u8 mbhc_micb_ctl_val;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302473 pr_debug("%s: event = %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302474
2475 switch (event) {
2476 case SND_SOC_DAPM_PRE_PMU:
2477 mbhc_micb_ctl_val = snd_soc_read(codec,
2478 sitar->mbhc_bias_regs.ctl_reg);
2479
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002480 if (!(mbhc_micb_ctl_val & 0x80)) {
2481 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302482 sitar_codec_switch_micbias(codec, 1);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002483 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
2484 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302485
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002486 if (sitar_is_line_pa_on(codec))
2487 sitar_enable_classg(codec, false);
2488 else
2489 sitar_enable_classg(codec, true);
2490
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302491 break;
2492
2493 case SND_SOC_DAPM_POST_PMD:
2494 /* schedule work is required because at the time HPH PA DAPM
2495 * event callback is called by DAPM framework, CODEC dapm mutex
2496 * would have been locked while snd_soc_jack_report also
2497 * attempts to acquire same lock.
2498 */
2499 if (w->shift == 5) {
2500 clear_bit(SITAR_HPHL_PA_OFF_ACK,
2501 &sitar->hph_pa_dac_state);
2502 clear_bit(SITAR_HPHL_DAC_OFF_ACK,
2503 &sitar->hph_pa_dac_state);
2504 if (sitar->hph_status & SND_JACK_OC_HPHL)
2505 schedule_work(&sitar->hphlocp_work);
2506 } else if (w->shift == 4) {
2507 clear_bit(SITAR_HPHR_PA_OFF_ACK,
2508 &sitar->hph_pa_dac_state);
2509 clear_bit(SITAR_HPHR_DAC_OFF_ACK,
2510 &sitar->hph_pa_dac_state);
2511 if (sitar->hph_status & SND_JACK_OC_HPHR)
2512 schedule_work(&sitar->hphrocp_work);
2513 }
2514
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002515 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
2516 sitar_codec_switch_micbias(codec, 0);
2517 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302518
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302519 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302520 w->name);
2521 usleep_range(10000, 10000);
2522
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002523 if (sitar_is_line_pa_on(codec))
2524 sitar_enable_classg(codec, true);
2525 else
2526 sitar_enable_classg(codec, false);
2527
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302528 break;
2529 }
2530 return 0;
2531}
2532
2533static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
2534 struct mbhc_micbias_regs *micbias_regs)
2535{
2536 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302537 unsigned int cfilt;
2538
Patrick Laia5062da2012-05-11 17:55:09 -07002539 switch (sitar->mbhc_cfg.micbias) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302540 case SITAR_MICBIAS1:
2541 cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
2542 micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
2543 micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
2544 micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
2545 break;
2546 case SITAR_MICBIAS2:
2547 cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
2548 micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
2549 micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
2550 micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
2551 break;
2552 default:
2553 /* Should never reach here */
2554 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
2555 return;
2556 }
2557
2558 micbias_regs->cfilt_sel = cfilt;
2559
2560 switch (cfilt) {
2561 case SITAR_CFILT1_SEL:
2562 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
2563 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002564 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302565 break;
2566 case SITAR_CFILT2_SEL:
2567 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
2568 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002569 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302570 break;
2571 }
2572}
2573
2574static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
2575 struct snd_kcontrol *kcontrol, int event)
2576{
2577 struct snd_soc_codec *codec = w->codec;
2578
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302579 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302580 switch (event) {
2581 case SND_SOC_DAPM_POST_PMU:
2582 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2583 0x01);
2584 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
2585 usleep_range(200, 200);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302586 break;
2587 case SND_SOC_DAPM_PRE_PMD:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302588 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002589 /*
2590 * This delay is for the class G controller to settle down
2591 * after turn OFF. The delay is as per the hardware spec for
2592 * the codec
2593 */
2594 usleep_range(20, 20);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302595 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2596 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302597 break;
2598 }
2599 return 0;
2600}
2601
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002602static int sitar_ear_pa_event(struct snd_soc_dapm_widget *w,
2603 struct snd_kcontrol *kcontrol, int event)
2604{
2605 switch (event) {
2606 case SND_SOC_DAPM_POST_PMU:
2607 pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
2608 __func__);
2609 msleep(20);
2610 break;
2611 case SND_SOC_DAPM_POST_PMD:
2612 pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
2613 __func__);
2614 msleep(20);
2615 break;
2616 }
2617 return 0;
2618}
2619
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302620static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
2621 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
2622 4, 0, NULL, 0),
2623 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
2624 0, NULL, 0),
2625};
2626
2627static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
2628 /*RX stuff */
2629 SND_SOC_DAPM_OUTPUT("EAR"),
2630
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002631 SND_SOC_DAPM_PGA_E("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0,
2632 sitar_ear_pa_event, SND_SOC_DAPM_POST_PMU |
2633 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302634 SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
2635 ARRAY_SIZE(dac1_switch)),
2636 SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07002637
2638 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
2639 AIF1_PB, 0, sitar_codec_enable_slimrx,
2640 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2641
2642 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, SITAR_RX1, 0,
2643 &sitar_aif_pb_mux[SITAR_RX1]),
2644 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, SITAR_RX2, 0,
2645 &sitar_aif_pb_mux[SITAR_RX2]),
2646 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, SITAR_RX3, 0,
2647 &sitar_aif_pb_mux[SITAR_RX3]),
2648 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, SITAR_RX4, 0,
2649 &sitar_aif_pb_mux[SITAR_RX4]),
2650 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, SITAR_RX5, 0,
2651 &sitar_aif_pb_mux[SITAR_RX5]),
2652
2653 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2654 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
2655 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
2656 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
2657 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302658
2659 /* Headphone */
2660 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2661 SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
2662 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2663 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302664
2665 SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
2666 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2667 SND_SOC_DAPM_POST_PMD),
2668
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002669 SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
2670 sitar_hph_dac_event,
2671 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302672 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002673 sitar_hph_dac_event,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302674 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2675
2676 /* Speaker */
2677 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
2678 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
2679
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002680 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
2681 , sitar_lineout_dac_event,
2682 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2683 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
2684 , sitar_lineout_dac_event,
2685 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2686
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302687 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
2688 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2689 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2690 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
2691 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2692 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2693
2694 SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002695 0, sitar_codec_reset_interpolator,
2696 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302697 SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002698 0, sitar_codec_reset_interpolator,
2699 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302700 SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002701 0, sitar_codec_reset_interpolator,
2702 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302703
2704 SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
2705 &rx_dac1_mux),
2706 SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
2707 &rx_dac2_mux),
2708 SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
2709 &rx_dac3_mux),
2710 SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
2711 &rx_dac4_mux),
2712
Kuirong Wang80dedd62012-12-07 19:16:24 +05302713 SND_SOC_DAPM_MIXER_E("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL,
2714 0, sitar_codec_dem_input_selection,
2715 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
2716 SND_SOC_DAPM_MIXER_E("RX2 CHAIN", SND_SOC_NOPM, 1, 0, NULL,
2717 0, sitar_codec_dem_input_selection,
2718 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
2719 SND_SOC_DAPM_MIXER_E("RX3 CHAIN", SND_SOC_NOPM, 2, 0, NULL,
2720 0, sitar_codec_dem_input_selection,
2721 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302722
2723 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2724 &rx_mix1_inp1_mux),
2725 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2726 &rx_mix1_inp2_mux),
2727 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2728 &rx2_mix1_inp1_mux),
2729 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2730 &rx2_mix1_inp2_mux),
2731 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2732 &rx3_mix1_inp1_mux),
2733 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2734 &rx3_mix1_inp2_mux),
2735
2736 SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
2737 sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2738 SND_SOC_DAPM_PRE_PMD),
2739 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2740 sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2741 SND_SOC_DAPM_POST_PMD),
2742
2743 SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
2744 sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2745 /* TX */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002746
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302747 SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2748 0),
2749 SND_SOC_DAPM_INPUT("AMIC1"),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002750 SND_SOC_DAPM_INPUT("AMIC2"),
2751 SND_SOC_DAPM_INPUT("AMIC3"),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302752 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
2753 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2754 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2755 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
2756 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2757 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2758
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302759 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
2760 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2761 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2762 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
2763 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2764 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2765 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
2766 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2767 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2768
2769 SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
2770 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2771 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2772 SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
2773 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2774 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002775 SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
2776 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2777 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302778
2779 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 -07002780 &dec1_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002781 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2782 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2783
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002784 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 -07002785 &dec2_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002786 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2787 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2788
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002789 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 -07002790 &dec3_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002791 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2792 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2793
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002794 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 -07002795 &dec4_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002796 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2797 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302798
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002799 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2800 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2801
2802 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2803 sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2804 SND_SOC_DAPM_POST_PMD),
2805
2806 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2807
Kuirong Wang906ac472012-07-09 12:54:44 -07002808 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
2809 AIF1_CAP, 0, sitar_codec_enable_slimtx,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302810 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2811
Kuirong Wang906ac472012-07-09 12:54:44 -07002812 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
2813 sitar_aif_cap_mixer, ARRAY_SIZE(sitar_aif_cap_mixer)),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302814
Kuirong Wang906ac472012-07-09 12:54:44 -07002815 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, SITAR_TX1, 0,
2816 &sb_tx1_mux),
2817 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, SITAR_TX2, 0,
2818 &sb_tx2_mux),
2819 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2820 &sb_tx3_mux),
2821 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2822 &sb_tx4_mux),
2823 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2824 &sb_tx5_mux),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302825
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002826 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
2827 0, sitar_codec_enable_slimtx,
2828 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2829
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302830 /* Digital Mic Inputs */
2831 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2832 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2833 SND_SOC_DAPM_POST_PMD),
2834 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2835 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2836 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302837 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2838 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2839 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302840 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2841 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2842 SND_SOC_DAPM_POST_PMD),
2843
Kuirong Wang80dedd62012-12-07 19:16:24 +05302844 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, COMPANDER_1, 0,
2845 sitar_config_compander, SND_SOC_DAPM_PRE_PMU |
2846 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2847 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, COMPANDER_2, 0,
2848 sitar_config_compander, SND_SOC_DAPM_PRE_PMU |
2849 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2850
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302851 /* Sidetone */
2852 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2853 SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302854 SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
2855 SND_SOC_DAPM_PGA("IIR2", SITAR_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302856
2857};
2858
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302859static const struct snd_soc_dapm_route audio_i2s_map[] = {
2860 {"RX_I2S_CLK", NULL, "CP"},
2861 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2862 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2863 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2864 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2865 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2866
2867 {"SLIM TX1", NULL, "TX_I2S_CLK"},
2868 {"SLIM TX2", NULL, "TX_I2S_CLK"},
2869 {"SLIM TX3", NULL, "TX_I2S_CLK"},
2870 {"SLIM TX4", NULL, "TX_I2S_CLK"},
2871};
Kuirong Wang906ac472012-07-09 12:54:44 -07002872#define SLIM_MIXER(x) (\
2873 {x, "SLIM TX1", "SLIM TX1 MUX"}, \
2874 {x, "SLIM TX2", "SLIM TX2 MUX"}, \
2875 {x, "SLIM TX3", "SLIM TX3 MUX"}, \
2876 {x, "SLIM TX4", "SLIM TX4 MUX"})
2877
2878
2879#define SLIM_MUX(x, y) (\
2880 {"SLIM RX1 MUX", x, y}, \
2881 {"SLIM RX2 MUX", x, y}, \
2882 {"SLIM RX3 MUX", x, y}, \
2883 {"SLIM RX4 MUX", x, y})
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302884
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302885static const struct snd_soc_dapm_route audio_map[] = {
2886 /* Earpiece (RX MIX1) */
2887 {"EAR", NULL, "EAR PA"},
2888 {"EAR PA", "NULL", "DAC1"},
2889 {"DAC1", "Switch", "DAC1 MUX"},
2890 {"DAC1", NULL, "CP"},
2891 {"DAC1", NULL, "EAR DRIVER"},
2892
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002893 {"CP", NULL, "RX_BIAS"},
2894
2895 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2896 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302897
2898 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002899 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002900 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2901 {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302902
2903 {"LINEOUT1", NULL, "LINEOUT1 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002904 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002905 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2906 {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
2907
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002908 {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
2909 {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
2910 {"ANC", NULL, "ANC1 FB MUX"},
2911
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302912
2913 /* Headset (RX MIX1 and RX MIX2) */
2914 {"HEADPHONE", NULL, "HPHL"},
2915 {"HEADPHONE", NULL, "HPHR"},
2916
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002917
Patrick Lai9b250b72012-05-24 14:45:57 -07002918 {"HPHL DAC", NULL, "CP"},
2919 {"HPHR DAC", NULL, "CP"},
2920
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302921 {"HPHL", NULL, "HPHL DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002922 {"HPHL DAC", "NULL", "RX2 CHAIN"},
2923 {"RX2 CHAIN", NULL, "DAC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302924 {"HPHR", NULL, "HPHR DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002925 {"HPHR DAC", NULL, "RX3 CHAIN"},
2926 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302927
2928 {"DAC1 MUX", "RX1", "RX1 CHAIN"},
2929 {"DAC2 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002930
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302931 {"DAC3 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002932 {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302933 {"DAC3 MUX", "RX2", "RX2 MIX1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002934
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302935 {"DAC4 MUX", "ON", "RX2 MIX1"},
2936
2937 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2938
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302939 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2940 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2941 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2942 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2943 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2944 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2945
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002946 /* ANC */
2947 {"ANC", NULL, "ANC1 MUX"},
2948 {"ANC", NULL, "ANC2 MUX"},
2949 {"ANC1 MUX", "ADC1", "ADC1"},
2950 {"ANC1 MUX", "ADC2", "ADC2"},
2951 {"ANC1 MUX", "ADC3", "ADC3"},
2952 {"ANC2 MUX", "ADC1", "ADC1"},
2953 {"ANC2 MUX", "ADC2", "ADC2"},
2954 {"ANC2 MUX", "ADC3", "ADC3"},
2955
2956 {"ANC", NULL, "CDC_CONN"},
2957
2958 {"RX2 MIX1", NULL, "ANC"},
2959 {"RX3 MIX1", NULL, "ANC"},
2960
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302961 /* SLIMBUS Connections */
Kuirong Wang906ac472012-07-09 12:54:44 -07002962 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2963
2964 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2965 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2966 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2967 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2968 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2969 /* SLIM_MUX("AIF1_PB", "AIF1 PB"), */
2970 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2971 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2972 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2973 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2974
2975 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2976 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2977 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2978 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302979
Kuirong Wang80dedd62012-12-07 19:16:24 +05302980 {"RX1 MIX1", NULL, "COMP2_CLK"},
2981 {"RX2 MIX1", NULL, "COMP1_CLK"},
2982 {"RX3 MIX1", NULL, "COMP1_CLK"},
2983
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302984 /* Slimbus port 5 is non functional in Sitar 1.0 */
2985 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2986 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2987 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2988 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2989 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302990 {"RX1 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302991 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2992 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2993 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2994 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2995 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302996 {"RX1 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302997 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2998 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2999 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3000 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
3001 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303002 {"RX2 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303003 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3004 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
3005 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3006 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
3007 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303008 {"RX2 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303009 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3010 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
3011 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3012 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
3013 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303014 {"RX3 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303015 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3016 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
3017 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3018 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
3019 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303020 {"RX3 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303021
3022
3023 /* TX */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303024 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
3025 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
3026 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003027 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07003028 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
3029 {"SLIM TX5 MUX", "DEC2", "DEC2 MUX"},
3030 {"SLIM TX5 MUX", "DEC3", "DEC3 MUX"},
3031 {"SLIM TX5 MUX", "DEC4", "DEC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303032
3033 /* Decimator Inputs */
3034 {"DEC1 MUX", "DMIC1", "DMIC1"},
3035 {"DEC1 MUX", "DMIC4", "DMIC4"},
3036 {"DEC1 MUX", "ADC1", "ADC1"},
3037 {"DEC1 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003038 {"DEC1 MUX", "ADC3", "ADC3"},
3039 {"DEC1 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303040 {"DEC2 MUX", "DMIC2", "DMIC2"},
3041 {"DEC2 MUX", "DMIC3", "DMIC3"},
3042 {"DEC2 MUX", "ADC1", "ADC1"},
3043 {"DEC2 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003044 {"DEC2 MUX", "ADC3", "ADC3"},
3045 {"DEC2 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303046 {"DEC3 MUX", "DMIC3", "DMIC3"},
3047 {"DEC3 MUX", "ADC1", "ADC1"},
3048 {"DEC3 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003049 {"DEC3 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303050 {"DEC3 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07003051 {"DEC3 MUX", "DMIC4", "DMIC4"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003052 {"DEC3 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303053 {"DEC4 MUX", "DMIC4", "DMIC4"},
3054 {"DEC4 MUX", "ADC1", "ADC1"},
3055 {"DEC4 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003056 {"DEC4 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303057 {"DEC4 MUX", "DMIC3", "DMIC3"},
3058 {"DEC4 MUX", "DMIC2", "DMIC2"},
3059 {"DEC4 MUX", "DMIC1", "DMIC1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003060 {"DEC4 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303061
3062 /* ADC Connections */
3063 {"ADC1", NULL, "AMIC1"},
3064 {"ADC2", NULL, "AMIC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003065 {"ADC3", NULL, "AMIC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303066
3067 /* IIR */
3068 {"IIR1", NULL, "IIR1 INP1 MUX"},
3069 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303070 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3071 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3072 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3073 {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
3074 {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
3075 {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
3076 {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
3077 {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
3078
3079 {"IIR2", NULL, "IIR2 INP1 MUX"},
3080 {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
3081 {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
3082 {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
3083 {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
3084 {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
3085 {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
3086 {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
3087 {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
3088 {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
3089
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303090 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3091 {"MIC BIAS1 External", NULL, "LDO_H"},
3092 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3093 {"MIC BIAS2 External", NULL, "LDO_H"},
3094};
3095
3096static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
3097{
3098 return sitar_reg_readable[reg];
3099}
3100
3101static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3102{
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07003103 int i;
3104
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303105 /* Registers lower than 0x100 are top level registers which can be
3106 * written by the Sitar core driver.
3107 */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303108 if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3109 return 1;
3110
3111 /* IIR Coeff registers are not cacheable */
3112 if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
3113 (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
3114 return 1;
3115
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07003116 for (i = 0; i < NUM_DECIMATORS; i++) {
3117 if (reg == SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * i))
3118 return 1;
3119 }
3120
3121 for (i = 0; i < NUM_INTERPOLATORS; i++) {
3122 if (reg == SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * i))
3123 return 1;
3124 }
Kuirong Wang80dedd62012-12-07 19:16:24 +05303125
3126 if ((reg == SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS) ||
3127 (reg == SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS))
3128 return 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303129 return 0;
3130}
3131
3132#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3133static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
3134 unsigned int value)
3135{
3136 int ret;
3137
Kuirong Wang906ac472012-07-09 12:54:44 -07003138 if (reg == SND_SOC_NOPM)
3139 return 0;
3140
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303141 BUG_ON(reg > SITAR_MAX_REGISTER);
3142
3143 if (!sitar_volatile(codec, reg)) {
3144 ret = snd_soc_cache_write(codec, reg, value);
3145 if (ret != 0)
3146 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3147 reg, ret);
3148 }
3149
3150 return wcd9xxx_reg_write(codec->control_data, reg, value);
3151}
3152static unsigned int sitar_read(struct snd_soc_codec *codec,
3153 unsigned int reg)
3154{
3155 unsigned int val;
3156 int ret;
3157
Kuirong Wang906ac472012-07-09 12:54:44 -07003158 if (reg == SND_SOC_NOPM)
3159 return 0;
3160
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303161 BUG_ON(reg > SITAR_MAX_REGISTER);
3162
3163 if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
3164 reg < codec->driver->reg_cache_size) {
3165 ret = snd_soc_cache_read(codec, reg, &val);
3166 if (ret >= 0) {
3167 return val;
3168 } else
3169 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3170 reg, ret);
3171 }
3172
3173 val = wcd9xxx_reg_read(codec->control_data, reg);
3174 return val;
3175}
3176
3177static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
3178{
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003179 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303180
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003181 if (SITAR_IS_1P0(sitar_core->version))
3182 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
3183
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003184 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303185 usleep_range(1000, 1000);
3186 snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
3187 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3188 0x80);
3189 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
3190 0x04);
3191 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
3192 0x01);
3193 usleep_range(1000, 1000);
3194 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3195 0x00);
3196}
3197
3198static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
3199 enum sitar_bandgap_type choice)
3200{
3201 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003202 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303203
3204 /* TODO lock resources accessed by audio streams and threaded
3205 * interrupt handlers
3206 */
3207
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303208 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303209 sitar->bandgap_type);
3210
3211 if (sitar->bandgap_type == choice)
3212 return;
3213
3214 if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
3215 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
3216 sitar_codec_enable_audio_mode_bandgap(codec);
3217 } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
Bhalchandra Gajare7708ee32012-05-24 17:37:37 -07003218 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303219 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
3220 0x2);
3221 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3222 0x80);
3223 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
3224 0x4);
3225 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
3226 0x1);
3227 usleep_range(1000, 1000);
3228 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3229 0x00);
3230 } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
3231 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
3232 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
3233 usleep_range(100, 100);
3234 sitar_codec_enable_audio_mode_bandgap(codec);
3235 } else if (choice == SITAR_BANDGAP_OFF) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003236 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303237 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003238 if (SITAR_IS_1P0(sitar_core->version))
3239 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
Asish Bhattacharya63032b42012-08-16 20:57:01 +05303240 0xF3, 0x61);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003241 usleep_range(1000, 1000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303242 } else {
3243 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
3244 }
3245 sitar->bandgap_type = choice;
3246}
3247
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003248static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
3249 int enable)
3250{
3251 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3252
3253 if (enable) {
3254 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
3255 snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
3256 usleep_range(5, 5);
3257 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
3258 0x80);
3259 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
3260 0x80);
3261 usleep_range(10, 10);
3262 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
3263 usleep_range(20, 20);
3264 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
3265 } else {
3266 snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
3267 0);
3268 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
3269 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
3270 }
3271 sitar->config_mode_active = enable ? true : false;
3272
3273 return 0;
3274}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303275
3276static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
3277 int config_mode)
3278{
3279 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3280
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303281 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303282
3283 if (config_mode) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003284 sitar_codec_enable_config_mode(codec, 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303285 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
3286 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
3287 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
3288 usleep_range(1000, 1000);
3289 } else
3290 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
3291
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003292 if (!config_mode && sitar->mbhc_polling_active) {
3293 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
3294 sitar_codec_enable_config_mode(codec, 0);
3295
3296 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303297
3298 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
3299 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
3300 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303301 usleep_range(50, 50);
3302 sitar->clock_active = true;
3303 return 0;
3304}
3305static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
3306{
3307 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303308 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303309 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
3310 ndelay(160);
3311 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
3312 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
3313 sitar->clock_active = false;
3314}
3315
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003316static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
3317{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003318 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003319 return 0;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003320 else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003321 return 1;
3322 else {
3323 BUG_ON(1);
3324 return -EINVAL;
3325 }
3326}
3327
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303328static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3329{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003330 u8 *n_ready, *n_cic;
3331 struct sitar_mbhc_btn_detect_cfg *btn_det;
3332 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303333
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003334 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303335
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003336 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
3337 sitar->mbhc_data.v_ins_hu & 0xFF);
3338 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
3339 (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303340
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003341 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
3342 sitar->mbhc_data.v_b1_hu & 0xFF);
3343 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
3344 (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
3345
3346 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
3347 sitar->mbhc_data.v_b1_h & 0xFF);
3348 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
3349 (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
3350
3351 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
3352 sitar->mbhc_data.v_brh & 0xFF);
3353 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
3354 (sitar->mbhc_data.v_brh >> 8) & 0xFF);
3355
3356 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
3357 sitar->mbhc_data.v_brl & 0xFF);
3358 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
3359 (sitar->mbhc_data.v_brl >> 8) & 0xFF);
3360
3361 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
3362 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
3363 n_ready[sitar_codec_mclk_index(sitar)]);
3364 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
3365 sitar->mbhc_data.npoll);
3366 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
3367 sitar->mbhc_data.nbounce_wait);
3368 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3369 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
3370 n_cic[sitar_codec_mclk_index(sitar)]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303371}
3372
3373static int sitar_startup(struct snd_pcm_substream *substream,
3374 struct snd_soc_dai *dai)
3375{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08003376 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
3377 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
3378 (wcd9xxx->dev->parent != NULL))
3379 pm_runtime_get_sync(wcd9xxx->dev->parent);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303380 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303381 substream->name, substream->stream);
3382
3383 return 0;
3384}
3385
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003386static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
3387{
3388 if (sitar->dev != NULL &&
3389 sitar->dev->parent != NULL) {
3390 pm_runtime_mark_last_busy(sitar->dev->parent);
3391 pm_runtime_put(sitar->dev->parent);
3392 }
3393}
3394
3395static void sitar_shutdown(struct snd_pcm_substream *substream,
3396 struct snd_soc_dai *dai)
3397{
3398 struct wcd9xxx *sitar_core = dev_get_drvdata(dai->codec->dev->parent);
3399 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3400 u32 active = 0;
3401
3402 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3403 substream->name, substream->stream);
3404 if (sitar->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3405 return;
3406
3407 if (dai->id <= NUM_CODEC_DAIS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003408 if (sitar->dai[dai->id].ch_mask) {
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003409 active = 1;
Joonwoo Park9bbb4d12012-11-09 19:58:11 -08003410 pr_debug("%s(): Codec DAI: chmask[%d] = 0x%lx\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003411 __func__, dai->id,
3412 sitar->dai[dai->id].ch_mask);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003413 }
3414 }
3415
3416 if (sitar_core != NULL && active == 0)
3417 sitar_codec_pm_runtime_put(sitar_core);
3418}
3419
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003420int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303421{
3422 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3423
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303424 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303425
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003426 if (dapm)
3427 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303428 if (mclk_enable) {
3429 sitar->mclk_enabled = true;
3430
3431 if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
3432 sitar_codec_pause_hs_polling(codec);
3433 sitar_codec_enable_bandgap(codec,
3434 SITAR_BANDGAP_AUDIO_MODE);
3435 sitar_codec_enable_clock_block(codec, 0);
3436 sitar_codec_calibrate_hs_polling(codec);
3437 sitar_codec_start_hs_polling(codec);
3438 } else {
3439 sitar_codec_enable_bandgap(codec,
3440 SITAR_BANDGAP_AUDIO_MODE);
3441 sitar_codec_enable_clock_block(codec, 0);
3442 }
3443 } else {
3444
3445 if (!sitar->mclk_enabled) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003446 if (dapm)
3447 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303448 pr_err("Error, MCLK already diabled\n");
3449 return -EINVAL;
3450 }
3451 sitar->mclk_enabled = false;
3452
3453 if (sitar->mbhc_polling_active) {
3454 if (!sitar->mclk_enabled) {
3455 sitar_codec_pause_hs_polling(codec);
3456 sitar_codec_enable_bandgap(codec,
3457 SITAR_BANDGAP_MBHC_MODE);
3458 sitar_enable_rx_bias(codec, 1);
3459 sitar_codec_enable_clock_block(codec, 1);
3460 sitar_codec_calibrate_hs_polling(codec);
3461 sitar_codec_start_hs_polling(codec);
3462 }
3463 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
3464 0x05, 0x01);
3465 } else {
3466 sitar_codec_disable_clock_block(codec);
3467 sitar_codec_enable_bandgap(codec,
3468 SITAR_BANDGAP_OFF);
3469 }
3470 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003471 if (dapm)
3472 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303473 return 0;
3474}
3475
3476static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
3477 int clk_id, unsigned int freq, int dir)
3478{
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303479 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303480 return 0;
3481}
3482
3483static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3484{
3485 u8 val = 0;
3486 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3487
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303488 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303489 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3490 case SND_SOC_DAIFMT_CBS_CFS:
3491 /* CPU is master */
3492 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3493 if (dai->id == AIF1_CAP)
3494 snd_soc_update_bits(dai->codec,
3495 SITAR_A_CDC_CLK_TX_I2S_CTL,
3496 SITAR_I2S_MASTER_MODE_MASK, 0);
3497 else if (dai->id == AIF1_PB)
3498 snd_soc_update_bits(dai->codec,
3499 SITAR_A_CDC_CLK_RX_I2S_CTL,
3500 SITAR_I2S_MASTER_MODE_MASK, 0);
3501 }
3502 break;
3503 case SND_SOC_DAIFMT_CBM_CFM:
3504 /* CPU is slave */
3505 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3506 val = SITAR_I2S_MASTER_MODE_MASK;
3507 if (dai->id == AIF1_CAP)
3508 snd_soc_update_bits(dai->codec,
3509 SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
3510 else if (dai->id == AIF1_PB)
3511 snd_soc_update_bits(dai->codec,
3512 SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
3513 }
3514 break;
3515 default:
3516 return -EINVAL;
3517 }
3518 return 0;
3519}
3520static int sitar_set_channel_map(struct snd_soc_dai *dai,
3521 unsigned int tx_num, unsigned int *tx_slot,
3522 unsigned int rx_num, unsigned int *rx_slot)
3523
3524{
3525 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003526 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303527 if (!tx_slot && !rx_slot) {
3528 pr_err("%s: Invalid\n", __func__);
3529 return -EINVAL;
3530 }
3531 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3532
Kuirong Wang906ac472012-07-09 12:54:44 -07003533 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3534 wcd9xxx_init_slimslave(core, core->slim->laddr,
3535 tx_num, tx_slot, rx_num, rx_slot);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303536 return 0;
3537}
3538
3539static int sitar_get_channel_map(struct snd_soc_dai *dai,
3540 unsigned int *tx_num, unsigned int *tx_slot,
3541 unsigned int *rx_num, unsigned int *rx_slot)
3542
3543{
Kuirong Wang906ac472012-07-09 12:54:44 -07003544 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(dai->codec);
3545 u32 i = 0;
3546 struct wcd9xxx_ch *ch;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303547
Kuirong Wang906ac472012-07-09 12:54:44 -07003548 switch (dai->id) {
3549 case AIF1_PB:
3550 if (!rx_slot || !rx_num) {
3551 pr_err("%s: Invalid rx_slot 0x%x or rx_num 0x%x\n",
3552 __func__, (u32) rx_slot, (u32) rx_num);
3553 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303554 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003555 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3556 list) {
3557 rx_slot[i++] = ch->ch_num;
3558 }
3559 *rx_num = i;
3560 break;
3561 case AIF1_CAP:
3562 if (!tx_slot || !tx_num) {
3563 pr_err("%s: Invalid tx_slot 0x%x or tx_num 0x%x\n",
3564 __func__, (u32) tx_slot, (u32) tx_num);
3565 return -EINVAL;
3566 }
3567 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3568 list) {
3569 tx_slot[i++] = ch->ch_num;
3570 }
3571 *tx_num = i;
3572 break;
3573 default:
3574 pr_err("%s: Invalid dai %d", __func__, dai->id);
3575 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303576 }
3577 return 0;
3578}
3579
3580static int sitar_hw_params(struct snd_pcm_substream *substream,
3581 struct snd_pcm_hw_params *params,
3582 struct snd_soc_dai *dai)
3583{
3584 struct snd_soc_codec *codec = dai->codec;
3585 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3586 u8 path, shift;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303587 u32 compander_fs;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303588 u16 tx_fs_reg, rx_fs_reg;
3589 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
3590
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303591 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303592
3593 switch (params_rate(params)) {
3594 case 8000:
3595 tx_fs_rate = 0x00;
3596 rx_fs_rate = 0x00;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303597 compander_fs = COMPANDER_FS_8KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303598 break;
3599 case 16000:
3600 tx_fs_rate = 0x01;
3601 rx_fs_rate = 0x20;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303602 compander_fs = COMPANDER_FS_16KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303603 break;
3604 case 32000:
3605 tx_fs_rate = 0x02;
3606 rx_fs_rate = 0x40;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303607 compander_fs = COMPANDER_FS_32KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303608 break;
3609 case 48000:
3610 tx_fs_rate = 0x03;
3611 rx_fs_rate = 0x60;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303612 compander_fs = COMPANDER_FS_48KHZ;
3613 break;
3614 case 96000:
3615 tx_fs_rate = 0x04;
3616 rx_fs_rate = 0x80;
3617 compander_fs = COMPANDER_FS_96KHZ;
3618 break;
3619 case 192000:
3620 tx_fs_rate = 0x05;
3621 rx_fs_rate = 0xa0;
3622 compander_fs = COMPANDER_FS_192KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303623 break;
3624 default:
3625 pr_err("%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07003626 params_rate(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303627 return -EINVAL;
3628 }
3629
3630
3631 /**
3632 * If current dai is a tx dai, set sample rate to
3633 * all the txfe paths that are currently not active
3634 */
3635 if (dai->id == AIF1_CAP) {
3636
3637 tx_state = snd_soc_read(codec,
3638 SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3639
3640 for (path = 1, shift = 0;
3641 path <= NUM_DECIMATORS; path++, shift++) {
3642
3643 if (!(tx_state & (1 << shift))) {
3644 tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
3645 + (BITS_PER_REG*(path-1));
3646 snd_soc_update_bits(codec, tx_fs_reg,
3647 0x03, tx_fs_rate);
3648 }
3649 }
3650 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3651 switch (params_format(params)) {
3652 case SNDRV_PCM_FORMAT_S16_LE:
3653 snd_soc_update_bits(codec,
3654 SITAR_A_CDC_CLK_TX_I2S_CTL,
3655 0x20, 0x20);
3656 break;
3657 case SNDRV_PCM_FORMAT_S32_LE:
3658 snd_soc_update_bits(codec,
3659 SITAR_A_CDC_CLK_TX_I2S_CTL,
3660 0x20, 0x00);
3661 break;
3662 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003663 pr_err("%s: Unsupport format %d\n", __func__,
3664 params_format(params));
3665 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303666 }
3667 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
3668 0x03, tx_fs_rate);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303669 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003670 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303671 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303672 }
3673
3674 /**
3675 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3676 * with varying sample rates
3677 */
3678
3679 /**
3680 * If current dai is a rx dai, set sample rate to
3681 * all the rx paths that are currently not active
3682 */
3683 if (dai->id == AIF1_PB) {
3684
3685 rx_state = snd_soc_read(codec,
3686 SITAR_A_CDC_CLK_RX_B1_CTL);
3687
3688 for (path = 1, shift = 0;
3689 path <= NUM_INTERPOLATORS; path++, shift++) {
3690
3691 if (!(rx_state & (1 << shift))) {
3692 rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
3693 + (BITS_PER_REG*(path-1));
3694 snd_soc_update_bits(codec, rx_fs_reg,
3695 0xE0, rx_fs_rate);
Kuirong Wang80dedd62012-12-07 19:16:24 +05303696 if (comp_rx_path[shift] < COMPANDER_MAX)
3697 sitar->comp_fs[comp_rx_path[shift]]
3698 = compander_fs;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303699 }
3700 }
3701 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3702 switch (params_format(params)) {
3703 case SNDRV_PCM_FORMAT_S16_LE:
3704 snd_soc_update_bits(codec,
3705 SITAR_A_CDC_CLK_RX_I2S_CTL,
3706 0x20, 0x20);
3707 break;
3708 case SNDRV_PCM_FORMAT_S32_LE:
3709 snd_soc_update_bits(codec,
3710 SITAR_A_CDC_CLK_RX_I2S_CTL,
3711 0x20, 0x00);
3712 break;
3713 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003714 pr_err("%s: Unsupport format %d\n", __func__,
3715 params_format(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303716 break;
3717 }
3718 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
3719 0x03, (rx_fs_rate >> 0x05));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303720 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003721 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303722 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303723 }
3724
3725 return 0;
3726}
3727
3728static struct snd_soc_dai_ops sitar_dai_ops = {
3729 .startup = sitar_startup,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003730 .shutdown = sitar_shutdown,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303731 .hw_params = sitar_hw_params,
3732 .set_sysclk = sitar_set_dai_sysclk,
3733 .set_fmt = sitar_set_dai_fmt,
3734 .set_channel_map = sitar_set_channel_map,
3735 .get_channel_map = sitar_get_channel_map,
3736};
3737
3738static struct snd_soc_dai_driver sitar_dai[] = {
3739 {
3740 .name = "sitar_rx1",
3741 .id = AIF1_PB,
3742 .playback = {
3743 .stream_name = "AIF1 Playback",
3744 .rates = WCD9304_RATES,
3745 .formats = SITAR_FORMATS,
3746 .rate_max = 48000,
3747 .rate_min = 8000,
3748 .channels_min = 1,
3749 .channels_max = 2,
3750 },
3751 .ops = &sitar_dai_ops,
3752 },
3753 {
3754 .name = "sitar_tx1",
3755 .id = AIF1_CAP,
3756 .capture = {
3757 .stream_name = "AIF1 Capture",
3758 .rates = WCD9304_RATES,
3759 .formats = SITAR_FORMATS,
3760 .rate_max = 48000,
3761 .rate_min = 8000,
3762 .channels_min = 1,
3763 .channels_max = 2,
3764 },
3765 .ops = &sitar_dai_ops,
3766 },
3767};
3768
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303769static struct snd_soc_dai_driver sitar_i2s_dai[] = {
3770 {
3771 .name = "sitar_i2s_rx1",
3772 .id = AIF1_PB,
3773 .playback = {
3774 .stream_name = "AIF1 Playback",
3775 .rates = WCD9304_RATES,
3776 .formats = SITAR_FORMATS,
3777 .rate_max = 192000,
3778 .rate_min = 8000,
3779 .channels_min = 1,
3780 .channels_max = 4,
3781 },
3782 .ops = &sitar_dai_ops,
3783 },
3784 {
3785 .name = "sitar_i2s_tx1",
3786 .id = AIF1_CAP,
3787 .capture = {
3788 .stream_name = "AIF1 Capture",
3789 .rates = WCD9304_RATES,
3790 .formats = SITAR_FORMATS,
3791 .rate_max = 192000,
3792 .rate_min = 8000,
3793 .channels_min = 1,
3794 .channels_max = 4,
3795 },
3796 .ops = &sitar_dai_ops,
3797 },
3798};
3799
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003800static int sitar_codec_enable_chmask(struct sitar_priv *sitar,
3801 int event, int index)
3802{
Kuirong Wang906ac472012-07-09 12:54:44 -07003803 int ret = 0;
3804 struct wcd9xxx_ch *ch;
3805
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003806 switch (event) {
3807 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003808 list_for_each_entry(ch,
3809 &sitar->dai[index].wcd9xxx_ch_list, list) {
3810 ret = wcd9xxx_get_slave_port(ch->ch_num);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003811 if (ret < 0) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003812 pr_err("%s: Invalid slave port ID: %d\n",
3813 __func__, ret);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003814 ret = -EINVAL;
3815 break;
3816 }
3817 sitar->dai[index].ch_mask |= 1 << ret;
3818 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003819 break;
3820 case SND_SOC_DAPM_POST_PMD:
3821 ret = wait_event_timeout(sitar->dai[index].dai_wait,
3822 (sitar->dai[index].ch_mask == 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07003823 msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003824 if (!ret) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003825 pr_err("%s: Slim close tx/rx wait timeout\n",
3826 __func__);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003827 ret = -EINVAL;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003828 } else {
3829 ret = 0;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003830 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003831 break;
3832 }
3833 return ret;
3834}
3835
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303836static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3837 struct snd_kcontrol *kcontrol, int event)
3838{
Kuirong Wang906ac472012-07-09 12:54:44 -07003839 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303840 struct snd_soc_codec *codec = w->codec;
3841 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003842 int ret = 0;
3843 struct wcd9xxx_codec_dai_data *dai;
3844
3845 core = dev_get_drvdata(codec->dev->parent);
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003846
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303847 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003848 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003849 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3850 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303851 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003852 }
3853
Kuirong Wang906ac472012-07-09 12:54:44 -07003854 dai = &sitar_p->dai[w->shift];
3855
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303856 switch (event) {
3857 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003858 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3859 w->shift);
3860 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3861 dai->rate, dai->bit_width,
3862 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303863 break;
3864 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003865 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3866 dai->grph);
3867 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3868 w->shift);
3869 if (ret < 0) {
3870 ret = wcd9xxx_disconnect_port(core,
3871 &dai->wcd9xxx_ch_list,
3872 dai->grph);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003873 pr_info("%s: Disconnect RX port ret = %d\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003874 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303875 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003876 if (core != NULL)
3877 sitar_codec_pm_runtime_put(core);
3878 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303879 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003880 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303881}
3882
3883static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3884 struct snd_kcontrol *kcontrol, int event)
3885{
Kuirong Wang906ac472012-07-09 12:54:44 -07003886 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303887 struct snd_soc_codec *codec = w->codec;
3888 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003889 struct wcd9xxx_codec_dai_data *dai;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003890 int ret = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303891
Kuirong Wang906ac472012-07-09 12:54:44 -07003892 core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303893
3894 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003895 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003896 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3897 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303898 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003899 }
3900
Kuirong Wang906ac472012-07-09 12:54:44 -07003901 dai = &sitar_p->dai[w->shift];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303902 switch (event) {
3903 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003904 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3905 w->shift);
3906 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3907 dai->rate, dai->bit_width,
3908 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303909 break;
3910 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003911 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3912 dai->grph);
3913 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3914 w->shift);
3915 if (ret < 0) {
3916 ret = wcd9xxx_disconnect_port(core,
3917 &dai->wcd9xxx_ch_list,
3918 dai->grph);
3919 pr_info("%s: Disconnect RX port ret = %d\n",
3920 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303921 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003922 if (core != NULL)
3923 sitar_codec_pm_runtime_put(core);
3924 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303925 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003926 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303927}
3928
3929
3930static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
3931{
3932 u8 bias_msb, bias_lsb;
3933 short bias_value;
3934
3935 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
3936 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
3937 bias_value = (bias_msb << 8) | bias_lsb;
3938 return bias_value;
3939}
3940
3941static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
3942{
3943 u8 bias_msb, bias_lsb;
3944 short bias_value;
3945
3946 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
3947 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
3948 bias_value = (bias_msb << 8) | bias_lsb;
3949 return bias_value;
3950}
3951
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003952static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
3953 bool on)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303954{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003955 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
3956}
3957
3958static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3959 bool override_bypass, bool noreldetection)
3960{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303961 short bias_value;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003962 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3963
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003964 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003965 if (noreldetection)
3966 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303967
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003968 /* Turn on the override */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003969 if (!override_bypass)
3970 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303971 if (dce) {
3972 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3973 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
3974 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003975 usleep_range(sitar->mbhc_data.t_sta_dce,
3976 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303977 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003978 usleep_range(sitar->mbhc_data.t_dce,
3979 sitar->mbhc_data.t_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303980 bias_value = sitar_codec_read_dce_result(codec);
3981 } else {
3982 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3983 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
3984 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003985 usleep_range(sitar->mbhc_data.t_sta_dce,
3986 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303987 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003988 usleep_range(sitar->mbhc_data.t_sta,
3989 sitar->mbhc_data.t_sta);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303990 bias_value = sitar_codec_read_sta_result(codec);
3991 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3992 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
3993 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003994 /* Turn off the override after measuring mic voltage */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003995 if (!override_bypass)
3996 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3997
3998 if (noreldetection)
3999 sitar_turn_onoff_rel_detection(codec, true);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004000 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304001
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304002 return bias_value;
4003}
4004
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004005static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4006 bool norel)
4007{
4008 return __sitar_codec_sta_dce(codec, dce, false, norel);
4009}
4010
4011static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
4012{
4013 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4014 const struct sitar_mbhc_general_cfg *generic =
4015 SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
4016
4017 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
4018 sitar_codec_enable_config_mode(codec, 1);
4019
4020 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4021 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
4022
4023 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
4024
4025 usleep_range(generic->t_shutdown_plug_rem,
4026 generic->t_shutdown_plug_rem);
4027
4028 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
4029 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
4030 sitar_codec_enable_config_mode(codec, 0);
4031
4032 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
4033}
4034
4035static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
4036{
4037 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4038
4039 sitar_codec_shutdown_hs_removal_detect(codec);
4040
4041 if (!sitar->mclk_enabled) {
4042 sitar_codec_disable_clock_block(codec);
4043 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
4044 }
4045
4046 sitar->mbhc_polling_active = false;
4047 sitar->mbhc_state = MBHC_STATE_NONE;
4048}
4049
4050/* called only from interrupt which is under codec_resource_lock acquisition */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304051static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
4052{
4053 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304054 short bias_value;
4055 u8 cfilt_mode;
4056
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004057 if (!sitar->mbhc_cfg.calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304058 pr_err("Error, no sitar calibration\n");
4059 return -ENODEV;
4060 }
4061
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304062 if (!sitar->mclk_enabled) {
4063 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
4064 sitar_enable_rx_bias(codec, 1);
4065 sitar_codec_enable_clock_block(codec, 1);
4066 }
4067
4068 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
4069
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304070 /* Make sure CFILT is in fast mode, save current mode */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004071 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
4072 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
4073
4074 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304075
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304076 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4077 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
4078
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004079 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
4080 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
4081 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
4082
4083 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304084 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4085 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
4086
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004087 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304088 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4089
4090 sitar_codec_calibrate_hs_polling(codec);
4091
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004092 /* don't flip override */
4093 bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004094 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
4095 cfilt_mode);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304096 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
4097
4098 return bias_value;
4099}
4100
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004101static int sitar_cancel_btn_work(struct sitar_priv *sitar)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304102{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004103 int r = 0;
4104 struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304105
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004106 if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
4107 /* if scheduled mbhc_btn_dwork is canceled from here,
4108 * we have to unlock from here instead btn_work */
4109 wcd9xxx_unlock_sleep(core);
4110 r = 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304111 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004112 return r;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304113}
4114
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004115
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004116static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4117 s16 vin_mv)
4118{
4119 short diff, zero;
4120 struct sitar_priv *sitar;
4121 u32 mb_mv, in;
4122
4123 sitar = snd_soc_codec_get_drvdata(codec);
4124 mb_mv = sitar->mbhc_data.micb_mv;
4125
4126 if (mb_mv == 0) {
4127 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4128 return -EINVAL;
4129 }
4130
4131 if (dce) {
4132 diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
4133 zero = sitar->mbhc_data.dce_z;
4134 } else {
4135 diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
4136 zero = sitar->mbhc_data.sta_z;
4137 }
4138 in = (u32) diff * vin_mv;
4139
4140 return (u16) (in / mb_mv) + zero;
4141}
4142
4143static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4144 u16 bias_value)
4145{
4146 struct sitar_priv *sitar;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004147 s16 value, z, mb;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004148 s32 mv;
4149
4150 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004151 value = bias_value;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004152
4153 if (dce) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004154 z = (sitar->mbhc_data.dce_z);
4155 mb = (sitar->mbhc_data.dce_mb);
4156 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004157 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004158 z = (sitar->mbhc_data.sta_z);
4159 mb = (sitar->mbhc_data.sta_mb);
4160 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004161 }
4162
4163 return mv;
4164}
4165
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004166static void btn_lpress_fn(struct work_struct *work)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304167{
4168 struct delayed_work *delayed_work;
4169 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004170 short bias_value;
4171 int dce_mv, sta_mv;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004172 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304173
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004174 pr_debug("%s:\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304175
4176 delayed_work = to_delayed_work(work);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004177 sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004178 core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304179
4180 if (sitar) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004181 if (sitar->mbhc_cfg.button_jack) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004182 bias_value = sitar_codec_read_sta_result(sitar->codec);
4183 sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004184 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004185 bias_value = sitar_codec_read_dce_result(sitar->codec);
4186 dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004187 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004188 pr_debug("%s: Reporting long button press event"
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004189 " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
4190 sitar_snd_soc_jack_report(sitar,
4191 sitar->mbhc_cfg.button_jack,
4192 sitar->buttons_pressed,
4193 sitar->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304194 }
4195 } else {
4196 pr_err("%s: Bad sitar private data\n", __func__);
4197 }
4198
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004199 pr_debug("%s: leave\n", __func__);
4200 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304201}
4202
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004203
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004204void sitar_mbhc_cal(struct snd_soc_codec *codec)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304205{
4206 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004207 struct sitar_mbhc_btn_detect_cfg *btn_det;
4208 u8 cfilt_mode, bg_mode;
4209 u8 ncic, nmeas, navg;
4210 u32 mclk_rate;
4211 u32 dce_wait, sta_wait;
4212 u8 *n_cic;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004213 void *calibration;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004214
4215 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004216 calibration = sitar->mbhc_cfg.calibration;
4217
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004218 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004219 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004220
4221 /* First compute the DCE / STA wait times
4222 * depending on tunable parameters.
4223 * The value is computed in microseconds
4224 */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004225 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004226 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
4227 ncic = n_cic[sitar_codec_mclk_index(sitar)];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004228 nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4229 navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4230 mclk_rate = sitar->mbhc_cfg.mclk_rate;
4231 dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004232 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
4233
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004234 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4235 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004236
4237 /* LDOH and CFILT are already configured during pdata handling.
4238 * Only need to make sure CFILT and bandgap are in Fast mode.
4239 * Need to restore defaults once calculation is done.
4240 */
4241 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
4242 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4243 bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
4244 0x02);
4245
4246 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4247 * to perform ADC calibration
4248 */
4249 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004250 sitar->mbhc_cfg.micbias << 5);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004251 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4252 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004253 snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004254 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4255
4256 /* DCE measurement for 0 volts */
4257 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
4258 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
4259 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
4260 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
4261 usleep_range(100, 100);
4262 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
4263 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
4264 sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
4265
4266 /* DCE measurment for MB voltage */
4267 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
4268 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
4269 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
4270 usleep_range(100, 100);
4271 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
4272 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
4273 sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
4274
4275 /* Sta measuremnt for 0 volts */
4276 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
4277 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
4278 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
4279 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
4280 usleep_range(100, 100);
4281 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
4282 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
4283 sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
4284
4285 /* STA Measurement for MB Voltage */
4286 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
4287 usleep_range(100, 100);
4288 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
4289 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
4290 sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
4291
4292 /* Restore default settings. */
4293 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4294 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
4295 cfilt_mode);
4296 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4297
4298 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
4299 usleep_range(100, 100);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004300
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004301 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004302 sitar_turn_onoff_rel_detection(codec, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004303}
4304
4305void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
4306 const enum sitar_mbhc_btn_det_mem mem)
4307{
4308 void *ret = &btn_det->_v_btn_low;
4309
4310 switch (mem) {
4311 case SITAR_BTN_DET_GAIN:
4312 ret += sizeof(btn_det->_n_cic);
4313 case SITAR_BTN_DET_N_CIC:
4314 ret += sizeof(btn_det->_n_ready);
4315 case SITAR_BTN_DET_N_READY:
4316 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4317 case SITAR_BTN_DET_V_BTN_HIGH:
4318 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4319 case SITAR_BTN_DET_V_BTN_LOW:
4320 /* do nothing */
4321 break;
4322 default:
4323 ret = NULL;
4324 }
4325
4326 return ret;
4327}
4328
4329static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
4330{
4331 struct sitar_priv *sitar;
4332 s16 btn_mv = 0, btn_delta_mv;
4333 struct sitar_mbhc_btn_detect_cfg *btn_det;
4334 struct sitar_mbhc_plug_type_cfg *plug_type;
4335 u16 *btn_high;
4336 u8 *n_ready;
4337 int i;
4338
4339 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004340 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
4341 plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004342
4343 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004344 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004345 sitar->mbhc_data.npoll = 9;
4346 sitar->mbhc_data.nbounce_wait = 30;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004347 } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004348 sitar->mbhc_data.npoll = 7;
4349 sitar->mbhc_data.nbounce_wait = 23;
4350 }
4351
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004352 sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
4353 (sitar->mbhc_cfg.mclk_rate / 1000) *
4354 n_ready[sitar_codec_mclk_index(sitar)]) +
4355 10;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004356 sitar->mbhc_data.v_ins_hu =
4357 sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4358 sitar->mbhc_data.v_ins_h =
4359 sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4360
4361 btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
4362 for (i = 0; i < btn_det->num_btn; i++)
4363 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4364
4365 sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
4366 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4367
4368 sitar->mbhc_data.v_b1_hu =
4369 sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
4370
4371 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4372
4373 sitar->mbhc_data.v_b1_huc =
4374 sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4375
4376 sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004377 sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004378
4379 sitar->mbhc_data.v_no_mic =
4380 sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4381}
4382
4383void sitar_mbhc_init(struct snd_soc_codec *codec)
4384{
4385 struct sitar_priv *sitar;
4386 struct sitar_mbhc_general_cfg *generic;
4387 struct sitar_mbhc_btn_detect_cfg *btn_det;
4388 int n;
4389 u8 *n_cic, *gain;
4390
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004391 pr_err("%s(): ENTER\n", __func__);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004392 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004393 generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
4394 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004395
4396 for (n = 0; n < 8; n++) {
4397 if (n != 7) {
4398 snd_soc_update_bits(codec,
4399 SITAR_A_CDC_MBHC_FIR_B1_CFG,
4400 0x07, n);
4401 snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
4402 btn_det->c[n]);
4403 }
4404 }
4405 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
4406 btn_det->nc);
4407
4408 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
4409 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
4410 n_cic[sitar_codec_mclk_index(sitar)]);
4411
4412 gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
4413 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
4414 gain[sitar_codec_mclk_index(sitar)] << 3);
4415
4416 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4417 generic->mbhc_nsa << 4);
4418
4419 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4420 btn_det->n_meas);
4421
4422 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4423
4424 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4425
4426 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
4427 btn_det->mbhc_nsc << 3);
4428
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004429 snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
4430 sitar->mbhc_cfg.micbias);
4431
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004432 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004433
4434 snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
4435
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004436}
4437
4438static bool sitar_mbhc_fw_validate(const struct firmware *fw)
4439{
4440 u32 cfg_offset;
4441 struct sitar_mbhc_imped_detect_cfg *imped_cfg;
4442 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
4443
4444 if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
4445 return false;
4446
4447 /* previous check guarantees that there is enough fw data up
4448 * to num_btn
4449 */
4450 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
4451 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4452 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
4453 return false;
4454
4455 /* previous check guarantees that there is enough fw data up
4456 * to start of impedance detection configuration
4457 */
4458 imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
4459 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4460
4461 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
4462 return false;
4463
4464 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
4465 return false;
4466
4467 return true;
4468}
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004469
4470
4471static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
4472{
4473 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
4474}
4475
4476/* called under codec_resource_lock acquisition */
4477void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
4478{
4479 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4480 u8 wg_time;
4481
4482 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
4483 wg_time += 1;
4484
4485 /* If headphone PA is on, check if userspace receives
4486 * removal event to sync-up PA's state */
4487 if (sitar_is_hph_pa_on(codec)) {
4488 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4489 set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
4490 set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
4491 } else {
4492 pr_debug("%s PA is off\n", __func__);
4493 }
4494
4495 if (sitar_is_hph_dac_on(codec, 1))
4496 set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
4497 if (sitar_is_hph_dac_on(codec, 0))
4498 set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
4499
4500 snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
4501 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
4502 0xC0, 0x00);
4503 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
4504 0xC0, 0x00);
4505 usleep_range(wg_time * 1000, wg_time * 1000);
4506}
4507
4508static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
4509{
4510 bool pa_turned_on = false;
4511 struct snd_soc_codec *codec = sitar->codec;
4512 u8 wg_time;
4513
4514 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
4515 wg_time += 1;
4516
4517 if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
4518 &sitar->hph_pa_dac_state)) {
4519 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4520 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
4521 0xC0, 0xC0);
4522 }
4523 if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
4524 &sitar->hph_pa_dac_state)) {
4525 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4526 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
4527 0xC0, 0xC0);
4528 }
4529
4530 if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
4531 &sitar->hph_pa_dac_state)) {
4532 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4533 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
4534 1 << 4);
4535 pa_turned_on = true;
4536 }
4537 if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
4538 &sitar->hph_pa_dac_state)) {
4539 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4540 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
4541 1 << 5);
4542 pa_turned_on = true;
4543 }
4544
4545 if (pa_turned_on) {
4546 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4547 __func__);
4548 usleep_range(wg_time * 1000, wg_time * 1000);
4549 }
4550}
4551
4552static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4553 enum snd_jack_types jack_type)
4554{
4555 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4556
4557 if (!insertion) {
4558 /* Report removal */
4559 sitar->hph_status &= ~jack_type;
4560 if (sitar->mbhc_cfg.headset_jack) {
4561 /* cancel possibly scheduled btn work and
4562 * report release if we reported button press */
4563 if (sitar_cancel_btn_work(sitar)) {
4564 pr_debug("%s: button press is canceled\n",
4565 __func__);
4566 } else if (sitar->buttons_pressed) {
4567 pr_debug("%s: Reporting release for reported "
4568 "button press %d\n", __func__,
4569 jack_type);
4570 sitar_snd_soc_jack_report(sitar,
4571 sitar->mbhc_cfg.button_jack, 0,
4572 sitar->buttons_pressed);
4573 sitar->buttons_pressed &=
4574 ~SITAR_JACK_BUTTON_MASK;
4575 }
4576 pr_debug("%s: Reporting removal %d\n", __func__,
4577 jack_type);
4578 sitar_snd_soc_jack_report(sitar,
4579 sitar->mbhc_cfg.headset_jack,
4580 sitar->hph_status,
4581 SITAR_JACK_MASK);
4582 }
4583 sitar_set_and_turnoff_hph_padac(codec);
4584 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004585 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004586 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004587 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004588 sitar->current_plug = PLUG_TYPE_NONE;
4589 sitar->mbhc_polling_active = false;
4590 } else {
4591 /* Report insertion */
4592 sitar->hph_status |= jack_type;
4593
4594 if (jack_type == SND_JACK_HEADPHONE)
4595 sitar->current_plug = PLUG_TYPE_HEADPHONE;
4596 else if (jack_type == SND_JACK_HEADSET) {
4597 sitar->mbhc_polling_active = true;
4598 sitar->current_plug = PLUG_TYPE_HEADSET;
4599 }
4600 if (sitar->mbhc_cfg.headset_jack) {
4601 pr_debug("%s: Reporting insertion %d\n", __func__,
4602 jack_type);
4603 sitar_snd_soc_jack_report(sitar,
4604 sitar->mbhc_cfg.headset_jack,
4605 sitar->hph_status,
4606 SITAR_JACK_MASK);
4607 }
4608 sitar_clr_and_turnon_hph_padac(sitar);
4609 }
4610}
4611
4612
4613static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
4614{
4615 return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
4616 sitar->mbhc_cfg.gpio_level_insert);
4617}
4618
4619static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
4620 int mic_volt, int mic_volt_prev)
4621{
4622 int delta = abs(mic_volt - mic_volt_prev);
4623 if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
4624 pr_debug("%s: volt delta %dmv\n", __func__, delta);
4625 return true;
4626 }
4627 return false;
4628}
4629
4630static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
4631 s32 mic_volt)
4632{
4633 bool invalid = false;
4634
4635 if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
4636 && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
4637 invalid = true;
4638 }
4639
4640 return invalid;
4641}
4642
4643static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
4644 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
4645 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
4646{
4647 int i;
4648 bool r = false;
4649 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4650 struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
4651 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4652
4653 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
4654 if (mic_mv[i] < plug_type_ptr->v_no_mic)
4655 plug_type[i] = PLUG_TYPE_HEADPHONE;
4656 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
4657 plug_type[i] = PLUG_TYPE_HEADSET;
4658 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
4659 plug_type[i] = PLUG_TYPE_HIGH_HPH;
4660
4661 r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
4662 if (!r && i > 0) {
4663 if (plug_type[i-1] != plug_type[i])
4664 r = true;
4665 else
4666 r = sitar_is_invalid_insert_delta(codec,
4667 mic_mv[i],
4668 mic_mv[i - 1]);
4669 }
4670 }
4671
4672 return r;
4673}
4674
4675/* called under codec_resource_lock acquisition */
4676void sitar_find_plug_and_report(struct snd_soc_codec *codec,
4677 enum sitar_mbhc_plug_type plug_type)
4678{
4679 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4680
4681 if (plug_type == PLUG_TYPE_HEADPHONE
4682 && sitar->current_plug == PLUG_TYPE_NONE) {
4683 /* Nothing was reported previously
4684 * reporte a headphone
4685 */
4686 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4687 sitar_codec_cleanup_hs_polling(codec);
4688 } else if (plug_type == PLUG_TYPE_HEADSET) {
4689 /* If Headphone was reported previously, this will
4690 * only report the mic line
4691 */
4692 sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
4693 msleep(100);
4694 sitar_codec_start_hs_polling(codec);
4695 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
4696 if (sitar->current_plug == PLUG_TYPE_NONE)
4697 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4698 sitar_codec_cleanup_hs_polling(codec);
4699 pr_debug("setup mic trigger for further detection\n");
4700 sitar->lpi_enabled = true;
4701 /* TODO ::: sitar_codec_enable_hs_detect */
4702 pr_err("%s(): High impedence hph not supported\n", __func__);
4703 }
4704}
4705
4706/* should be called under interrupt context that hold suspend */
4707static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
4708{
4709 pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
4710 sitar->hs_detect_work_stop = false;
4711 wcd9xxx_lock_sleep(sitar->codec->control_data);
4712 schedule_work(&sitar->hs_correct_plug_work);
4713}
4714
4715/* called under codec_resource_lock acquisition */
4716static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
4717{
4718 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
4719 sitar->hs_detect_work_stop = true;
4720 wmb();
4721 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4722 if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
4723 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
4724 wcd9xxx_unlock_sleep(sitar->codec->control_data);
4725 }
4726 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4727}
4728
4729static void sitar_hs_correct_gpio_plug(struct work_struct *work)
4730{
4731 struct sitar_priv *sitar;
4732 struct snd_soc_codec *codec;
4733 int retry = 0, i;
4734 bool correction = false;
4735 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4736 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4737 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4738 unsigned long timeout;
4739
4740 sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
4741 codec = sitar->codec;
4742
4743 pr_debug("%s: enter\n", __func__);
4744 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4745
4746 /* Keep override on during entire plug type correction work.
4747 *
4748 * This is okay under the assumption that any GPIO irqs which use
4749 * MBHC block cancel and sync this work so override is off again
4750 * prior to GPIO interrupt handler's MBHC block usage.
4751 * Also while this correction work is running, we can guarantee
4752 * DAPM doesn't use any MBHC block as this work only runs with
4753 * headphone detection.
4754 */
4755 sitar_turn_onoff_override(codec, true);
4756
4757 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4758 while (!time_after(jiffies, timeout)) {
4759 ++retry;
4760 rmb();
4761 if (sitar->hs_detect_work_stop) {
4762 pr_debug("%s: stop requested\n", __func__);
4763 break;
4764 }
4765
4766 msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
4767 if (sitar_hs_gpio_level_remove(sitar)) {
4768 pr_debug("%s: GPIO value is low\n", __func__);
4769 break;
4770 }
4771
4772 /* can race with removal interrupt */
4773 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4774 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4775 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4776 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4777 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
4778 __func__, retry, mic_mv[i], mb_v[i]);
4779 }
4780 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4781
4782 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4783 pr_debug("Invalid plug in attempt # %d\n", retry);
4784 if (retry == NUM_ATTEMPTS_TO_REPORT &&
4785 sitar->current_plug == PLUG_TYPE_NONE) {
4786 sitar_codec_report_plug(codec, 1,
4787 SND_JACK_HEADPHONE);
4788 }
4789 } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
4790 plug_type) &&
4791 plug_type[0] == PLUG_TYPE_HEADPHONE) {
4792 pr_debug("Good headphone detected, continue polling mic\n");
4793 if (sitar->current_plug == PLUG_TYPE_NONE) {
4794 sitar_codec_report_plug(codec, 1,
4795 SND_JACK_HEADPHONE);
4796 }
4797 } else {
4798 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4799 /* Turn off override */
4800 sitar_turn_onoff_override(codec, false);
4801 sitar_find_plug_and_report(codec, plug_type[0]);
4802 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4803 pr_debug("Attempt %d found correct plug %d\n", retry,
4804 plug_type[0]);
4805 correction = true;
4806 break;
4807 }
4808 }
4809
4810 /* Turn off override */
4811 if (!correction)
4812 sitar_turn_onoff_override(codec, false);
4813
4814 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4815 pr_debug("%s: leave\n", __func__);
4816 /* unlock sleep */
4817 wcd9xxx_unlock_sleep(sitar->codec->control_data);
4818}
4819
4820/* called under codec_resource_lock acquisition */
4821static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
4822{
4823 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4824 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4825 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4826 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4827 int i;
4828
4829 pr_debug("%s: enter\n", __func__);
4830
4831 sitar_turn_onoff_override(codec, true);
4832 mb_v[0] = sitar_codec_setup_hs_polling(codec);
4833 mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
4834 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
4835
4836 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4837 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4838 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4839 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
4840 mic_mv[i]);
4841 }
4842 sitar_turn_onoff_override(codec, false);
4843
4844 if (sitar_hs_gpio_level_remove(sitar)) {
4845 pr_debug("%s: GPIO value is low when determining plug\n",
4846 __func__);
4847 return;
4848 }
4849
4850 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4851 sitar_schedule_hs_detect_plug(sitar);
4852 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
4853 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4854 sitar_schedule_hs_detect_plug(sitar);
4855 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
4856 pr_debug("%s: Valid plug found, determine plug type\n",
4857 __func__);
4858 sitar_find_plug_and_report(codec, plug_type[0]);
4859 }
4860
4861}
4862
4863/* called under codec_resource_lock acquisition */
4864static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
4865{
4866 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4867 const struct sitar_mbhc_plug_detect_cfg *plug_det =
4868 SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
4869
4870 if (plug_det->t_ins_complete > 20)
4871 msleep(plug_det->t_ins_complete);
4872 else
4873 usleep_range(plug_det->t_ins_complete * 1000,
4874 plug_det->t_ins_complete * 1000);
4875
4876 if (sitar_hs_gpio_level_remove(sitar))
4877 pr_debug("%s: GPIO value is low when determining "
4878 "plug\n", __func__);
4879 else
4880 sitar_codec_decide_gpio_plug(codec);
4881
4882 return;
4883}
4884
4885static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
4886{
4887 bool insert;
4888 struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
4889 bool is_removed = false;
4890
4891 pr_debug("%s: enter\n", __func__);
4892
4893 priv->in_gpio_handler = true;
4894 /* Wait here for debounce time */
4895 usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
4896 SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
4897
4898 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4899
4900 /* cancel pending button press */
4901 if (sitar_cancel_btn_work(priv))
4902 pr_debug("%s: button press is canceled\n", __func__);
4903
4904 insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4905 priv->mbhc_cfg.gpio_level_insert);
4906 if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
4907 priv->lpi_enabled = false;
4908 wmb();
4909
4910 /* cancel detect plug */
4911 sitar_cancel_hs_detect_plug(priv);
4912
4913 /* Disable Mic Bias pull down and HPH Switch to GND */
4914 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
4915 0x00);
4916 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
4917 sitar_codec_detect_plug_type(codec);
4918 } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
4919 priv->lpi_enabled = false;
4920 wmb();
4921
4922 /* cancel detect plug */
4923 sitar_cancel_hs_detect_plug(priv);
4924
4925 if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
4926 sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
4927 is_removed = true;
4928 } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
4929 sitar_codec_pause_hs_polling(codec);
4930 sitar_codec_cleanup_hs_polling(codec);
4931 sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
4932 is_removed = true;
4933 }
4934
4935 if (is_removed) {
4936 /* Enable Mic Bias pull down and HPH Switch to GND */
4937 snd_soc_update_bits(codec,
4938 priv->mbhc_bias_regs.ctl_reg, 0x01,
4939 0x01);
4940 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
4941 0x01);
4942 /* Make sure mic trigger is turned off */
4943 snd_soc_update_bits(codec,
4944 priv->mbhc_bias_regs.ctl_reg,
4945 0x01, 0x01);
4946 snd_soc_update_bits(codec,
4947 priv->mbhc_bias_regs.mbhc_reg,
4948 0x90, 0x00);
4949 /* Reset MBHC State Machine */
4950 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4951 0x08, 0x08);
4952 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4953 0x08, 0x00);
4954 /* Turn off override */
4955 sitar_turn_onoff_override(codec, false);
4956 }
4957 }
4958
4959 priv->in_gpio_handler = false;
4960 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4961 pr_debug("%s: leave\n", __func__);
4962}
4963
4964static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
4965{
4966 int r = IRQ_HANDLED;
4967 struct snd_soc_codec *codec = data;
4968
4969 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
4970 pr_warn("%s(): Failed to hold suspend\n", __func__);
4971 r = IRQ_NONE;
4972 } else {
4973 sitar_hs_gpio_handler(codec);
4974 wcd9xxx_unlock_sleep(codec->control_data);
4975 }
4976 return r;
4977}
4978
4979static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
4980{
4981 int rc = 0;
4982 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4983
4984 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4985 sitar_mbhc_init(codec);
4986 sitar_mbhc_cal(codec);
4987 sitar_mbhc_calc_thres(codec);
4988 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4989 sitar_codec_calibrate_hs_polling(codec);
4990
4991 /* Enable Mic Bias pull down and HPH Switch to GND */
4992 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
4993 0x01, 0x01);
4994 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
4995 0x01, 0x01);
4996
4997 rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
4998 NULL,
4999 sitar_mechanical_plug_detect_irq,
5000 (IRQF_TRIGGER_RISING |
5001 IRQF_TRIGGER_FALLING),
5002 "sitar-hs-gpio", codec);
5003
5004 if (!IS_ERR_VALUE(rc)) {
5005 rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
5006 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
5007 0x10, 0x10);
5008 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005009 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005010 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005011 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005012 /* Bootup time detection */
5013 sitar_hs_gpio_handler(codec);
5014 }
5015
5016 return rc;
5017}
5018
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005019static void mbhc_fw_read(struct work_struct *work)
5020{
5021 struct delayed_work *dwork;
5022 struct sitar_priv *sitar;
5023 struct snd_soc_codec *codec;
5024 const struct firmware *fw;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005025 int ret = -1, retry = 0;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005026
5027 dwork = to_delayed_work(work);
5028 sitar = container_of(dwork, struct sitar_priv,
5029 mbhc_firmware_dwork);
5030 codec = sitar->codec;
5031
5032 while (retry < MBHC_FW_READ_ATTEMPTS) {
5033 retry++;
5034 pr_info("%s:Attempt %d to request MBHC firmware\n",
5035 __func__, retry);
5036 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
5037 codec->dev);
5038
5039 if (ret != 0) {
5040 usleep_range(MBHC_FW_READ_TIMEOUT,
5041 MBHC_FW_READ_TIMEOUT);
5042 } else {
5043 pr_info("%s: MBHC Firmware read succesful\n", __func__);
5044 break;
5045 }
5046 }
5047
5048 if (ret != 0) {
5049 pr_err("%s: Cannot load MBHC firmware use default cal\n",
5050 __func__);
5051 } else if (sitar_mbhc_fw_validate(fw) == false) {
5052 pr_err("%s: Invalid MBHC cal data size use default cal\n",
5053 __func__);
5054 release_firmware(fw);
5055 } else {
5056 sitar->calibration = (void *)fw->data;
5057 sitar->mbhc_fw = fw;
5058 }
5059
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005060 sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005061}
5062
5063int sitar_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005064 const struct sitar_mbhc_config *cfg)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005065{
5066 struct sitar_priv *sitar;
5067 int rc = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305068
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005069 if (!codec || !cfg->calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305070 pr_err("Error: no codec or calibration\n");
5071 return -EINVAL;
5072 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005073
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005074 if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
5075 if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005076 pr_err("Error: clock rate %dHz is not yet supported\n",
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005077 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005078 else
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005079 pr_err("Error: unsupported clock rate %d\n",
5080 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005081 return -EINVAL;
5082 }
5083
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305084 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005085 sitar->mbhc_cfg = *cfg;
5086 sitar->in_gpio_handler = false;
5087 sitar->current_plug = PLUG_TYPE_NONE;
5088 sitar->lpi_enabled = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305089 sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
5090
5091 /* Put CFILT in fast mode by default */
5092 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005093 0x40, SITAR_CFILT_FAST_MODE);
5094
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005095 INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005096 INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305097 INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
5098 INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005099 INIT_WORK(&sitar->hs_correct_plug_work,
5100 sitar_hs_correct_gpio_plug);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005101
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005102 if (!sitar->mbhc_cfg.read_fw_bin) {
5103 rc = sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005104 } else {
5105 schedule_delayed_work(&sitar->mbhc_firmware_dwork,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005106 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305107 }
5108
5109 return rc;
5110}
5111EXPORT_SYMBOL_GPL(sitar_hs_detect);
5112
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005113static int sitar_determine_button(const struct sitar_priv *priv,
5114 const s32 bias_mv)
5115{
5116 s16 *v_btn_low, *v_btn_high;
5117 struct sitar_mbhc_btn_detect_cfg *btn_det;
5118 int i, btn = -1;
5119
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005120 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005121 v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
5122 v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
5123 SITAR_BTN_DET_V_BTN_HIGH);
5124 for (i = 0; i < btn_det->num_btn; i++) {
5125 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
5126 btn = i;
5127 break;
5128 }
5129 }
5130
5131 if (btn == -1)
5132 pr_debug("%s: couldn't find button number for mic mv %d\n",
5133 __func__, bias_mv);
5134
5135 return btn;
5136}
5137
5138static int sitar_get_button_mask(const int btn)
5139{
5140 int mask = 0;
5141 switch (btn) {
5142 case 0:
5143 mask = SND_JACK_BTN_0;
5144 break;
5145 case 1:
5146 mask = SND_JACK_BTN_1;
5147 break;
5148 case 2:
5149 mask = SND_JACK_BTN_2;
5150 break;
5151 case 3:
5152 mask = SND_JACK_BTN_3;
5153 break;
5154 case 4:
5155 mask = SND_JACK_BTN_4;
5156 break;
5157 case 5:
5158 mask = SND_JACK_BTN_5;
5159 break;
5160 case 6:
5161 mask = SND_JACK_BTN_6;
5162 break;
5163 case 7:
5164 mask = SND_JACK_BTN_7;
5165 break;
5166 }
5167 return mask;
5168}
5169
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005170
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305171static irqreturn_t sitar_dce_handler(int irq, void *data)
5172{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005173 int i, mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005174 short dce, sta, bias_value_dce;
5175 s32 mv, stamv, bias_mv_dce;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005176 int btn = -1, meas = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305177 struct sitar_priv *priv = data;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005178 const struct sitar_mbhc_btn_detect_cfg *d =
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005179 SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005180 short btnmeas[d->n_btn_meas + 1];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305181 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005182 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005183 int n_btn_meas = d->n_btn_meas;
5184 u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305185
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005186 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305187
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005188 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5189 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5190 pr_debug("%s: mbhc is being recovered, skip button press\n",
5191 __func__);
5192 goto done;
5193 }
5194
5195 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5196
5197 if (!priv->mbhc_polling_active) {
5198 pr_warn("%s: mbhc polling is not active, skip button press\n",
5199 __func__);
5200 goto done;
5201 }
5202
5203 dce = sitar_codec_read_dce_result(codec);
5204 mv = sitar_codec_sta_dce_v(codec, 1, dce);
5205
5206 /* If GPIO interrupt already kicked in, ignore button press */
5207 if (priv->in_gpio_handler) {
5208 pr_debug("%s: GPIO State Changed, ignore button press\n",
5209 __func__);
5210 btn = -1;
5211 goto done;
5212 }
5213
5214 if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
5215 if (priv->mbhc_last_resume &&
5216 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5217 pr_debug("%s: Button is already released shortly after "
5218 "resume\n", __func__);
5219 n_btn_meas = 0;
5220 } else {
5221 pr_debug("%s: Button is already released without "
5222 "resume", __func__);
5223 sta = sitar_codec_read_sta_result(codec);
5224 stamv = sitar_codec_sta_dce_v(codec, 0, sta);
5225 btn = sitar_determine_button(priv, mv);
5226 if (btn != sitar_determine_button(priv, stamv))
5227 btn = -1;
5228 goto done;
5229 }
5230 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305231
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005232 /* determine pressed button */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005233 btnmeas[meas++] = sitar_determine_button(priv, mv);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005234 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005235 meas - 1, dce, mv, btnmeas[meas - 1]);
5236 if (n_btn_meas == 0)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005237 btn = btnmeas[0];
5238 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005239 bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005240 bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
5241 btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
5242 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
5243 __func__, meas, bias_value_dce, bias_mv_dce,
5244 btnmeas[meas]);
5245 /* if large enough measurements are collected,
5246 * start to check if last all n_btn_con measurements were
5247 * in same button low/high range */
5248 if (meas + 1 >= d->n_btn_con) {
5249 for (i = 0; i < d->n_btn_con; i++)
5250 if ((btnmeas[meas] < 0) ||
5251 (btnmeas[meas] != btnmeas[meas - i]))
5252 break;
5253 if (i == d->n_btn_con) {
5254 /* button pressed */
5255 btn = btnmeas[meas];
5256 break;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005257 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5258 /* if left measurements are less than n_btn_con,
5259 * it's impossible to find button number */
5260 break;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005261 }
5262 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005263 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305264
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005265 if (btn >= 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005266 if (priv->in_gpio_handler) {
5267 pr_debug("%s: GPIO already triggered, ignore button "
5268 "press\n", __func__);
5269 goto done;
5270 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005271 mask = sitar_get_button_mask(btn);
5272 priv->buttons_pressed |= mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005273 wcd9xxx_lock_sleep(core);
5274 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5275 msecs_to_jiffies(400)) == 0) {
5276 WARN(1, "Button pressed twice without release"
5277 "event\n");
5278 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005279 }
5280 } else {
5281 pr_debug("%s: bogus button press, too short press?\n",
5282 __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305283 }
5284
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005285 done:
5286 pr_debug("%s: leave\n", __func__);
5287 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305288 return IRQ_HANDLED;
5289}
5290
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005291static int sitar_is_fake_press(struct sitar_priv *priv)
5292{
5293 int i;
5294 int r = 0;
5295 struct snd_soc_codec *codec = priv->codec;
5296 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
5297 short mb_v;
5298
5299 for (i = 0; i < dces; i++) {
5300 usleep_range(10000, 10000);
5301 if (i == 0) {
5302 mb_v = sitar_codec_sta_dce(codec, 0, true);
5303 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5304 sitar_codec_sta_dce_v(codec, 0, mb_v));
5305 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
5306 mb_v > (short)priv->mbhc_data.v_ins_hu) {
5307 r = 1;
5308 break;
5309 }
5310 } else {
5311 mb_v = sitar_codec_sta_dce(codec, 1, true);
5312 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5313 sitar_codec_sta_dce_v(codec, 1, mb_v));
5314 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
5315 mb_v > (short)priv->mbhc_data.v_ins_h) {
5316 r = 1;
5317 break;
5318 }
5319 }
5320 }
5321
5322 return r;
5323}
5324
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305325static irqreturn_t sitar_release_handler(int irq, void *data)
5326{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005327 int ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305328 struct sitar_priv *priv = data;
5329 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305330
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005331 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305332
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005333 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5334 priv->mbhc_state = MBHC_STATE_RELEASE;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305335
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005336 if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
5337 ret = sitar_cancel_btn_work(priv);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305338 if (ret == 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005339 pr_debug("%s: Reporting long button release event\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005340 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005341 if (priv->mbhc_cfg.button_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305342 sitar_snd_soc_jack_report(priv,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005343 priv->mbhc_cfg.button_jack, 0,
5344 priv->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305345 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005346 if (sitar_is_fake_press(priv)) {
5347 pr_debug("%s: Fake button press interrupt\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005348 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005349 } else if (priv->mbhc_cfg.button_jack) {
5350 if (priv->in_gpio_handler) {
5351 pr_debug("%s: GPIO kicked in, ignore\n",
5352 __func__);
5353 } else {
5354 pr_debug("%s: Reporting short button 0 "
5355 "press and release\n",
5356 __func__);
5357 sitar_snd_soc_jack_report(priv,
5358 priv->mbhc_cfg.button_jack,
5359 priv->buttons_pressed,
5360 priv->buttons_pressed);
5361 sitar_snd_soc_jack_report(priv,
5362 priv->mbhc_cfg.button_jack, 0,
5363 priv->buttons_pressed);
5364 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305365 }
5366 }
5367
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005368 priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
5369 }
5370
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005371 sitar_codec_calibrate_hs_polling(codec);
5372
5373 if (priv->mbhc_cfg.gpio)
5374 msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
5375
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305376 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005377
5378 pr_debug("%s: leave\n", __func__);
5379 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
5380
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305381 return IRQ_HANDLED;
5382}
5383
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305384static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
5385{
5386 struct sitar_priv *sitar = data;
5387 struct snd_soc_codec *codec;
5388
5389 pr_info("%s: received HPHL OCP irq\n", __func__);
5390
5391 if (sitar) {
5392 codec = sitar->codec;
Patrick Lai71579f02013-03-16 13:05:00 -07005393 if ((sitar->hphlocp_cnt < SITAR_OCP_ATTEMPT) &&
5394 (!sitar->hphrocp_cnt)) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305395 pr_info("%s: retry\n", __func__);
Patrick Lai71579f02013-03-16 13:05:00 -07005396 sitar->hphlocp_cnt++;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305397 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005398 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305399 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005400 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305401 } else {
5402 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005403 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305404 sitar->hph_status |= SND_JACK_OC_HPHL;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005405 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305406 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005407 sitar->mbhc_cfg.headset_jack,
5408 sitar->hph_status,
5409 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305410 }
5411 } else {
5412 pr_err("%s: Bad sitar private data\n", __func__);
5413 }
5414
5415 return IRQ_HANDLED;
5416}
5417
5418static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
5419{
5420 struct sitar_priv *sitar = data;
5421 struct snd_soc_codec *codec;
5422
5423 pr_info("%s: received HPHR OCP irq\n", __func__);
5424
5425 if (sitar) {
5426 codec = sitar->codec;
Patrick Lai71579f02013-03-16 13:05:00 -07005427 if ((sitar->hphrocp_cnt < SITAR_OCP_ATTEMPT) &&
5428 (!sitar->hphlocp_cnt)) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305429 pr_info("%s: retry\n", __func__);
Patrick Lai71579f02013-03-16 13:05:00 -07005430 sitar->hphrocp_cnt++;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305431 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
5432 0x00);
5433 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
5434 0x10);
5435 } else {
5436 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005437 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305438 sitar->hph_status |= SND_JACK_OC_HPHR;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005439 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305440 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005441 sitar->mbhc_cfg.headset_jack,
5442 sitar->hph_status,
5443 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305444 }
5445 } else {
5446 pr_err("%s: Bad sitar private data\n", __func__);
5447 }
5448
5449 return IRQ_HANDLED;
5450}
5451
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305452static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
5453{
5454 struct sitar_priv *priv = data;
5455 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305456
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005457 pr_debug("%s: enter\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005458 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005459 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305460
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305461 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5462
5463 /* Turn off both HPH and MIC line schmitt triggers */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005464 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305465 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005466 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305467
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005468 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305469
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005470 rmb();
5471 if (priv->lpi_enabled)
5472 msleep(100);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305473
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005474 rmb();
5475 if (!priv->lpi_enabled) {
5476 pr_debug("%s: lpi is disabled\n", __func__);
5477 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5478 priv->mbhc_cfg.gpio_level_insert) {
5479 pr_debug("%s: Valid insertion, "
5480 "detect plug type\n", __func__);
5481 sitar_codec_decide_gpio_plug(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305482 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005483 pr_debug("%s: Invalid insertion, "
5484 "stop plug detection\n", __func__);
5485 }
5486 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
5487 return IRQ_HANDLED;
5488}
5489
5490static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5491{
5492 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5493 struct sitar_mbhc_plug_type_cfg *plug_type =
5494 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
5495
5496 return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
5497 && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
5498 && (mic_mv > plug_type->v_no_mic)
5499 && (mic_mv < plug_type->v_hs_max)) ? true : false;
5500}
5501
5502/* called under codec_resource_lock acquisition
5503 * returns true if mic voltage range is back to normal insertion
5504 * returns false either if timedout or removed */
5505static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
5506{
5507 int i;
5508 bool timedout, settled = false;
5509 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5510 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5511 unsigned long retry = 0, timeout;
5512 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5513
5514 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
5515 while (!(timedout = time_after(jiffies, timeout))) {
5516 retry++;
5517 if (sitar_hs_gpio_level_remove(sitar)) {
5518 pr_debug("%s: GPIO indicates removal\n", __func__);
5519 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305520 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005521
5522 if (retry > 1)
5523 msleep(250);
5524 else
5525 msleep(50);
5526
5527 if (sitar_hs_gpio_level_remove(sitar)) {
5528 pr_debug("%s: GPIO indicates removal\n", __func__);
5529 break;
5530 }
5531
5532 sitar_turn_onoff_override(codec, true);
5533 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5534 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
5535 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
5536 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
5537 __func__, retry, mic_mv[i], mb_v[i]);
5538 }
5539 sitar_turn_onoff_override(codec, false);
5540
5541 if (sitar_hs_gpio_level_remove(sitar)) {
5542 pr_debug("%s: GPIO indicates removal\n", __func__);
5543 break;
5544 }
5545
5546 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5547 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5548 break;
5549
5550 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5551 pr_debug("%s: MIC voltage settled\n", __func__);
5552 settled = true;
5553 msleep(200);
5554 break;
5555 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305556 }
5557
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005558 if (timedout)
5559 pr_debug("%s: Microphone did not settle in %d seconds\n",
5560 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
5561 return settled;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305562}
5563
5564static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
5565{
5566 struct sitar_priv *priv = data;
5567 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305568
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005569 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305570
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005571 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5572 if (sitar_hs_remove_settle(codec))
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305573 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005574 pr_debug("%s: remove settle done\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305575
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005576 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305577 return IRQ_HANDLED;
5578}
5579
5580
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305581
5582static irqreturn_t sitar_slimbus_irq(int irq, void *data)
5583{
5584 struct sitar_priv *priv = data;
5585 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005586 unsigned long slimbus_value;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005587 int i, j, k, port_id, ch_mask_temp;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305588 u8 val;
5589
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305590
5591 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
5592 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
5593 SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
5594 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005595 port_id = i*8 + j;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305596 val = wcd9xxx_interface_reg_read(codec->control_data,
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005597 SITAR_SLIM_PGD_PORT_INT_SOURCE0 + port_id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305598 if (val & 0x1)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005599 pr_err_ratelimited("overflow error on port %x, value %x\n",
5600 port_id, val);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305601 if (val & 0x2)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005602 pr_err_ratelimited("underflow error on port %x,value %x\n",
5603 port_id, val);
5604 if (val & 0x4) {
5605 pr_debug("%s: port %x disconnect value %x\n",
5606 __func__, port_id, val);
5607 for (k = 0; k < ARRAY_SIZE(sitar_dai); k++) {
5608 ch_mask_temp = 1 << port_id;
5609 if (ch_mask_temp &
5610 priv->dai[k].ch_mask) {
5611 priv->dai[k].ch_mask &=
5612 ~ch_mask_temp;
5613 if (!priv->dai[k].ch_mask)
5614 wake_up(
5615 &priv->dai[k].dai_wait);
5616 }
5617 }
5618 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305619 }
5620 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005621 SITAR_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
5622 val = 0x0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305623 }
5624
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305625 return IRQ_HANDLED;
5626}
5627
5628
5629static int sitar_handle_pdata(struct sitar_priv *sitar)
5630{
5631 struct snd_soc_codec *codec = sitar->codec;
5632 struct wcd9xxx_pdata *pdata = sitar->pdata;
5633 int k1, k2, rc = 0;
5634 u8 leg_mode = pdata->amic_settings.legacy_mode;
5635 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
5636 u8 txfe_buff = pdata->amic_settings.txfe_buff;
5637 u8 flag = pdata->amic_settings.use_pdata;
5638 u8 i = 0, j = 0;
5639 u8 val_txfe = 0, value = 0;
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305640 int amic_reg_count = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305641
5642 if (!pdata) {
5643 rc = -ENODEV;
5644 goto done;
5645 }
5646
5647 /* Make sure settings are correct */
5648 if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
5649 (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
5650 (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
5651 rc = -EINVAL;
5652 goto done;
5653 }
5654
5655 /* figure out k value */
5656 k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
5657 pdata->micbias.cfilt1_mv);
5658 k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
5659 pdata->micbias.cfilt2_mv);
5660
5661 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
5662 rc = -EINVAL;
5663 goto done;
5664 }
5665
5666 /* Set voltage level and always use LDO */
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07005667 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
5668 (pdata->micbias.ldoh_v << 2));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305669
5670 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
5671 (k1 << 2));
5672 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
5673 (k2 << 2));
5674
5675 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
5676 (pdata->micbias.bias1_cfilt_sel << 5));
5677 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
5678 (pdata->micbias.bias2_cfilt_sel << 5));
5679
Bhalchandra Gajare15dbeaa2012-06-26 12:53:07 -07005680 /* Set micbias capless mode */
5681 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x10,
5682 (pdata->micbias.bias1_cap_mode << 4));
5683 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
5684 (pdata->micbias.bias2_cap_mode << 4));
5685
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305686 amic_reg_count = (NUM_AMIC % 2) ? NUM_AMIC + 1 : NUM_AMIC;
5687 for (i = 0; i < amic_reg_count; j++, i += 2) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305688 if (flag & (0x01 << i)) {
5689 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
5690 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
5691 val_txfe = val_txfe |
5692 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
5693 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5694 0x10, value);
5695 snd_soc_update_bits(codec,
5696 SITAR_A_TX_1_2_TEST_EN + j * 10,
5697 0x30, val_txfe);
5698 }
5699 if (flag & (0x01 << (i + 1))) {
5700 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
5701 val_txfe = (txfe_bypass &
5702 (0x01 << (i + 1))) ? 0x02 : 0x00;
5703 val_txfe |= (txfe_buff &
5704 (0x01 << (i + 1))) ? 0x01 : 0x00;
5705 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5706 0x01, value);
5707 snd_soc_update_bits(codec,
5708 SITAR_A_TX_1_2_TEST_EN + j * 10,
5709 0x03, val_txfe);
5710 }
5711 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005712 if (flag & 0x40) {
5713 value = (leg_mode & 0x40) ? 0x10 : 0x00;
5714 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
5715 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
5716 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
5717 0x13, value);
5718 }
5719
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305720
5721 if (pdata->ocp.use_pdata) {
5722 /* not defined in CODEC specification */
5723 if (pdata->ocp.hph_ocp_limit == 1 ||
5724 pdata->ocp.hph_ocp_limit == 5) {
5725 rc = -EINVAL;
5726 goto done;
5727 }
5728 snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
5729 0x0F, pdata->ocp.num_attempts);
5730 snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
5731 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
5732 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
5733 0xE0, (pdata->ocp.hph_ocp_limit << 5));
5734 }
5735done:
5736 return rc;
5737}
5738
5739static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
5740
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305741 SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
5742 SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
5743
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305744 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
5745 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
5746
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305747 SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
5748 SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
5749 SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
5750
Simmi Pateriya6dc02f72012-10-08 13:28:31 +05305751 SITAR_REG_VAL(SITAR_A_RX_LINE_BIAS_PA, 0xA7),
5752
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305753 SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
Asish Bhattacharya2e1d7522012-05-25 15:08:40 +05305754 SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
5755 SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305756
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305757 SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
5758
5759 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
Bhalchandra Gajare8a0bb372012-10-03 18:41:01 -07005760 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x5B),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305761
5762};
5763
5764static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
5765{
5766 u32 i;
5767 for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
5768 snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
5769 sitar_1_1_reg_defaults[i].val);
5770
5771}
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305772
5773static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
5774 {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
5775};
5776
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305777static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
5778 /* Initialize current threshold to 350MA
5779 * number of wait and run cycles to 4096
5780 */
Bhalchandra Gajare33f74302012-06-14 15:12:51 -07005781 {SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305782 {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
5783
5784 {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
5785
5786 /* Initialize gain registers to use register gain */
5787 {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
5788 {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
5789 {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
5790 {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
5791
Kuirong Wangccb29c62012-06-15 11:09:07 -07005792 /* Set the MICBIAS default output as pull down*/
5793 {SITAR_A_MICB_1_CTL, 0x01, 0x01},
5794 {SITAR_A_MICB_2_CTL, 0x01, 0x01},
5795
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305796 /* Initialize mic biases to differential mode */
5797 {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
5798 {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
5799
5800 {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
5801
5802 /* Use 16 bit sample size for TX1 to TX6 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005803 {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305804 {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
5805 {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
5806 {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
5807 {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005808 {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305809
5810 /* Use 16 bit sample size for RX */
5811 {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
5812 {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
5813
5814 /*enable HPF filter for TX paths */
5815 {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005816 {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07005817
5818 /*enable External clock select*/
5819 {SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305820};
5821
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305822static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
5823{
5824 u32 i;
5825 for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
5826 snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
5827 sitar_i2c_codec_reg_init_val[i].mask,
5828 sitar_i2c_codec_reg_init_val[i].val);
5829}
5830
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305831static void sitar_codec_init_reg(struct snd_soc_codec *codec)
5832{
5833 u32 i;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305834 for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
5835 snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
5836 sitar_codec_reg_init_val[i].mask,
5837 sitar_codec_reg_init_val[i].val);
5838}
5839
5840static int sitar_codec_probe(struct snd_soc_codec *codec)
5841{
Kuirong Wang906ac472012-07-09 12:54:44 -07005842 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305843 struct sitar_priv *sitar;
5844 struct snd_soc_dapm_context *dapm = &codec->dapm;
5845 int ret = 0;
5846 int i;
5847 u8 sitar_version;
Kuirong Wang906ac472012-07-09 12:54:44 -07005848 void *ptr = NULL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305849
5850 codec->control_data = dev_get_drvdata(codec->dev->parent);
Kuirong Wang906ac472012-07-09 12:54:44 -07005851 core = codec->control_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305852
5853 sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
5854 if (!sitar) {
5855 dev_err(codec->dev, "Failed to allocate private data\n");
5856 return -ENOMEM;
5857 }
5858
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07005859 for (i = 0; i < NUM_DECIMATORS; i++) {
5860 tx_hpf_work[i].sitar = sitar;
5861 tx_hpf_work[i].decimator = i + 1;
5862 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
5863 tx_hpf_corner_freq_callback);
5864 }
5865
5866
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305867 /* Make sure mbhc micbias register addresses are zeroed out */
5868 memset(&sitar->mbhc_bias_regs, 0,
5869 sizeof(struct mbhc_micbias_regs));
5870 sitar->cfilt_k_value = 0;
5871 sitar->mbhc_micbias_switched = false;
5872
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005873 /* Make sure mbhc intenal calibration data is zeroed out */
5874 memset(&sitar->mbhc_data, 0,
5875 sizeof(struct mbhc_internal_cal_data));
5876 sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
5877 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
5878 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305879 snd_soc_codec_set_drvdata(codec, sitar);
5880
5881 sitar->mclk_enabled = false;
5882 sitar->bandgap_type = SITAR_BANDGAP_OFF;
5883 sitar->clock_active = false;
5884 sitar->config_mode_active = false;
5885 sitar->mbhc_polling_active = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305886 sitar->no_mic_headset_override = false;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005887 mutex_init(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305888 sitar->codec = codec;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005889 sitar->mbhc_state = MBHC_STATE_NONE;
5890 sitar->mbhc_last_resume = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305891 sitar->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305892 sitar_update_reg_defaults(codec);
5893 sitar_codec_init_reg(codec);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305894 sitar->intf_type = wcd9xxx_get_intf_type();
5895 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
5896 sitar_i2c_codec_init_reg(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305897
Kuirong Wang80dedd62012-12-07 19:16:24 +05305898 for (i = 0; i < COMPANDER_MAX; i++) {
5899 sitar->comp_enabled[i] = 0;
5900 sitar->comp_fs[i] = COMPANDER_FS_48KHZ;
5901 }
5902
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305903 ret = sitar_handle_pdata(sitar);
5904 if (IS_ERR_VALUE(ret)) {
5905 pr_err("%s: bad pdata\n", __func__);
5906 goto err_pdata;
5907 }
5908
Steve Mucklef132c6c2012-06-06 18:30:57 -07005909 snd_soc_add_codec_controls(codec, sitar_snd_controls,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305910 ARRAY_SIZE(sitar_snd_controls));
5911 snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
5912 ARRAY_SIZE(sitar_dapm_widgets));
Kuirong Wang906ac472012-07-09 12:54:44 -07005913
5914 ptr = kmalloc((sizeof(sitar_rx_chs) +
5915 sizeof(sitar_tx_chs)), GFP_KERNEL);
5916 if (!ptr) {
5917 pr_err("%s: no mem for slim chan ctl data\n", __func__);
5918 ret = -ENOMEM;
5919 goto err_nomem_slimch;
5920 }
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305921 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
5922 snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
5923 ARRAY_SIZE(sitar_dapm_i2s_widgets));
5924 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5925 ARRAY_SIZE(audio_i2s_map));
Kuirong Wang906ac472012-07-09 12:54:44 -07005926 for (i = 0; i < ARRAY_SIZE(sitar_i2s_dai); i++)
5927 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305928 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005929 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
5930 for (i = 0; i < NUM_CODEC_DAIS; i++) {
5931 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
5932 init_waitqueue_head(&sitar->dai[i].dai_wait);
5933 }
5934 }
5935 core->num_rx_port = SITAR_RX_MAX;
5936 core->rx_chs = ptr;
5937 memcpy(core->rx_chs, sitar_rx_chs, sizeof(sitar_rx_chs));
5938 core->num_tx_port = SITAR_TX_MAX;
5939 core->tx_chs = ptr + sizeof(sitar_rx_chs);
5940 memcpy(core->tx_chs, sitar_tx_chs, sizeof(sitar_tx_chs));
5941
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305942 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
5943
5944 sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
5945 pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
5946
5947 sitar_version &= 0x1F;
5948 pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
5949
5950 snd_soc_dapm_sync(dapm);
5951
5952
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005953 ret = wcd9xxx_request_irq(codec->control_data,
5954 WCD9XXX_IRQ_MBHC_INSERTION,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305955 sitar_hs_insert_irq, "Headset insert detect", sitar);
5956 if (ret) {
5957 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005958 WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305959 goto err_insert_irq;
5960 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005961 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305962
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005963 ret = wcd9xxx_request_irq(codec->control_data,
5964 WCD9XXX_IRQ_MBHC_REMOVAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305965 sitar_hs_remove_irq, "Headset remove detect", sitar);
5966 if (ret) {
5967 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005968 WCD9XXX_IRQ_MBHC_REMOVAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305969 goto err_remove_irq;
5970 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305971
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005972 ret = wcd9xxx_request_irq(codec->control_data,
5973 WCD9XXX_IRQ_MBHC_POTENTIAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305974 sitar_dce_handler, "DC Estimation detect", sitar);
5975 if (ret) {
5976 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005977 WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305978 goto err_potential_irq;
5979 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305980
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005981 ret = wcd9xxx_request_irq(codec->control_data,
5982 WCD9XXX_IRQ_MBHC_RELEASE,
5983 sitar_release_handler,
5984 "Button Release detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305985 if (ret) {
5986 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005987 WCD9XXX_IRQ_MBHC_RELEASE);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305988 goto err_release_irq;
5989 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305990
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005991 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
5992 sitar_slimbus_irq, "SLIMBUS Slave", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305993 if (ret) {
5994 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005995 WCD9XXX_IRQ_SLIMBUS);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305996 goto err_slimbus_irq;
5997 }
5998
5999 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
6000 wcd9xxx_interface_reg_write(codec->control_data,
6001 SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
6002
6003
6004 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006005 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
6006 sitar_hphl_ocp_irq,
6007 "HPH_L OCP detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306008 if (ret) {
6009 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006010 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306011 goto err_hphl_ocp_irq;
6012 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006013 wcd9xxx_disable_irq(codec->control_data,
6014 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306015
6016 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006017 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
6018 sitar_hphr_ocp_irq, "HPH_R OCP detect",
6019 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306020 if (ret) {
6021 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006022 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306023 goto err_hphr_ocp_irq;
6024 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006025 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306026
Steve Mucklef132c6c2012-06-06 18:30:57 -07006027 codec->ignore_pmdown_time = 1;
6028
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306029#ifdef CONFIG_DEBUG_FS
6030 debug_sitar_priv = sitar;
6031#endif
6032
6033 return ret;
6034
6035err_hphr_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006036 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
6037 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306038err_hphl_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006039 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306040err_slimbus_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006041 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306042err_release_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006043 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
6044 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306045err_potential_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006046 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306047err_remove_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006048 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
6049 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306050err_insert_irq:
Kuirong Wang906ac472012-07-09 12:54:44 -07006051 kfree(ptr);
6052err_nomem_slimch:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306053err_pdata:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006054 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306055 kfree(sitar);
6056 return ret;
6057}
6058static int sitar_codec_remove(struct snd_soc_codec *codec)
6059{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306060 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006061 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
6062 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
6063 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
6064 sitar);
6065 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
6066 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
6067 sitar);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006068 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306069 sitar_codec_disable_clock_block(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006070 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306071 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08006072 if (sitar->mbhc_fw)
6073 release_firmware(sitar->mbhc_fw);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006074 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306075 kfree(sitar);
6076 return 0;
6077}
6078static struct snd_soc_codec_driver soc_codec_dev_sitar = {
6079 .probe = sitar_codec_probe,
6080 .remove = sitar_codec_remove,
6081 .read = sitar_read,
6082 .write = sitar_write,
6083
6084 .readable_register = sitar_readable,
6085 .volatile_register = sitar_volatile,
6086
6087 .reg_cache_size = SITAR_CACHE_SIZE,
6088 .reg_cache_default = sitar_reg_defaults,
6089 .reg_word_size = 1,
6090};
6091
6092#ifdef CONFIG_DEBUG_FS
6093static struct dentry *debugfs_poke;
6094
6095static int codec_debug_open(struct inode *inode, struct file *file)
6096{
6097 file->private_data = inode->i_private;
6098 return 0;
6099}
6100
6101static ssize_t codec_debug_write(struct file *filp,
6102 const char __user *ubuf, size_t cnt, loff_t *ppos)
6103{
6104 char lbuf[32];
6105 char *buf;
6106 int rc;
6107
6108 if (cnt > sizeof(lbuf) - 1)
6109 return -EINVAL;
6110
6111 rc = copy_from_user(lbuf, ubuf, cnt);
6112 if (rc)
6113 return -EFAULT;
6114
6115 lbuf[cnt] = '\0';
6116 buf = (char *)lbuf;
6117 debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
6118 ? false : true;
6119
6120 return rc;
6121}
6122
6123static const struct file_operations codec_debug_ops = {
6124 .open = codec_debug_open,
6125 .write = codec_debug_write,
6126};
6127#endif
6128
6129#ifdef CONFIG_PM
6130static int sitar_suspend(struct device *dev)
6131{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08006132 dev_dbg(dev, "%s: system suspend\n", __func__);
6133 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306134}
6135
6136static int sitar_resume(struct device *dev)
6137{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006138 struct platform_device *pdev = to_platform_device(dev);
6139 struct sitar_priv *sitar = platform_get_drvdata(pdev);
Asish Bhattacharya1d069532012-03-07 13:25:24 -08006140 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006141 sitar->mbhc_last_resume = jiffies;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08006142 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306143}
6144
6145static const struct dev_pm_ops sitar_pm_ops = {
6146 .suspend = sitar_suspend,
6147 .resume = sitar_resume,
6148};
6149#endif
6150
6151static int __devinit sitar_probe(struct platform_device *pdev)
6152{
6153 int ret = 0;
6154 pr_err("%s\n", __func__);
6155#ifdef CONFIG_DEBUG_FS
6156 debugfs_poke = debugfs_create_file("TRRS",
6157 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
6158
6159#endif
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05306160 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
6161 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306162 sitar_dai, ARRAY_SIZE(sitar_dai));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05306163 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
6164 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
6165 sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306166 return ret;
6167}
6168static int __devexit sitar_remove(struct platform_device *pdev)
6169{
6170 snd_soc_unregister_codec(&pdev->dev);
6171
6172#ifdef CONFIG_DEBUG_FS
6173 debugfs_remove(debugfs_poke);
6174#endif
6175 return 0;
6176}
6177static struct platform_driver sitar_codec_driver = {
6178 .probe = sitar_probe,
6179 .remove = sitar_remove,
6180 .driver = {
6181 .name = "sitar_codec",
6182 .owner = THIS_MODULE,
6183#ifdef CONFIG_PM
6184 .pm = &sitar_pm_ops,
6185#endif
6186 },
6187};
6188
6189static int __init sitar_codec_init(void)
6190{
6191 return platform_driver_register(&sitar_codec_driver);
6192}
6193
6194static void __exit sitar_codec_exit(void)
6195{
6196 platform_driver_unregister(&sitar_codec_driver);
6197}
6198
6199module_init(sitar_codec_init);
6200module_exit(sitar_codec_exit);
6201
6202MODULE_DESCRIPTION("Sitar codec driver");
6203MODULE_VERSION("1.0");
6204MODULE_LICENSE("GPL v2");