blob: a68722c7e90fd5f890906114dd0ef6a7569376d7 [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 Wang80aca0d2013-05-09 14:51:09 -070048#define SITAR_RX_PORT_START_NUMBER 10
Kuirong Wang906ac472012-07-09 12:54:44 -070049
50enum {
51 AIF1_PB = 0,
52 AIF1_CAP,
53 NUM_CODEC_DAIS,
54};
55
56struct wcd9xxx_ch sitar_rx_chs[SITAR_RX_MAX] = {
Kuirong Wang80aca0d2013-05-09 14:51:09 -070057 WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER, 0),
58 WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 1, 1),
59 WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 2, 2),
60 WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 3, 3),
61 WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 4, 4)
Kuirong Wang906ac472012-07-09 12:54:44 -070062};
63
64struct wcd9xxx_ch sitar_tx_chs[SITAR_TX_MAX] = {
65 WCD9XXX_CH(0, 0),
66 WCD9XXX_CH(1, 1),
67 WCD9XXX_CH(2, 2),
68 WCD9XXX_CH(3, 3),
69 WCD9XXX_CH(4, 4),
70};
71
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080072#define SITAR_CFILT_FAST_MODE 0x00
73#define SITAR_CFILT_SLOW_MODE 0x40
74#define MBHC_FW_READ_ATTEMPTS 15
75#define MBHC_FW_READ_TIMEOUT 2000000
76
Kuirong Wang906ac472012-07-09 12:54:44 -070077#define SLIM_CLOSE_TIMEOUT 1000
78
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080079#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
80
81#define SITAR_I2S_MASTER_MODE_MASK 0x08
82
83#define SITAR_OCP_ATTEMPT 1
84
Kuirong Wang80dedd62012-12-07 19:16:24 +053085#define COMP_DIGITAL_DB_GAIN_APPLY(a, b) \
86 (((a) <= 0) ? ((a) - b) : (a))
87/* The wait time value comes from codec HW specification */
88#define COMP_BRINGUP_WAIT_TIME 3000
89
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080090#define SITAR_MCLK_RATE_12288KHZ 12288000
91#define SITAR_MCLK_RATE_9600KHZ 9600000
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053092
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080093#define SITAR_FAKE_INS_THRESHOLD_MS 2500
94#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070095#define SITAR_MBHC_BUTTON_MIN 0x8000
96#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
97
98#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
99#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
100
101#define MBHC_NUM_DCE_PLUG_DETECT 3
102#define SITAR_MBHC_FAKE_INSERT_LOW 10
103#define SITAR_MBHC_FAKE_INSERT_HIGH 80
104#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
105#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
106#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
107#define NUM_ATTEMPTS_TO_REPORT 5
108#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
109#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530110
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -0700111#define CUT_OF_FREQ_MASK 0x30
112#define CF_MIN_3DB_4HZ 0x0
113#define CF_MIN_3DB_75HZ 0x01
114#define CF_MIN_3DB_150HZ 0x02
115
116
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530117static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
118static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
119static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
120static struct snd_soc_dai_driver sitar_dai[];
121static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
122 struct snd_kcontrol *kcontrol, int event);
123static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
124 struct snd_kcontrol *kcontrol, int event);
125
126enum sitar_bandgap_type {
127 SITAR_BANDGAP_OFF = 0,
128 SITAR_BANDGAP_AUDIO_MODE,
129 SITAR_BANDGAP_MBHC_MODE,
130};
131
132struct mbhc_micbias_regs {
133 u16 cfilt_val;
134 u16 cfilt_ctl;
135 u16 mbhc_reg;
136 u16 int_rbias;
137 u16 ctl_reg;
138 u8 cfilt_sel;
139};
140
141/* Codec supports 2 IIR filters */
142enum {
143 IIR1 = 0,
144 IIR2,
145 IIR_MAX,
146};
147/* Codec supports 5 bands */
148enum {
149 BAND1 = 0,
150 BAND2,
151 BAND3,
152 BAND4,
153 BAND5,
154 BAND_MAX,
155};
156
Kuirong Wang80dedd62012-12-07 19:16:24 +0530157enum {
158 COMPANDER_1 = 0,
159 COMPANDER_2,
160 COMPANDER_MAX,
161};
162
163enum {
164 COMPANDER_FS_8KHZ = 0,
165 COMPANDER_FS_16KHZ,
166 COMPANDER_FS_32KHZ,
167 COMPANDER_FS_48KHZ,
168 COMPANDER_FS_96KHZ,
169 COMPANDER_FS_192KHZ,
170 COMPANDER_FS_MAX,
171};
172
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530173/* Flags to track of PA and DAC state.
174 * PA and DAC should be tracked separately as AUXPGA loopback requires
175 * only PA to be turned on without DAC being on. */
176enum sitar_priv_ack_flags {
177 SITAR_HPHL_PA_OFF_ACK = 0,
178 SITAR_HPHR_PA_OFF_ACK,
179 SITAR_HPHL_DAC_OFF_ACK,
180 SITAR_HPHR_DAC_OFF_ACK
181};
182
Kuirong Wang80dedd62012-12-07 19:16:24 +0530183struct comp_sample_dependent_params {
184 u32 peak_det_timeout;
185 u32 rms_meter_div_fact;
186 u32 rms_meter_resamp_fact;
187};
188
189struct comp_dgtl_gain_offset {
190 u8 whole_db_gain;
191 u8 half_db_gain;
192};
193
194static const struct comp_dgtl_gain_offset comp_dgtl_gain[] = {
195 {0, 0},
196 {1, 1},
197 {3, 0},
198 {4, 1},
199 {6, 0},
200 {7, 1},
201 {9, 0},
202 {10, 1},
203 {12, 0},
204 {13, 1},
205 {15, 0},
206 {16, 1},
207 {18, 0},
208};
209
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800210/* Data used by MBHC */
211struct mbhc_internal_cal_data {
212 u16 dce_z;
213 u16 dce_mb;
214 u16 sta_z;
215 u16 sta_mb;
216 u32 t_sta_dce;
217 u32 t_dce;
218 u32 t_sta;
219 u32 micb_mv;
220 u16 v_ins_hu;
221 u16 v_ins_h;
222 u16 v_b1_hu;
223 u16 v_b1_h;
224 u16 v_b1_huc;
225 u16 v_brh;
226 u16 v_brl;
227 u16 v_no_mic;
228 u8 npoll;
229 u8 nbounce_wait;
230};
231
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700232enum sitar_mbhc_plug_type {
233 PLUG_TYPE_INVALID = -1,
234 PLUG_TYPE_NONE,
235 PLUG_TYPE_HEADSET,
236 PLUG_TYPE_HEADPHONE,
237 PLUG_TYPE_HIGH_HPH,
238};
239
240enum sitar_mbhc_state {
241 MBHC_STATE_NONE = -1,
242 MBHC_STATE_POTENTIAL,
243 MBHC_STATE_POTENTIAL_RECOVERY,
244 MBHC_STATE_RELEASE,
245};
246
Kuirong Wang906ac472012-07-09 12:54:44 -0700247static const u32 vport_check_table[NUM_CODEC_DAIS] = {
248 0, /* AIF1_PB */
249 0, /* AIF1_CAP */
250};
251
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -0700252struct hpf_work {
253 struct sitar_priv *sitar;
254 u32 decimator;
255 u8 tx_hpf_cut_of_freq;
256 struct delayed_work dwork;
257};
258
259static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
260
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530261struct sitar_priv {
262 struct snd_soc_codec *codec;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800263 u32 mclk_freq;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530264 u32 adc_count;
265 u32 cfilt1_cnt;
266 u32 cfilt2_cnt;
267 u32 cfilt3_cnt;
268 u32 rx_bias_count;
269 enum sitar_bandgap_type bandgap_type;
270 bool mclk_enabled;
271 bool clock_active;
272 bool config_mode_active;
273 bool mbhc_polling_active;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800274 unsigned long mbhc_fake_ins_start;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530275 int buttons_pressed;
276
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800277 enum sitar_micbias_num micbias;
278 /* void* calibration contains:
279 * struct sitar_mbhc_general_cfg generic;
280 * struct sitar_mbhc_plug_detect_cfg plug_det;
281 * struct sitar_mbhc_plug_type_cfg plug_type;
282 * struct sitar_mbhc_btn_detect_cfg btn_det;
283 * struct sitar_mbhc_imped_detect_cfg imped_det;
284 * Note: various size depends on btn_det->num_btn
285 */
286 void *calibration;
287 struct mbhc_internal_cal_data mbhc_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530288
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530289 struct wcd9xxx_pdata *pdata;
290 u32 anc_slot;
291
292 bool no_mic_headset_override;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530293
294 struct mbhc_micbias_regs mbhc_bias_regs;
295 u8 cfilt_k_value;
296 bool mbhc_micbias_switched;
297
298 /* track PA/DAC state */
299 unsigned long hph_pa_dac_state;
300
301 /*track sitar interface type*/
302 u8 intf_type;
303
304 u32 hph_status; /* track headhpone status */
305 /* define separate work for left and right headphone OCP to avoid
306 * additional checking on which OCP event to report so no locking
307 * to ensure synchronization is required
308 */
309 struct work_struct hphlocp_work; /* reporting left hph ocp off */
310 struct work_struct hphrocp_work; /* reporting right hph ocp off */
311
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530312 u8 hphlocp_cnt; /* headphone left ocp retry */
313 u8 hphrocp_cnt; /* headphone right ocp retry */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800314
315 /* Callback function to enable MCLK */
316 int (*mclk_cb) (struct snd_soc_codec*, int);
317
318 /* Work to perform MBHC Firmware Read */
319 struct delayed_work mbhc_firmware_dwork;
320 const struct firmware *mbhc_fw;
321
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530322 /* num of slim ports required */
Kuirong Wang906ac472012-07-09 12:54:44 -0700323 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700324
Kuirong Wang80dedd62012-12-07 19:16:24 +0530325 /*compander*/
326 int comp_enabled[COMPANDER_MAX];
327 u32 comp_fs[COMPANDER_MAX];
328 u8 comp_gain_offset[NUM_INTERPOLATORS];
329
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700330 /* Currently, only used for mbhc purpose, to protect
331 * concurrent execution of mbhc threaded irq handlers and
332 * kill race between DAPM and MBHC.But can serve as a
333 * general lock to protect codec resource
334 */
335 struct mutex codec_resource_lock;
336
337 struct sitar_mbhc_config mbhc_cfg;
338 bool in_gpio_handler;
339 u8 current_plug;
340 bool lpi_enabled;
341 enum sitar_mbhc_state mbhc_state;
342 struct work_struct hs_correct_plug_work;
343 bool hs_detect_work_stop;
344 struct delayed_work mbhc_btn_dwork;
345 unsigned long mbhc_last_resume; /* in jiffies */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530346};
347
348#ifdef CONFIG_DEBUG_FS
349struct sitar_priv *debug_sitar_priv;
350#endif
351
Kuirong Wang80dedd62012-12-07 19:16:24 +0530352static const int comp_rx_path[] = {
353 COMPANDER_2,
354 COMPANDER_1,
355 COMPANDER_1,
356 COMPANDER_MAX,
357};
358
359static const struct comp_sample_dependent_params
360 comp_samp_params[COMPANDER_FS_MAX] = {
361 {
362 .peak_det_timeout = 0x6,
363 .rms_meter_div_fact = 0x9 << 4,
364 .rms_meter_resamp_fact = 0x06,
365 },
366 {
367 .peak_det_timeout = 0x7,
368 .rms_meter_div_fact = 0xA << 4,
369 .rms_meter_resamp_fact = 0x0C,
370 },
371 {
372 .peak_det_timeout = 0x8,
373 .rms_meter_div_fact = 0xB << 4,
374 .rms_meter_resamp_fact = 0x30,
375 },
376 {
377 .peak_det_timeout = 0x9,
378 .rms_meter_div_fact = 0xB << 4,
379 .rms_meter_resamp_fact = 0x28,
380 },
381 {
382 .peak_det_timeout = 0xA,
383 .rms_meter_div_fact = 0xC << 4,
384 .rms_meter_resamp_fact = 0x50,
385 },
386 {
387 .peak_det_timeout = 0xB,
388 .rms_meter_div_fact = 0xC << 4,
389 .rms_meter_resamp_fact = 0x50,
390 },
391};
392
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700393static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
394 struct snd_ctl_elem_value *ucontrol)
395{
396 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
397 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
398 ucontrol->value.integer.value[0] = sitar->anc_slot;
399 return 0;
400}
401
402static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
403 struct snd_ctl_elem_value *ucontrol)
404{
405 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
406 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
407 sitar->anc_slot = ucontrol->value.integer.value[0];
408 return 0;
409}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530410
411static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
412 struct snd_ctl_elem_value *ucontrol)
413{
414 u8 ear_pa_gain;
415 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
416
417 ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
418
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700419 ear_pa_gain &= 0xE0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530420
421 if (ear_pa_gain == 0x00) {
422 ucontrol->value.integer.value[0] = 0;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700423 } else if (ear_pa_gain == 0x80) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530424 ucontrol->value.integer.value[0] = 1;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700425 } else if (ear_pa_gain == 0xA0) {
426 ucontrol->value.integer.value[0] = 2;
427 } else if (ear_pa_gain == 0xE0) {
428 ucontrol->value.integer.value[0] = 3;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530429 } else {
430 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
431 __func__, ear_pa_gain);
432 return -EINVAL;
433 }
434
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530435 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530436
437 return 0;
438}
439
440static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
441 struct snd_ctl_elem_value *ucontrol)
442{
443 u8 ear_pa_gain;
444 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
445
446 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
447 ucontrol->value.integer.value[0]);
448
449 switch (ucontrol->value.integer.value[0]) {
450 case 0:
451 ear_pa_gain = 0x00;
452 break;
453 case 1:
454 ear_pa_gain = 0x80;
455 break;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700456 case 2:
457 ear_pa_gain = 0xA0;
458 break;
459 case 3:
460 ear_pa_gain = 0xE0;
461 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530462 default:
463 return -EINVAL;
464 }
465
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700466 snd_soc_update_bits(codec, SITAR_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530467 return 0;
468}
469
470static int sitar_get_iir_enable_audio_mixer(
471 struct snd_kcontrol *kcontrol,
472 struct snd_ctl_elem_value *ucontrol)
473{
474 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
475 int iir_idx = ((struct soc_multi_mixer_control *)
476 kcontrol->private_value)->reg;
477 int band_idx = ((struct soc_multi_mixer_control *)
478 kcontrol->private_value)->shift;
479
480 ucontrol->value.integer.value[0] =
481 snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
482 (1 << band_idx);
483
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530484 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530485 iir_idx, band_idx,
486 (uint32_t)ucontrol->value.integer.value[0]);
487 return 0;
488}
489
490static int sitar_put_iir_enable_audio_mixer(
491 struct snd_kcontrol *kcontrol,
492 struct snd_ctl_elem_value *ucontrol)
493{
494 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
495 int iir_idx = ((struct soc_multi_mixer_control *)
496 kcontrol->private_value)->reg;
497 int band_idx = ((struct soc_multi_mixer_control *)
498 kcontrol->private_value)->shift;
499 int value = ucontrol->value.integer.value[0];
500
501 /* Mask first 5 bits, 6-8 are reserved */
502 snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
503 (1 << band_idx), (value << band_idx));
504
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530505 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530506 iir_idx, band_idx, value);
507 return 0;
508}
509static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
510 int iir_idx, int band_idx,
511 int coeff_idx)
512{
513 /* Address does not automatically update if reading */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530514 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530515 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530516 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530517
518 /* Mask bits top 2 bits since they are reserved */
519 return ((snd_soc_read(codec,
520 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
521 (snd_soc_read(codec,
522 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
523 (snd_soc_read(codec,
524 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
525 (snd_soc_read(codec,
526 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
527 0x3FFFFFFF;
528}
529
530static int sitar_get_iir_band_audio_mixer(
531 struct snd_kcontrol *kcontrol,
532 struct snd_ctl_elem_value *ucontrol)
533{
534 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
535 int iir_idx = ((struct soc_multi_mixer_control *)
536 kcontrol->private_value)->reg;
537 int band_idx = ((struct soc_multi_mixer_control *)
538 kcontrol->private_value)->shift;
539
540 ucontrol->value.integer.value[0] =
541 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
542 ucontrol->value.integer.value[1] =
543 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
544 ucontrol->value.integer.value[2] =
545 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
546 ucontrol->value.integer.value[3] =
547 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
548 ucontrol->value.integer.value[4] =
549 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
550
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530551 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530552 "%s: IIR #%d band #%d b1 = 0x%x\n"
553 "%s: IIR #%d band #%d b2 = 0x%x\n"
554 "%s: IIR #%d band #%d a1 = 0x%x\n"
555 "%s: IIR #%d band #%d a2 = 0x%x\n",
556 __func__, iir_idx, band_idx,
557 (uint32_t)ucontrol->value.integer.value[0],
558 __func__, iir_idx, band_idx,
559 (uint32_t)ucontrol->value.integer.value[1],
560 __func__, iir_idx, band_idx,
561 (uint32_t)ucontrol->value.integer.value[2],
562 __func__, iir_idx, band_idx,
563 (uint32_t)ucontrol->value.integer.value[3],
564 __func__, iir_idx, band_idx,
565 (uint32_t)ucontrol->value.integer.value[4]);
566 return 0;
567}
568
569static void set_iir_band_coeff(struct snd_soc_codec *codec,
570 int iir_idx, int band_idx,
571 int coeff_idx, uint32_t value)
572{
573 /* Mask top 3 bits, 6-8 are reserved */
574 /* Update address manually each time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530575 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530576 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530577 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530578
579 /* Mask top 2 bits, 7-8 are reserved */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530580 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530581 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530582 (value >> 24) & 0x3F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530583
584 /* Isolate 8bits at a time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530585 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530586 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530587 (value >> 16) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530588
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530589 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530590 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530591 (value >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530592
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530593 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530594 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530595 value & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530596}
597
598static int sitar_put_iir_band_audio_mixer(
599 struct snd_kcontrol *kcontrol,
600 struct snd_ctl_elem_value *ucontrol)
601{
602 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
603 int iir_idx = ((struct soc_multi_mixer_control *)
604 kcontrol->private_value)->reg;
605 int band_idx = ((struct soc_multi_mixer_control *)
606 kcontrol->private_value)->shift;
607
608 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
609 ucontrol->value.integer.value[0]);
610 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
611 ucontrol->value.integer.value[1]);
612 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
613 ucontrol->value.integer.value[2]);
614 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
615 ucontrol->value.integer.value[3]);
616 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
617 ucontrol->value.integer.value[4]);
618
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530619 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530620 "%s: IIR #%d band #%d b1 = 0x%x\n"
621 "%s: IIR #%d band #%d b2 = 0x%x\n"
622 "%s: IIR #%d band #%d a1 = 0x%x\n"
623 "%s: IIR #%d band #%d a2 = 0x%x\n",
624 __func__, iir_idx, band_idx,
625 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
626 __func__, iir_idx, band_idx,
627 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
628 __func__, iir_idx, band_idx,
629 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
630 __func__, iir_idx, band_idx,
631 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
632 __func__, iir_idx, band_idx,
633 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
634 return 0;
635}
636
Kuirong Wang80dedd62012-12-07 19:16:24 +0530637static int sitar_compander_gain_offset(
638 struct snd_soc_codec *codec, u32 enable,
639 unsigned int pa_reg, unsigned int vol_reg,
640 int mask, int event,
641 struct comp_dgtl_gain_offset *gain_offset,
642 int index)
643{
644 unsigned int pa_gain = snd_soc_read(codec, pa_reg);
645 unsigned int digital_vol = snd_soc_read(codec, vol_reg);
646 int pa_mode = pa_gain & mask;
647 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
648
649 pr_debug("%s: pa_gain(0x%x=0x%x)digital_vol(0x%x=0x%x)event(0x%x) index(%d)\n",
650 __func__, pa_reg, pa_gain, vol_reg, digital_vol, event, index);
651 if (((pa_gain & 0xF) + 1) > ARRAY_SIZE(comp_dgtl_gain) ||
652 (index >= ARRAY_SIZE(sitar->comp_gain_offset))) {
653 pr_err("%s: Out of array boundary\n", __func__);
654 return -EINVAL;
655 }
656
657 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0)) {
658 gain_offset->whole_db_gain = COMP_DIGITAL_DB_GAIN_APPLY(
659 (digital_vol - comp_dgtl_gain[pa_gain & 0xF].whole_db_gain),
660 comp_dgtl_gain[pa_gain & 0xF].half_db_gain);
661 pr_debug("%s: listed whole_db_gain:0x%x, adjusted whole_db_gain:0x%x\n",
662 __func__, comp_dgtl_gain[pa_gain & 0xF].whole_db_gain,
663 gain_offset->whole_db_gain);
664 gain_offset->half_db_gain =
665 comp_dgtl_gain[pa_gain & 0xF].half_db_gain;
666 sitar->comp_gain_offset[index] = digital_vol -
667 gain_offset->whole_db_gain ;
668 }
669 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0)) {
670 gain_offset->whole_db_gain = digital_vol +
671 sitar->comp_gain_offset[index];
672 pr_debug("%s: listed whole_db_gain:0x%x, adjusted whole_db_gain:0x%x\n",
673 __func__, comp_dgtl_gain[pa_gain & 0xF].whole_db_gain,
674 gain_offset->whole_db_gain);
675 gain_offset->half_db_gain = 0;
676 }
677
678 pr_debug("%s: half_db_gain(%d)whole_db_gain(0x%x)comp_gain_offset[%d](%d)\n",
679 __func__, gain_offset->half_db_gain,
680 gain_offset->whole_db_gain, index,
681 sitar->comp_gain_offset[index]);
682 return 0;
683}
684
685static int sitar_config_gain_compander(
686 struct snd_soc_codec *codec,
687 u32 compander, u32 enable, int event)
688{
689 int value = 0;
690 int mask = 1 << 4;
691 struct comp_dgtl_gain_offset gain_offset = {0, 0};
692 if (compander >= COMPANDER_MAX) {
693 pr_err("%s: Error, invalid compander channel\n", __func__);
694 return -EINVAL;
695 }
696
697 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
698 value = 1 << 4;
699
700 if (compander == COMPANDER_1) {
701 sitar_compander_gain_offset(codec, enable,
702 SITAR_A_RX_HPH_L_GAIN,
703 SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
704 mask, event, &gain_offset, 1);
705 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_GAIN, mask, value);
706 snd_soc_update_bits(codec, SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
707 0xFF, gain_offset.whole_db_gain);
708 snd_soc_update_bits(codec, SITAR_A_CDC_RX2_B6_CTL,
709 0x02, gain_offset.half_db_gain);
710 sitar_compander_gain_offset(codec, enable,
711 SITAR_A_RX_HPH_R_GAIN,
712 SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
713 mask, event, &gain_offset, 2);
714 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_GAIN, mask, value);
715 snd_soc_update_bits(codec, SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
716 0xFF, gain_offset.whole_db_gain);
717 snd_soc_update_bits(codec, SITAR_A_CDC_RX3_B6_CTL,
718 0x02, gain_offset.half_db_gain);
719 } else if (compander == COMPANDER_2) {
720 sitar_compander_gain_offset(codec, enable,
721 SITAR_A_RX_LINE_1_GAIN,
722 SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
723 mask, event, &gain_offset, 0);
724 snd_soc_update_bits(codec, SITAR_A_RX_LINE_1_GAIN, mask, value);
725 snd_soc_update_bits(codec, SITAR_A_RX_LINE_2_GAIN, mask, value);
726 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
727 0xFF, gain_offset.whole_db_gain);
728 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
729 0x02, gain_offset.half_db_gain);
730 }
731 return 0;
732}
733
734static int sitar_get_compander(struct snd_kcontrol *kcontrol,
735 struct snd_ctl_elem_value *ucontrol)
736{
737 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
738 int comp = ((struct soc_multi_mixer_control *)
739 kcontrol->private_value)->shift;
740 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
741
742 ucontrol->value.integer.value[0] = sitar->comp_enabled[comp];
743
744 return 0;
745}
746
747static int sitar_set_compander(struct snd_kcontrol *kcontrol,
748 struct snd_ctl_elem_value *ucontrol)
749{
750 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
751 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
752 int comp = ((struct soc_multi_mixer_control *)
753 kcontrol->private_value)->shift;
754 int value = ucontrol->value.integer.value[0];
755
756 pr_debug("%s: compander #%d enable %d\n",
757 __func__, comp + 1, value);
758 if (value == sitar->comp_enabled[comp]) {
759 pr_debug("%s: compander #%d enable %d no change\n",
760 __func__, comp + 1, value);
761 return 0;
762 }
763 sitar->comp_enabled[comp] = value;
764 return 0;
765}
766
767static int sitar_config_compander(struct snd_soc_dapm_widget *w,
768 struct snd_kcontrol *kcontrol,
769 int event)
770{
771 struct snd_soc_codec *codec = w->codec;
772 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
773 u32 rate = sitar->comp_fs[w->shift];
774 u32 value;
775
776 pr_debug("%s: compander #%d enable %d event %d widget name %s\n",
777 __func__, w->shift + 1,
778 sitar->comp_enabled[w->shift], event , w->name);
779 if (sitar->comp_enabled[w->shift] == 0)
780 goto rtn;
781 switch (event) {
782 case SND_SOC_DAPM_PRE_PMU:
783 /* Update compander sample rate */
784 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_FS_CFG +
785 w->shift * 8, 0x07, rate);
786 /* Enable compander clock */
787 snd_soc_update_bits(codec,
788 SITAR_A_CDC_CLK_RX_B2_CTL,
789 1 << w->shift,
790 1 << w->shift);
791 /* Toggle compander reset bits */
792 snd_soc_update_bits(codec,
793 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
794 1 << w->shift,
795 1 << w->shift);
796 snd_soc_update_bits(codec,
797 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
798 1 << w->shift, 0);
799 sitar_config_gain_compander(codec, w->shift, 1, event);
800 /* Compander enable -> 0x370/0x378 */
801 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B1_CTL +
802 w->shift * 8, 0x03, 0x03);
803 /* Update the RMS meter resampling */
804 snd_soc_update_bits(codec,
805 SITAR_A_CDC_COMP1_B3_CTL +
806 w->shift * 8, 0xFF, 0x01);
807 snd_soc_update_bits(codec,
808 SITAR_A_CDC_COMP1_B2_CTL +
809 w->shift * 8, 0xF0, 0x50);
810 usleep_range(COMP_BRINGUP_WAIT_TIME, COMP_BRINGUP_WAIT_TIME);
811 break;
812 case SND_SOC_DAPM_POST_PMU:
813 snd_soc_update_bits(codec,
814 SITAR_A_CDC_CLSG_CTL,
815 0x11, 0x00);
816 if (w->shift == COMPANDER_1)
817 value = 0x22;
818 else
819 value = 0x11;
820 snd_soc_write(codec,
821 SITAR_A_CDC_CONN_CLSG_CTL, value);
822
823 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B2_CTL +
824 w->shift * 8, 0x0F,
825 comp_samp_params[rate].peak_det_timeout);
826 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B2_CTL +
827 w->shift * 8, 0xF0,
828 comp_samp_params[rate].rms_meter_div_fact);
829 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B3_CTL +
830 w->shift * 8, 0xFF,
831 comp_samp_params[rate].rms_meter_resamp_fact);
832 break;
833 case SND_SOC_DAPM_POST_PMD:
834 snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B1_CTL +
835 w->shift * 8, 0x03, 0x00);
836 /* Toggle compander reset bits */
837 snd_soc_update_bits(codec,
838 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
839 1 << w->shift,
840 1 << w->shift);
841 snd_soc_update_bits(codec,
842 SITAR_A_CDC_CLK_OTHR_RESET_CTL,
843 1 << w->shift, 0);
844 /* Disable compander clock */
845 snd_soc_update_bits(codec,
846 SITAR_A_CDC_CLK_RX_B2_CTL,
847 1 << w->shift,
848 0);
849 /* Restore the gain */
850 sitar_config_gain_compander(codec, w->shift,
851 sitar->comp_enabled[w->shift],
852 event);
853 snd_soc_update_bits(codec,
854 SITAR_A_CDC_CLSG_CTL,
855 0x11, 0x11);
856 snd_soc_write(codec,
857 SITAR_A_CDC_CONN_CLSG_CTL, 0x14);
858 break;
859 }
860rtn:
861 return 0;
862}
863
864static int sitar_codec_dem_input_selection(struct snd_soc_dapm_widget *w,
865 struct snd_kcontrol *kcontrol,
866 int event)
867{
868 struct snd_soc_codec *codec = w->codec;
869 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
870 pr_debug("%s: compander#1->enable(%d) compander#2->enable(%d) reg(0x%x = 0x%x) event(%d)\n",
871 __func__, sitar->comp_enabled[COMPANDER_1],
872 sitar->comp_enabled[COMPANDER_2],
873 SITAR_A_CDC_RX1_B6_CTL + w->shift * 8,
874 snd_soc_read(codec, SITAR_A_CDC_RX1_B6_CTL + w->shift * 8),
875 event);
876 switch (event) {
877 case SND_SOC_DAPM_POST_PMU:
878 if (sitar->comp_enabled[COMPANDER_1] ||
879 sitar->comp_enabled[COMPANDER_2])
880 snd_soc_update_bits(codec,
881 SITAR_A_CDC_RX1_B6_CTL +
882 w->shift * 8,
883 1 << 5, 0);
884 else
885 snd_soc_update_bits(codec,
886 SITAR_A_CDC_RX1_B6_CTL +
887 w->shift * 8,
888 1 << 5, 0x20);
889 break;
890 case SND_SOC_DAPM_POST_PMD:
891 snd_soc_update_bits(codec,
892 SITAR_A_CDC_RX1_B6_CTL + w->shift * 8,
893 1 << 5, 0);
894 break;
895 }
896 return 0;
897}
898
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700899static const char * const sitar_ear_pa_gain_text[] = {"POS_6_DB",
900 "POS_2_DB", "NEG_2P5_DB", "NEG_12_DB"};
901
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530902static const struct soc_enum sitar_ear_pa_gain_enum[] = {
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700903 SOC_ENUM_SINGLE_EXT(4, sitar_ear_pa_gain_text),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530904};
905
906/*cut of frequency for high pass filter*/
907static const char *cf_text[] = {
908 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
909};
910
911static const struct soc_enum cf_dec1_enum =
912 SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
913
914static const struct soc_enum cf_rxmix1_enum =
915 SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
916
917static const struct snd_kcontrol_new sitar_snd_controls[] = {
918
919 SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
920 sitar_pa_gain_get, sitar_pa_gain_put),
921
922 SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
923 line_gain),
924 SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
925 line_gain),
926
927 SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
928 line_gain),
929 SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
930 line_gain),
931
932 SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
933 -84, 40, digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800934 SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
935 -84, 40, digital_gain),
936 SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
937 -84, 40, digital_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530938
939 SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
940 digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800941 SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
942 digital_gain),
943 SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
944 digital_gain),
945 SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
946 digital_gain),
947
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530948 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
949 40, digital_gain),
950 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
951 40, digital_gain),
952 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
953 40, digital_gain),
954 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
955 40, digital_gain),
956 SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
957 SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800958 SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530959
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700960 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
961 sitar_put_anc_slot),
962
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530963 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
964
965 SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
966
967 SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
968
969 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
970
971 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
972 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
973 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
974 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
975 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
976 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
977 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
978 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
979 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
980 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
981 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
982 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
983 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
984 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
985 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
986 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
987 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
988 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
989 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
990 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
991
992 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
993 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
994 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
995 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
996 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
997 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
998 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
999 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1000 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1001 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1002 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1003 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1004 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1005 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1006 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1007 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1008 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1009 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
1010 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1011 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
Kuirong Wang80dedd62012-12-07 19:16:24 +05301012 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
1013 sitar_get_compander, sitar_set_compander),
1014 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
1015 sitar_get_compander, sitar_set_compander),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301016};
1017
1018static const char *rx_mix1_text[] = {
1019 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1020 "RX5"
1021};
1022
1023static const char *rx_dac1_text[] = {
1024 "ZERO", "RX1", "RX2"
1025};
1026
1027static const char *rx_dac2_text[] = {
1028 "ZERO", "RX1",
1029};
1030
1031static const char *rx_dac3_text[] = {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001032 "ZERO", "RX1", "INV_RX1", "RX2"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301033};
1034
1035static const char *rx_dac4_text[] = {
1036 "ZERO", "ON"
1037};
1038
1039static const char *sb_tx1_mux_text[] = {
1040 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1041 "DEC1"
1042};
1043
1044static const char *sb_tx2_mux_text[] = {
1045 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1046 "DEC2"
1047};
1048
1049static const char *sb_tx3_mux_text[] = {
1050 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1051 "DEC3"
1052};
1053
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001054static const char *sb_tx4_mux_text[] = {
1055 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1056 "DEC4"
1057};
1058
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301059static const char *sb_tx5_mux_text[] = {
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001060 "ZERO", "RMIX1", "RMIX2", "RMIX3", "DEC1", "DEC2", "DEC3", "DEC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301061};
1062
1063static const char *dec1_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001064 "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301065};
1066
1067static const char *dec2_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001068 "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301069};
1070
1071static const char *dec3_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001072 "ZERO", "DMIC3", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC2", "DMIC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301073};
1074
1075static const char *dec4_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001076 "ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301077};
1078
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001079static const char const *anc_mux_text[] = {
1080 "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
1081 "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
1082};
1083
1084static const char const *anc1_fb_mux_text[] = {
1085 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1086};
1087
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301088static const char const *iir_inp1_text[] = {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301089 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
1090 "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
1091};
1092
1093static const struct soc_enum rx_mix1_inp1_chain_enum =
1094 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
1095
1096static const struct soc_enum rx_mix1_inp2_chain_enum =
1097 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
1098
1099static const struct soc_enum rx2_mix1_inp1_chain_enum =
1100 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
1101
1102static const struct soc_enum rx2_mix1_inp2_chain_enum =
1103 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
1104
1105static const struct soc_enum rx3_mix1_inp1_chain_enum =
1106 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
1107
1108static const struct soc_enum rx3_mix1_inp2_chain_enum =
1109 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
1110
1111static const struct soc_enum rx_dac1_enum =
1112 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
1113
1114static const struct soc_enum rx_dac2_enum =
1115 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
1116
1117static const struct soc_enum rx_dac3_enum =
1118 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
1119
1120static const struct soc_enum rx_dac4_enum =
1121 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
1122
1123static const struct soc_enum sb_tx5_mux_enum =
1124 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1125
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001126static const struct soc_enum sb_tx4_mux_enum =
1127 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
1128
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301129static const struct soc_enum sb_tx3_mux_enum =
1130 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
1131
1132static const struct soc_enum sb_tx2_mux_enum =
1133 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
1134
1135static const struct soc_enum sb_tx1_mux_enum =
1136 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1137
1138static const struct soc_enum dec1_mux_enum =
1139 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
1140
1141static const struct soc_enum dec2_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001142 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301143
1144static const struct soc_enum dec3_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001145 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301146
1147static const struct soc_enum dec4_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001148 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301149
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001150static const struct soc_enum anc1_mux_enum =
1151 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
1152
1153static const struct soc_enum anc2_mux_enum =
1154 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
1155
1156static const struct soc_enum anc1_fb_mux_enum =
1157 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1158
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301159static const struct soc_enum iir1_inp1_mux_enum =
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301160 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir_inp1_text);
1161
1162static const struct soc_enum iir2_inp1_mux_enum =
1163 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ2_B1_CTL, 0, 16, iir_inp1_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301164
1165static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1166 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1167
1168static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1169 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1170
1171static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1172 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1173
1174static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1175 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1176
1177static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1178 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1179
1180static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1181 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1182
1183static const struct snd_kcontrol_new rx_dac1_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001184 SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301185
1186static const struct snd_kcontrol_new rx_dac2_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001187 SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301188
1189static const struct snd_kcontrol_new rx_dac3_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001190 SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301191
1192static const struct snd_kcontrol_new rx_dac4_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001193 SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301194
1195static const struct snd_kcontrol_new sb_tx5_mux =
1196 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1197
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001198static const struct snd_kcontrol_new sb_tx4_mux =
1199 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301201static const struct snd_kcontrol_new sb_tx3_mux =
1202 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1203
1204static const struct snd_kcontrol_new sb_tx2_mux =
1205 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1206
1207static const struct snd_kcontrol_new sb_tx1_mux =
1208 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1209
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301210static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
1211 struct snd_ctl_elem_value *ucontrol)
1212 {
1213 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1214 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1215 struct snd_soc_codec *codec = w->codec;
1216 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1217 unsigned int dec_mux, decimator;
1218 char *dec_name = NULL;
1219 char *widget_name = NULL;
1220 char *temp;
1221 u16 tx_mux_ctl_reg;
1222 u8 adc_dmic_sel = 0x0;
1223 int ret = 0;
1224
1225 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1226 return -EINVAL;
1227
1228 dec_mux = ucontrol->value.enumerated.item[0];
1229
1230 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1231 if (!widget_name)
1232 return -ENOMEM;
1233 temp = widget_name;
1234
1235 dec_name = strsep(&widget_name, " ");
1236 widget_name = temp;
1237 if (!dec_name) {
1238 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1239 ret = -EINVAL;
1240 goto out;
1241 }
1242
1243 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1244 if (ret < 0) {
1245 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1246 ret = -EINVAL;
1247 goto out;
1248 }
1249
1250 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
1251 "dec_mux = %u\n", __func__, w->name, dec_name, decimator,
1252 dec_mux);
1253
1254
1255 switch (decimator) {
1256 case 1:
1257 case 2:
1258 if ((dec_mux == 1) || (dec_mux == 6))
1259 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
1260 else
1261 adc_dmic_sel = ADC_DMIC_SEL_ADC;
1262 break;
1263 case 3:
1264 if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
1265 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
1266 else
1267 adc_dmic_sel = ADC_DMIC_SEL_ADC;
1268 break;
1269 case 4:
1270 if ((dec_mux == 1) || (dec_mux == 5)
1271 || (dec_mux == 6) || (dec_mux == 7))
1272 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
1273 else
1274 adc_dmic_sel = ADC_DMIC_SEL_ADC;
1275 break;
1276 default:
1277 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1278 ret = -EINVAL;
1279 goto out;
1280 }
1281
1282 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1283
1284 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1285
1286 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1287out:
1288 kfree(widget_name);
1289 return ret;
1290}
1291
1292#define WCD9304_DEC_ENUM(xname, xenum) \
1293{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1294 .info = snd_soc_info_enum_double, \
1295 .get = snd_soc_dapm_get_enum_double, \
1296 .put = wcd9304_put_dec_enum, \
1297 .private_value = (unsigned long)&xenum }
1298
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301299static const struct snd_kcontrol_new dec1_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301300 WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301301
1302static const struct snd_kcontrol_new dec2_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301303 WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301304
1305static const struct snd_kcontrol_new dec3_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301306 WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301307
1308static const struct snd_kcontrol_new dec4_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301309 WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301310
1311static const struct snd_kcontrol_new iir1_inp1_mux =
1312 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1313
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05301314static const struct snd_kcontrol_new iir2_inp1_mux =
1315 SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
1316
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001317static const struct snd_kcontrol_new anc1_mux =
1318 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1319
1320static const struct snd_kcontrol_new anc2_mux =
1321 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
1322
1323static const struct snd_kcontrol_new anc1_fb_mux =
1324 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
1325
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301326static const struct snd_kcontrol_new dac1_switch[] = {
1327 SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
1328};
1329
Kuirong Wang906ac472012-07-09 12:54:44 -07001330static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1331 struct snd_ctl_elem_value *ucontrol)
1332{
1333 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1334 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1335
1336 ucontrol->value.integer.value[0] = widget->value;
1337 return 0;
1338}
1339
1340static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1341 struct snd_ctl_elem_value *ucontrol)
1342{
1343 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1344 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1345 struct snd_soc_codec *codec = widget->codec;
1346 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
1347 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1348 struct soc_multi_mixer_control *mixer =
1349 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1350 u32 dai_id = widget->shift;
1351 u32 port_id = mixer->shift;
1352 u32 enable = ucontrol->value.integer.value[0];
1353
1354 mutex_lock(&codec->mutex);
1355
1356 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1357 if (dai_id != AIF1_CAP) {
1358 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1359 __func__);
1360 mutex_unlock(&codec->mutex);
1361 return -EINVAL;
1362 }
1363 }
1364
1365 switch (dai_id) {
1366 case AIF1_CAP:
1367 if (enable && !(widget->value & 1 << port_id)) {
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001368 if (wcd9xxx_tx_vport_validation(
1369 vport_check_table[dai_id],
1370 port_id,
1371 sitar_p->dai)) {
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001372 dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07001373 __func__, port_id + 1);
1374 mutex_unlock(&codec->mutex);
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001375 return 0;
Kuirong Wang906ac472012-07-09 12:54:44 -07001376 }
1377 widget->value |= 1 << port_id;
1378 list_add_tail(&core->tx_chs[port_id].list,
1379 &sitar_p->dai[dai_id].wcd9xxx_ch_list);
1380 } else if (!enable && (widget->value & 1 << port_id)) {
1381 widget->value &= ~(1<<port_id);
1382 list_del_init(&core->tx_chs[port_id].list);
1383 } else {
1384 if (enable)
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001385 dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07001386 __func__, port_id + 1);
1387 else
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001388 dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07001389 __func__, port_id + 1);
1390 /* avoid update power function */
1391 mutex_unlock(&codec->mutex);
1392 return 0;
1393 }
1394 break;
1395 default:
1396 pr_err("Unknown AIF %d\n", dai_id);
1397 mutex_unlock(&codec->mutex);
1398 return -EINVAL;
1399 }
1400
1401 pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
1402 widget->name, widget->sname, widget->value, widget->shift);
1403 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1404 mutex_unlock(&codec->mutex);
1405 return 0;
1406}
1407
1408static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1409 struct snd_ctl_elem_value *ucontrol)
1410{
1411 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1412 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1413
1414 ucontrol->value.enumerated.item[0] = widget->value;
1415 return 0;
1416}
1417
1418static const char * const slim_rx_mux_text[] = {
1419 "ZERO", "AIF1_PB"
1420};
1421
1422static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1423 struct snd_ctl_elem_value *ucontrol)
1424{
1425 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1426 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1427 struct snd_soc_codec *codec = widget->codec;
1428 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
1429 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1430 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1431 u32 port_id = widget->shift;
1432
1433 widget->value = ucontrol->value.enumerated.item[0];
1434
1435 mutex_lock(&codec->mutex);
1436
1437 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1438 if (widget->value > 1) {
1439 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1440 __func__);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001441 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001442 }
1443 }
1444
1445 switch (widget->value) {
1446 case 0:
1447 list_del_init(&core->rx_chs[port_id].list);
1448 break;
1449 case 1:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001450 if (wcd9xxx_rx_vport_validation(port_id +
1451 SITAR_RX_PORT_START_NUMBER,
1452 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
1453 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1454 __func__, port_id + 1);
1455 goto rtn;
1456 }
Kuirong Wang906ac472012-07-09 12:54:44 -07001457 list_add_tail(&core->rx_chs[port_id].list,
1458 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
1459 break;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001460 break;
Kuirong Wang906ac472012-07-09 12:54:44 -07001461 default:
1462 pr_err("Unknown AIF %d\n", widget->value);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001463 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001464 }
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001465
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001466rtn:
Kuirong Wang906ac472012-07-09 12:54:44 -07001467 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
1468 mutex_unlock(&codec->mutex);
1469 return 0;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001470err:
1471 mutex_unlock(&codec->mutex);
1472 return -EINVAL;
Kuirong Wang906ac472012-07-09 12:54:44 -07001473}
1474
1475static const struct soc_enum slim_rx_mux_enum =
1476 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1477
1478static const struct snd_kcontrol_new sitar_aif_pb_mux[SITAR_RX_MAX] = {
1479 SOC_DAPM_ENUM_EXT("SLIM RX1 MUX", slim_rx_mux_enum,
1480 slim_rx_mux_get, slim_rx_mux_put),
1481 SOC_DAPM_ENUM_EXT("SLIM RX2 MUX", slim_rx_mux_enum,
1482 slim_rx_mux_get, slim_rx_mux_put),
1483 SOC_DAPM_ENUM_EXT("SLIM RX3 MUX", slim_rx_mux_enum,
1484 slim_rx_mux_get, slim_rx_mux_put),
1485 SOC_DAPM_ENUM_EXT("SLIM RX4 MUX", slim_rx_mux_enum,
1486 slim_rx_mux_get, slim_rx_mux_put),
1487 SOC_DAPM_ENUM_EXT("SLIM RX5 MUX", slim_rx_mux_enum,
1488 slim_rx_mux_get, slim_rx_mux_put)
1489};
1490
1491static const struct snd_kcontrol_new sitar_aif_cap_mixer[SITAR_TX_MAX] = {
1492 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, SITAR_TX1, 1, 0,
1493 slim_tx_mixer_get, slim_tx_mixer_put),
1494 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, SITAR_TX2, 1, 0,
1495 slim_tx_mixer_get, slim_tx_mixer_put),
1496 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, SITAR_TX3, 1, 0,
1497 slim_tx_mixer_get, slim_tx_mixer_put),
1498 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, SITAR_TX4, 1, 0,
1499 slim_tx_mixer_get, slim_tx_mixer_put),
1500 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, SITAR_TX5, 1, 0,
1501 slim_tx_mixer_get, slim_tx_mixer_put),
1502};
1503
1504
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301505static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
1506 int enable)
1507{
1508 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1509
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301510 pr_debug("%s %d\n", __func__, enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301511
1512 if (enable) {
1513 sitar->adc_count++;
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001514 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL,
1515 0x02, 0x02);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301516 } else {
1517 sitar->adc_count--;
1518 if (!sitar->adc_count) {
1519 if (!sitar->mbhc_polling_active)
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001520 snd_soc_update_bits(codec,
1521 SITAR_A_CDC_CLK_OTHR_CTL, 0xE0, 0x0);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301522 }
1523 }
1524}
1525
1526static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
1527 struct snd_kcontrol *kcontrol, int event)
1528{
1529 struct snd_soc_codec *codec = w->codec;
1530 u16 adc_reg;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001531 u8 init_bit_shift;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301532
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301533 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301534
1535 if (w->reg == SITAR_A_TX_1_2_EN)
1536 adc_reg = SITAR_A_TX_1_2_TEST_CTL;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001537 else if (w->reg == SITAR_A_TX_3_EN)
1538 adc_reg = SITAR_A_TX_3_TEST_CTL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301539 else {
1540 pr_err("%s: Error, invalid adc register\n", __func__);
1541 return -EINVAL;
1542 }
1543
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001544 if (w->shift == 3)
1545 init_bit_shift = 6;
1546 else if (w->shift == 7)
1547 init_bit_shift = 7;
1548 else {
1549 pr_err("%s: Error, invalid init bit postion adc register\n",
1550 __func__);
1551 return -EINVAL;
1552 }
1553
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301554 switch (event) {
1555 case SND_SOC_DAPM_PRE_PMU:
1556 sitar_codec_enable_adc_block(codec, 1);
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001557 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1558 1 << init_bit_shift);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301559 break;
1560 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001561
1562 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1563
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301564 break;
1565 case SND_SOC_DAPM_POST_PMD:
1566 sitar_codec_enable_adc_block(codec, 0);
1567 break;
1568 }
1569 return 0;
1570}
1571
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001572static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
1573 struct snd_kcontrol *kcontrol, int event)
1574{
1575 struct snd_soc_codec *codec = w->codec;
1576
1577 pr_debug("%s %s %d\n", __func__, w->name, event);
1578
1579 switch (event) {
1580 case SND_SOC_DAPM_PRE_PMU:
1581 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1582 break;
1583
1584 case SND_SOC_DAPM_POST_PMD:
1585 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1586 break;
1587 }
1588 return 0;
1589}
1590
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001591static void sitar_enable_classg(struct snd_soc_codec *codec,
1592 bool enable)
1593{
1594
1595 if (enable) {
1596 snd_soc_update_bits(codec,
1597 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x00);
1598 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x00);
1599 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
1600 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
1601
1602 } else {
1603 snd_soc_update_bits(codec,
1604 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x10);
1605 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x03);
1606 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
1607 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
1608 }
1609}
1610
1611static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
1612{
1613 u8 hph_reg_val = 0;
1614 hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
1615
1616 return (hph_reg_val & 0x30) ? true : false;
1617}
1618
1619static bool sitar_is_line_pa_on(struct snd_soc_codec *codec)
1620{
1621 u8 line_reg_val = 0;
1622 line_reg_val = snd_soc_read(codec, SITAR_A_RX_LINE_CNP_EN);
1623
1624 return (line_reg_val & 0x03) ? true : false;
1625}
1626
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301627static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1628 struct snd_kcontrol *kcontrol, int event)
1629{
1630 struct snd_soc_codec *codec = w->codec;
Kuirong Wang80dedd62012-12-07 19:16:24 +05301631 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301632 u16 lineout_gain_reg;
1633
Kuirong Wang80dedd62012-12-07 19:16:24 +05301634 pr_debug("%s %d %s comp2 enable %d\n", __func__, event, w->name,
1635 sitar->comp_enabled[COMPANDER_2]);
1636
1637 if (sitar->comp_enabled[COMPANDER_2])
1638 goto rtn;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301639
1640 switch (w->shift) {
1641 case 0:
1642 lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
1643 break;
1644 case 1:
1645 lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
1646 break;
1647 default:
1648 pr_err("%s: Error, incorrect lineout register value\n",
1649 __func__);
1650 return -EINVAL;
1651 }
1652
1653 switch (event) {
1654 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001655 if (sitar_is_hph_pa_on(codec)) {
1656 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1657 0x20, 0x00);
1658 sitar_enable_classg(codec, false);
1659 } else {
1660 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1661 0x20, 0x20);
1662 sitar_enable_classg(codec, true);
1663 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001664 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301665 break;
1666 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001667 pr_debug("%s: sleeping 32 ms after %s PA turn on\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301668 __func__, w->name);
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001669 usleep_range(32000, 32000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301670 break;
1671 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001672 if (sitar_is_hph_pa_on(codec))
1673 sitar_enable_classg(codec, true);
1674 else
1675 sitar_enable_classg(codec, false);
1676
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001677 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301678 break;
1679 }
Kuirong Wang80dedd62012-12-07 19:16:24 +05301680rtn:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301681 return 0;
1682}
1683
1684static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1685 struct snd_kcontrol *kcontrol, int event)
1686{
1687 struct snd_soc_codec *codec = w->codec;
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301688 u16 tx_dmic_ctl_reg;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301689 u8 dmic_clk_sel, dmic_clk_en;
1690 unsigned int dmic;
1691 int ret;
1692
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001693 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301694 if (ret < 0) {
1695 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1696 return -EINVAL;
1697 }
1698
1699 switch (dmic) {
1700 case 1:
1701 case 2:
1702 dmic_clk_sel = 0x02;
1703 dmic_clk_en = 0x01;
1704 break;
1705 case 3:
1706 case 4:
1707 dmic_clk_sel = 0x08;
1708 dmic_clk_en = 0x04;
1709 break;
1710
1711 break;
1712
1713 default:
1714 pr_err("%s: Invalid DMIC Selection\n", __func__);
1715 return -EINVAL;
1716 }
1717
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301718 tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1719
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301720 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301721
1722 switch (event) {
1723 case SND_SOC_DAPM_PRE_PMU:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301724 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1725 dmic_clk_sel, dmic_clk_sel);
1726
1727 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1728
1729 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1730 dmic_clk_en, dmic_clk_en);
1731 break;
1732 case SND_SOC_DAPM_POST_PMD:
1733 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1734 dmic_clk_en, 0);
1735 break;
1736 }
1737 return 0;
1738}
1739
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001740static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
1741 struct snd_kcontrol *kcontrol, int event)
1742{
1743 struct snd_soc_codec *codec = w->codec;
1744 const char *filename;
1745 const struct firmware *fw;
1746 int i;
1747 int ret;
1748 int num_anc_slots;
1749 struct anc_header *anc_head;
1750 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1751 u32 anc_writes_size = 0;
1752 int anc_size_remaining;
1753 u32 *anc_ptr;
1754 u16 reg;
1755 u8 mask, val, old_val;
1756
1757 pr_debug("%s %d\n", __func__, event);
1758 switch (event) {
1759 case SND_SOC_DAPM_PRE_PMU:
1760
1761 /* Use the same firmware file as that of WCD9310,
1762 * since the register sequences are same for
1763 * WCD9310 and WCD9304
1764 */
1765 filename = "wcd9310/wcd9310_anc.bin";
1766
1767 ret = request_firmware(&fw, filename, codec->dev);
1768 if (ret != 0) {
1769 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1770 ret);
1771 return -ENODEV;
1772 }
1773
1774 if (fw->size < sizeof(struct anc_header)) {
1775 dev_err(codec->dev, "Not enough data\n");
1776 release_firmware(fw);
1777 return -ENOMEM;
1778 }
1779
1780 /* First number is the number of register writes */
1781 anc_head = (struct anc_header *)(fw->data);
1782 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1783 anc_size_remaining = fw->size - sizeof(struct anc_header);
1784 num_anc_slots = anc_head->num_anc_slots;
1785
1786 if (sitar->anc_slot >= num_anc_slots) {
1787 dev_err(codec->dev, "Invalid ANC slot selected\n");
1788 release_firmware(fw);
1789 return -EINVAL;
1790 }
1791
1792 for (i = 0; i < num_anc_slots; i++) {
1793
1794 if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
1795 dev_err(codec->dev, "Invalid register format\n");
1796 release_firmware(fw);
1797 return -EINVAL;
1798 }
1799 anc_writes_size = (u32)(*anc_ptr);
1800 anc_size_remaining -= sizeof(u32);
1801 anc_ptr += 1;
1802
1803 if (anc_writes_size * SITAR_PACKED_REG_SIZE
1804 > anc_size_remaining) {
1805 dev_err(codec->dev, "Invalid register format\n");
1806 release_firmware(fw);
1807 return -ENOMEM;
1808 }
1809
1810 if (sitar->anc_slot == i)
1811 break;
1812
1813 anc_size_remaining -= (anc_writes_size *
1814 SITAR_PACKED_REG_SIZE);
1815 anc_ptr += anc_writes_size;
1816 }
1817 if (i == num_anc_slots) {
1818 dev_err(codec->dev, "Selected ANC slot not present\n");
1819 release_firmware(fw);
1820 return -ENOMEM;
1821 }
1822
1823 for (i = 0; i < anc_writes_size; i++) {
1824 SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1825 mask, val);
1826 old_val = snd_soc_read(codec, reg);
1827 snd_soc_write(codec, reg, (old_val & ~mask) |
1828 (val & mask));
1829 }
1830
1831 release_firmware(fw);
1832
1833 /* For Sitar, it is required to enable both Feed-forward
1834 * and Feed back clocks to enable ANC
1835 */
1836 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
1837
1838 break;
1839
1840 case SND_SOC_DAPM_POST_PMD:
1841 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1842 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
1843 break;
1844 }
1845 return 0;
1846}
1847
1848
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301849static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
1850{
1851 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001852 int mbhc_state = sitar->mbhc_state;
1853
1854 pr_debug("%s: enter\n", __func__);
1855 if (!sitar->mbhc_polling_active) {
1856 pr_debug("Polling is not active, do not start polling\n");
1857 return;
1858 }
1859 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
1860
1861
1862 if (!sitar->no_mic_headset_override) {
1863 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1864 pr_debug("%s recovering MBHC state macine\n", __func__);
1865 sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
1866 /* set to max button press threshold */
1867 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
1868 0x7F);
1869 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
1870 0xFF);
1871 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
1872 0x7F);
1873 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
1874 0xFF);
1875 /* set to max */
1876 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
1877 0x7F);
1878 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
1879 0xFF);
1880 }
1881 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301882
1883 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001884 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
1885 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1886 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301887}
1888
1889static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
1890{
1891 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1892
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001893 pr_debug("%s: enter\n", __func__);
1894 if (!sitar->mbhc_polling_active) {
1895 pr_debug("polling not active, nothing to pause\n");
1896 return;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301897 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001898
1899 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1900 pr_debug("%s: leave\n", __func__);
1901
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301902}
1903
1904static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1905 int mode)
1906{
1907 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1908 u8 reg_mode_val, cur_mode_val;
1909 bool mbhc_was_polling = false;
1910
1911 if (mode)
1912 reg_mode_val = SITAR_CFILT_FAST_MODE;
1913 else
1914 reg_mode_val = SITAR_CFILT_SLOW_MODE;
1915
1916 cur_mode_val = snd_soc_read(codec,
1917 sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
1918
1919 if (cur_mode_val != reg_mode_val) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001920 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301921 if (sitar->mbhc_polling_active) {
1922 sitar_codec_pause_hs_polling(codec);
1923 mbhc_was_polling = true;
1924 }
1925 snd_soc_update_bits(codec,
1926 sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1927 if (mbhc_was_polling)
1928 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001929 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301930 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301931 cur_mode_val, reg_mode_val);
1932 } else {
1933 pr_err("%s: CFILT Value is already %x\n",
1934 __func__, cur_mode_val);
1935 }
1936}
1937
1938static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1939 u8 cfilt_sel, int inc)
1940{
1941 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1942 u32 *cfilt_cnt_ptr = NULL;
1943 u16 micb_cfilt_reg;
1944
1945 switch (cfilt_sel) {
1946 case SITAR_CFILT1_SEL:
1947 cfilt_cnt_ptr = &sitar->cfilt1_cnt;
1948 micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
1949 break;
1950 case SITAR_CFILT2_SEL:
1951 cfilt_cnt_ptr = &sitar->cfilt2_cnt;
1952 micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
1953 break;
1954 default:
1955 return; /* should not happen */
1956 }
1957
1958 if (inc) {
1959 if (!(*cfilt_cnt_ptr)++) {
1960 /* Switch CFILT to slow mode if MBHC CFILT being used */
1961 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1962 sitar_codec_switch_cfilt_mode(codec, 0);
1963
1964 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1965 }
1966 } else {
1967 /* check if count not zero, decrement
1968 * then check if zero, go ahead disable cfilter
1969 */
1970 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1971 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1972
1973 /* Switch CFILT to fast mode if MBHC CFILT being used */
1974 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1975 sitar_codec_switch_cfilt_mode(codec, 1);
1976 }
1977 }
1978}
1979
1980static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1981{
1982 int rc = -EINVAL;
1983 unsigned min_mv, max_mv;
1984
1985 switch (ldoh_v) {
1986 case SITAR_LDOH_1P95_V:
1987 min_mv = 160;
1988 max_mv = 1800;
1989 break;
1990 case SITAR_LDOH_2P35_V:
1991 min_mv = 200;
1992 max_mv = 2200;
1993 break;
1994 case SITAR_LDOH_2P75_V:
1995 min_mv = 240;
1996 max_mv = 2600;
1997 break;
1998 case SITAR_LDOH_2P85_V:
1999 min_mv = 250;
2000 max_mv = 2700;
2001 break;
2002 default:
2003 goto done;
2004 }
2005
2006 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2007 goto done;
2008
2009 for (rc = 4; rc <= 44; rc++) {
2010 min_mv = max_mv * (rc) / 44;
2011 if (min_mv >= cfilt_mv) {
2012 rc -= 4;
2013 break;
2014 }
2015 }
2016done:
2017 return rc;
2018}
2019
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302020static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2021{
2022 u8 hph_reg_val = 0;
2023 if (left)
2024 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002025 SITAR_A_RX_HPH_L_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302026 else
2027 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002028 SITAR_A_RX_HPH_R_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302029
2030 return (hph_reg_val & 0xC0) ? true : false;
2031}
2032
2033static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
2034 int vddio_switch)
2035{
2036 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2037 int cfilt_k_val;
2038 bool mbhc_was_polling = false;
2039
2040 switch (vddio_switch) {
2041 case 1:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002042 if (sitar->mbhc_micbias_switched == 0 &&
2043 sitar->mbhc_polling_active) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302044
2045 sitar_codec_pause_hs_polling(codec);
2046 /* Enable Mic Bias switch to VDDIO */
2047 sitar->cfilt_k_value = snd_soc_read(codec,
2048 sitar->mbhc_bias_regs.cfilt_val);
2049 cfilt_k_val = sitar_find_k_value(
2050 sitar->pdata->micbias.ldoh_v, 1800);
2051 snd_soc_update_bits(codec,
2052 sitar->mbhc_bias_regs.cfilt_val,
2053 0xFC, (cfilt_k_val << 2));
2054
2055 snd_soc_update_bits(codec,
2056 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
2057 snd_soc_update_bits(codec,
2058 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2059 sitar_codec_start_hs_polling(codec);
2060
2061 sitar->mbhc_micbias_switched = true;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302062 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302063 __func__);
2064 }
2065 break;
2066
2067 case 0:
2068 if (sitar->mbhc_micbias_switched) {
2069 if (sitar->mbhc_polling_active) {
2070 sitar_codec_pause_hs_polling(codec);
2071 mbhc_was_polling = true;
2072 }
2073 /* Disable Mic Bias switch to VDDIO */
2074 if (sitar->cfilt_k_value != 0)
2075 snd_soc_update_bits(codec,
2076 sitar->mbhc_bias_regs.cfilt_val, 0XFC,
2077 sitar->cfilt_k_value);
2078 snd_soc_update_bits(codec,
2079 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2080 snd_soc_update_bits(codec,
2081 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2082
2083 if (mbhc_was_polling)
2084 sitar_codec_start_hs_polling(codec);
2085
2086 sitar->mbhc_micbias_switched = false;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302087 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302088 __func__);
2089 }
2090 break;
2091 }
2092}
2093
2094static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2095 struct snd_kcontrol *kcontrol, int event)
2096{
2097 struct snd_soc_codec *codec = w->codec;
2098 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2099 u16 micb_int_reg;
2100 int micb_line;
2101 u8 cfilt_sel_val = 0;
2102 char *internal1_text = "Internal1";
2103 char *internal2_text = "Internal2";
2104
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302105 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302106 switch (w->reg) {
2107 case SITAR_A_MICB_1_CTL:
2108 micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
2109 cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
2110 micb_line = SITAR_MICBIAS1;
2111 break;
2112 case SITAR_A_MICB_2_CTL:
2113 micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
2114 cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
2115 micb_line = SITAR_MICBIAS2;
2116 break;
2117 default:
2118 pr_err("%s: Error, invalid micbias register\n", __func__);
2119 return -EINVAL;
2120 }
2121
2122 switch (event) {
2123 case SND_SOC_DAPM_PRE_PMU:
2124 /* Decide whether to switch the micbias for MBHC */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002125 if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
2126 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302127 sitar_codec_switch_micbias(codec, 0);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002128 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
2129 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302130
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002131 snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302132 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
2133
2134 if (strnstr(w->name, internal1_text, 30))
2135 snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
2136 else if (strnstr(w->name, internal2_text, 30))
2137 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2138 break;
2139 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002140
2141 usleep_range(20000, 20000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302142 if (sitar->mbhc_polling_active &&
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07002143 sitar->mbhc_cfg.micbias == micb_line) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002144 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302145 sitar_codec_pause_hs_polling(codec);
2146 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002147 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302148 }
2149 break;
2150 case SND_SOC_DAPM_POST_PMD:
2151
2152 if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
2153 && sitar_is_hph_pa_on(codec))
2154 sitar_codec_switch_micbias(codec, 1);
2155
2156 if (strnstr(w->name, internal1_text, 30))
2157 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
2158 else if (strnstr(w->name, internal2_text, 30))
2159 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2160 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
2161 break;
2162 }
2163
2164 return 0;
2165}
2166
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002167static void tx_hpf_corner_freq_callback(struct work_struct *work)
2168{
2169 struct delayed_work *hpf_delayed_work;
2170 struct hpf_work *hpf_work;
2171 struct sitar_priv *sitar;
2172 struct snd_soc_codec *codec;
2173 u16 tx_mux_ctl_reg;
2174 u8 hpf_cut_of_freq;
2175
2176 hpf_delayed_work = to_delayed_work(work);
2177 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2178 sitar = hpf_work->sitar;
2179 codec = hpf_work->sitar->codec;
2180 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2181
2182 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL +
2183 (hpf_work->decimator - 1) * 8;
2184
2185 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2186 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2187
2188 snd_soc_update_bits(codec, tx_mux_ctl_reg,
2189 CUT_OF_FREQ_MASK, hpf_cut_of_freq << 4);
2190}
2191
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302192static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
2193 struct snd_kcontrol *kcontrol, int event)
2194{
2195 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002196 u16 dec_reset_reg, gain_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2197 unsigned int decimator;
2198 char *dec_name = NULL;
2199 char *widget_name = NULL;
2200 char *temp;
2201 int ret = 0;
2202 u8 dec_hpf_cut_of_freq, current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302203
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302204 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302205
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002206 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2207 if (!widget_name)
2208 return -ENOMEM;
2209 temp = widget_name;
2210
2211 dec_name = strsep(&widget_name, " ");
2212 widget_name = temp;
2213 if (!dec_name) {
2214 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2215 ret = -EINVAL;
2216 goto out;
2217 }
2218
2219 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
2220 if (ret < 0) {
2221 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2222 ret = -EINVAL;
2223 goto out;
2224 }
2225
2226 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2227 w->name, dec_name, decimator);
2228
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302229 if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2230 dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
2231 else {
2232 pr_err("%s: Error, incorrect dec\n", __func__);
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002233 ret = EINVAL;
2234 goto out;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302235 }
2236
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002237 tx_vol_ctl_reg = SITAR_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
2238 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2239
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302240 switch (event) {
2241 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002242 /* Enable TX Digital Mute */
2243 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2244
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302245 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2246 1 << w->shift);
2247 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002248
2249 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2250 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq &
2251 CUT_OF_FREQ_MASK) >> 4;
2252
2253 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2254 dec_hpf_cut_of_freq;
2255
2256 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2257 /* Set cut off freq to CF_MIN_3DB_150HZ (0x01) */
2258 snd_soc_update_bits(codec, tx_mux_ctl_reg,
2259 CUT_OF_FREQ_MASK, CF_MIN_3DB_150HZ << 4);
2260 }
2261
2262 /* enable HPF */
2263 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x00);
2264
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302265 break;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002266
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002267 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002268 /* Disable TX Digital Mute */
2269 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2270
2271 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2272 CF_MIN_3DB_150HZ) {
2273 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2274 msecs_to_jiffies(300));
2275 }
2276
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002277 /* Reprogram the digital gain after power up of Decimator */
2278 gain_reg = SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * w->shift);
2279 current_gain = snd_soc_read(codec, gain_reg);
2280 snd_soc_write(codec, gain_reg, current_gain);
2281 break;
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002282
2283 case SND_SOC_DAPM_PRE_PMD:
2284 /* Enable Digital Mute, Cancel possibly scheduled work */
2285 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2286 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2287
2288 break;
2289
2290 case SND_SOC_DAPM_POST_PMD:
2291 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2292 snd_soc_update_bits(codec, tx_mux_ctl_reg, CUT_OF_FREQ_MASK,
2293 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2294 break;
2295
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302296 }
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002297
2298out:
2299 kfree(widget_name);
2300 return ret;
2301
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302302}
2303
2304static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
2305 struct snd_kcontrol *kcontrol, int event)
2306{
2307 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002308 u16 gain_reg;
2309 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302310
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302311 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302312
2313 switch (event) {
2314 case SND_SOC_DAPM_PRE_PMU:
2315 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
2316 1 << w->shift, 1 << w->shift);
2317 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
2318 1 << w->shift, 0x0);
2319 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002320 case SND_SOC_DAPM_POST_PMU:
2321 /* Reprogram gain after power up interpolator */
2322 gain_reg = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * w->shift);
2323 current_gain = snd_soc_read(codec, gain_reg);
2324 snd_soc_write(codec, gain_reg, current_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302325 }
2326 return 0;
2327}
2328
2329static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2330 struct snd_kcontrol *kcontrol, int event)
2331{
2332 switch (event) {
2333 case SND_SOC_DAPM_POST_PMU:
2334 case SND_SOC_DAPM_POST_PMD:
2335 usleep_range(1000, 1000);
2336 pr_debug("LDO_H\n");
2337 break;
2338 }
2339 return 0;
2340}
2341
2342static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
2343{
2344 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2345
2346 if (enable) {
2347 sitar->rx_bias_count++;
2348 if (sitar->rx_bias_count == 1)
2349 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
2350 0x80, 0x80);
2351 } else {
2352 sitar->rx_bias_count--;
2353 if (!sitar->rx_bias_count)
2354 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
2355 0x80, 0x00);
2356 }
2357}
2358
2359static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2360 struct snd_kcontrol *kcontrol, int event)
2361{
2362 struct snd_soc_codec *codec = w->codec;
2363
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302364 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302365
2366 switch (event) {
2367 case SND_SOC_DAPM_PRE_PMU:
2368 sitar_enable_rx_bias(codec, 1);
2369 break;
2370 case SND_SOC_DAPM_POST_PMD:
2371 sitar_enable_rx_bias(codec, 0);
2372 break;
2373 }
2374 return 0;
2375}
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002376static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302377 struct snd_kcontrol *kcontrol, int event)
2378{
2379 struct snd_soc_codec *codec = w->codec;
Kuirong Wang80dedd62012-12-07 19:16:24 +05302380 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302381
Kuirong Wang80dedd62012-12-07 19:16:24 +05302382 pr_debug("%s %s %d comp#1 enable %d\n", __func__,
2383 w->name, event, sitar->comp_enabled[COMPANDER_1]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302384
2385 switch (event) {
2386 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002387 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
Kuirong Wang80dedd62012-12-07 19:16:24 +05302388 if (!sitar->comp_enabled[COMPANDER_1]) {
2389 snd_soc_update_bits(codec,
2390 SITAR_A_CDC_CONN_CLSG_CTL,
2391 0x30, 0x20);
2392 snd_soc_update_bits(codec,
2393 SITAR_A_CDC_CONN_CLSG_CTL,
2394 0x0C, 0x08);
2395 }
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002396 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302397 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2398 break;
2399 case SND_SOC_DAPM_POST_PMD:
2400 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002401 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
2402 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2403 0x30, 0x10);
2404 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
2405 0x0C, 0x04);
2406 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302407 break;
2408 }
2409 return 0;
2410}
2411
2412static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
2413 struct snd_soc_jack *jack, int status,
2414 int mask)
2415{
2416 /* XXX: wake_lock_timeout()? */
Laxminath Kasamc24dc6f2012-12-07 11:10:35 +05302417 snd_soc_jack_report_no_dapm(jack, status, mask);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302418}
2419
2420static void hphocp_off_report(struct sitar_priv *sitar,
2421 u32 jack_status, int irq)
2422{
2423 struct snd_soc_codec *codec;
2424
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002425 if (!sitar) {
2426 pr_err("%s: Bad sitar private data\n", __func__);
2427 return;
2428 }
2429
2430 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
2431 codec = sitar->codec;
2432 if (sitar->hph_status & jack_status) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302433 sitar->hph_status &= ~jack_status;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002434 if (sitar->mbhc_cfg.headset_jack)
2435 sitar_snd_soc_jack_report(sitar,
2436 sitar->mbhc_cfg.headset_jack,
2437 sitar->hph_status,
2438 SITAR_JACK_MASK);
2439 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2440 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302441 /* reset retry counter as PA is turned off signifying
2442 * start of new OCP detection session
2443 */
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002444 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302445 sitar->hphlocp_cnt = 0;
2446 else
2447 sitar->hphrocp_cnt = 0;
2448 wcd9xxx_enable_irq(codec->control_data, irq);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302449 }
2450}
2451
2452static void hphlocp_off_report(struct work_struct *work)
2453{
2454 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
2455 hphlocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002456 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
2457 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302458}
2459
2460static void hphrocp_off_report(struct work_struct *work)
2461{
2462 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
2463 hphrocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07002464 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
2465 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302466}
2467
2468static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
2469 struct snd_kcontrol *kcontrol, int event)
2470{
2471 struct snd_soc_codec *codec = w->codec;
2472 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2473 u8 mbhc_micb_ctl_val;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302474 pr_debug("%s: event = %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302475
2476 switch (event) {
2477 case SND_SOC_DAPM_PRE_PMU:
2478 mbhc_micb_ctl_val = snd_soc_read(codec,
2479 sitar->mbhc_bias_regs.ctl_reg);
2480
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002481 if (!(mbhc_micb_ctl_val & 0x80)) {
2482 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302483 sitar_codec_switch_micbias(codec, 1);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002484 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
2485 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302486
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002487 if (sitar_is_line_pa_on(codec))
2488 sitar_enable_classg(codec, false);
2489 else
2490 sitar_enable_classg(codec, true);
2491
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302492 break;
2493
2494 case SND_SOC_DAPM_POST_PMD:
2495 /* schedule work is required because at the time HPH PA DAPM
2496 * event callback is called by DAPM framework, CODEC dapm mutex
2497 * would have been locked while snd_soc_jack_report also
2498 * attempts to acquire same lock.
2499 */
2500 if (w->shift == 5) {
2501 clear_bit(SITAR_HPHL_PA_OFF_ACK,
2502 &sitar->hph_pa_dac_state);
2503 clear_bit(SITAR_HPHL_DAC_OFF_ACK,
2504 &sitar->hph_pa_dac_state);
2505 if (sitar->hph_status & SND_JACK_OC_HPHL)
2506 schedule_work(&sitar->hphlocp_work);
2507 } else if (w->shift == 4) {
2508 clear_bit(SITAR_HPHR_PA_OFF_ACK,
2509 &sitar->hph_pa_dac_state);
2510 clear_bit(SITAR_HPHR_DAC_OFF_ACK,
2511 &sitar->hph_pa_dac_state);
2512 if (sitar->hph_status & SND_JACK_OC_HPHR)
2513 schedule_work(&sitar->hphrocp_work);
2514 }
2515
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002516 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
2517 sitar_codec_switch_micbias(codec, 0);
2518 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302519
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302520 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302521 w->name);
2522 usleep_range(10000, 10000);
2523
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002524 if (sitar_is_line_pa_on(codec))
2525 sitar_enable_classg(codec, true);
2526 else
2527 sitar_enable_classg(codec, false);
2528
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302529 break;
2530 }
2531 return 0;
2532}
2533
2534static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
2535 struct mbhc_micbias_regs *micbias_regs)
2536{
2537 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302538 unsigned int cfilt;
2539
Patrick Laia5062da2012-05-11 17:55:09 -07002540 switch (sitar->mbhc_cfg.micbias) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302541 case SITAR_MICBIAS1:
2542 cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
2543 micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
2544 micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
2545 micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
2546 break;
2547 case SITAR_MICBIAS2:
2548 cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
2549 micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
2550 micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
2551 micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
2552 break;
2553 default:
2554 /* Should never reach here */
2555 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
2556 return;
2557 }
2558
2559 micbias_regs->cfilt_sel = cfilt;
2560
2561 switch (cfilt) {
2562 case SITAR_CFILT1_SEL:
2563 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
2564 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002565 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302566 break;
2567 case SITAR_CFILT2_SEL:
2568 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
2569 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002570 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302571 break;
2572 }
2573}
2574
2575static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
2576 struct snd_kcontrol *kcontrol, int event)
2577{
2578 struct snd_soc_codec *codec = w->codec;
2579
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302580 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302581 switch (event) {
2582 case SND_SOC_DAPM_POST_PMU:
2583 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2584 0x01);
2585 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
2586 usleep_range(200, 200);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302587 break;
2588 case SND_SOC_DAPM_PRE_PMD:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302589 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002590 /*
2591 * This delay is for the class G controller to settle down
2592 * after turn OFF. The delay is as per the hardware spec for
2593 * the codec
2594 */
2595 usleep_range(20, 20);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302596 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2597 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302598 break;
2599 }
2600 return 0;
2601}
2602
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002603static int sitar_ear_pa_event(struct snd_soc_dapm_widget *w,
2604 struct snd_kcontrol *kcontrol, int event)
2605{
2606 switch (event) {
2607 case SND_SOC_DAPM_POST_PMU:
2608 pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
2609 __func__);
2610 msleep(20);
2611 break;
2612 case SND_SOC_DAPM_POST_PMD:
2613 pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
2614 __func__);
2615 msleep(20);
2616 break;
2617 }
2618 return 0;
2619}
2620
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302621static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
2622 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
2623 4, 0, NULL, 0),
2624 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
2625 0, NULL, 0),
2626};
2627
2628static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
2629 /*RX stuff */
2630 SND_SOC_DAPM_OUTPUT("EAR"),
2631
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002632 SND_SOC_DAPM_PGA_E("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0,
2633 sitar_ear_pa_event, SND_SOC_DAPM_POST_PMU |
2634 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302635 SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
2636 ARRAY_SIZE(dac1_switch)),
2637 SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07002638
2639 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
2640 AIF1_PB, 0, sitar_codec_enable_slimrx,
2641 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2642
2643 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, SITAR_RX1, 0,
2644 &sitar_aif_pb_mux[SITAR_RX1]),
2645 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, SITAR_RX2, 0,
2646 &sitar_aif_pb_mux[SITAR_RX2]),
2647 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, SITAR_RX3, 0,
2648 &sitar_aif_pb_mux[SITAR_RX3]),
2649 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, SITAR_RX4, 0,
2650 &sitar_aif_pb_mux[SITAR_RX4]),
2651 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, SITAR_RX5, 0,
2652 &sitar_aif_pb_mux[SITAR_RX5]),
2653
2654 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2655 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
2656 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
2657 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
2658 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302659
2660 /* Headphone */
2661 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2662 SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
2663 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2664 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302665
2666 SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
2667 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2668 SND_SOC_DAPM_POST_PMD),
2669
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002670 SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
2671 sitar_hph_dac_event,
2672 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302673 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002674 sitar_hph_dac_event,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302675 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2676
2677 /* Speaker */
2678 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
2679 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
2680
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002681 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
2682 , sitar_lineout_dac_event,
2683 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2684 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
2685 , sitar_lineout_dac_event,
2686 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2687
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302688 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
2689 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2690 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2691 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
2692 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2693 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2694
2695 SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002696 0, sitar_codec_reset_interpolator,
2697 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302698 SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002699 0, sitar_codec_reset_interpolator,
2700 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302701 SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002702 0, sitar_codec_reset_interpolator,
2703 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302704
2705 SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
2706 &rx_dac1_mux),
2707 SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
2708 &rx_dac2_mux),
2709 SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
2710 &rx_dac3_mux),
2711 SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
2712 &rx_dac4_mux),
2713
Kuirong Wang80dedd62012-12-07 19:16:24 +05302714 SND_SOC_DAPM_MIXER_E("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL,
2715 0, sitar_codec_dem_input_selection,
2716 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
2717 SND_SOC_DAPM_MIXER_E("RX2 CHAIN", SND_SOC_NOPM, 1, 0, NULL,
2718 0, sitar_codec_dem_input_selection,
2719 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
2720 SND_SOC_DAPM_MIXER_E("RX3 CHAIN", SND_SOC_NOPM, 2, 0, NULL,
2721 0, sitar_codec_dem_input_selection,
2722 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302723
2724 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2725 &rx_mix1_inp1_mux),
2726 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2727 &rx_mix1_inp2_mux),
2728 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2729 &rx2_mix1_inp1_mux),
2730 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2731 &rx2_mix1_inp2_mux),
2732 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2733 &rx3_mix1_inp1_mux),
2734 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2735 &rx3_mix1_inp2_mux),
2736
2737 SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
2738 sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2739 SND_SOC_DAPM_PRE_PMD),
2740 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2741 sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2742 SND_SOC_DAPM_POST_PMD),
2743
2744 SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
2745 sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2746 /* TX */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002747
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302748 SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2749 0),
2750 SND_SOC_DAPM_INPUT("AMIC1"),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002751 SND_SOC_DAPM_INPUT("AMIC2"),
2752 SND_SOC_DAPM_INPUT("AMIC3"),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302753 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
2754 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2755 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2756 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
2757 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2758 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2759
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302760 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
2761 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2762 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2763 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
2764 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2765 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2766 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
2767 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2768 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2769
2770 SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
2771 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2772 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2773 SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
2774 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2775 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002776 SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
2777 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2778 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302779
2780 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 -07002781 &dec1_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002782 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2783 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2784
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002785 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 -07002786 &dec2_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002787 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2788 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2789
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002790 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 -07002791 &dec3_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002792 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2793 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2794
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002795 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 -07002796 &dec4_mux, sitar_codec_enable_dec,
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07002797 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2798 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302799
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002800 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2801 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2802
2803 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2804 sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2805 SND_SOC_DAPM_POST_PMD),
2806
2807 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2808
Kuirong Wang906ac472012-07-09 12:54:44 -07002809 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
2810 AIF1_CAP, 0, sitar_codec_enable_slimtx,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302811 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2812
Kuirong Wang906ac472012-07-09 12:54:44 -07002813 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
2814 sitar_aif_cap_mixer, ARRAY_SIZE(sitar_aif_cap_mixer)),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302815
Kuirong Wang906ac472012-07-09 12:54:44 -07002816 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, SITAR_TX1, 0,
2817 &sb_tx1_mux),
2818 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, SITAR_TX2, 0,
2819 &sb_tx2_mux),
2820 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2821 &sb_tx3_mux),
2822 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2823 &sb_tx4_mux),
2824 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2825 &sb_tx5_mux),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302826
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002827 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
2828 0, sitar_codec_enable_slimtx,
2829 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2830
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302831 /* Digital Mic Inputs */
2832 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2833 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2834 SND_SOC_DAPM_POST_PMD),
2835 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2836 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2837 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302838 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2839 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2840 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302841 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2842 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2843 SND_SOC_DAPM_POST_PMD),
2844
Kuirong Wang80dedd62012-12-07 19:16:24 +05302845 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, COMPANDER_1, 0,
2846 sitar_config_compander, SND_SOC_DAPM_PRE_PMU |
2847 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2848 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, COMPANDER_2, 0,
2849 sitar_config_compander, SND_SOC_DAPM_PRE_PMU |
2850 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2851
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302852 /* Sidetone */
2853 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2854 SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302855 SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
2856 SND_SOC_DAPM_PGA("IIR2", SITAR_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302857
2858};
2859
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302860static const struct snd_soc_dapm_route audio_i2s_map[] = {
2861 {"RX_I2S_CLK", NULL, "CP"},
2862 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2863 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2864 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2865 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2866 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2867
2868 {"SLIM TX1", NULL, "TX_I2S_CLK"},
2869 {"SLIM TX2", NULL, "TX_I2S_CLK"},
2870 {"SLIM TX3", NULL, "TX_I2S_CLK"},
2871 {"SLIM TX4", NULL, "TX_I2S_CLK"},
2872};
Kuirong Wang906ac472012-07-09 12:54:44 -07002873#define SLIM_MIXER(x) (\
2874 {x, "SLIM TX1", "SLIM TX1 MUX"}, \
2875 {x, "SLIM TX2", "SLIM TX2 MUX"}, \
2876 {x, "SLIM TX3", "SLIM TX3 MUX"}, \
2877 {x, "SLIM TX4", "SLIM TX4 MUX"})
2878
2879
2880#define SLIM_MUX(x, y) (\
2881 {"SLIM RX1 MUX", x, y}, \
2882 {"SLIM RX2 MUX", x, y}, \
2883 {"SLIM RX3 MUX", x, y}, \
2884 {"SLIM RX4 MUX", x, y})
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302885
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302886static const struct snd_soc_dapm_route audio_map[] = {
2887 /* Earpiece (RX MIX1) */
2888 {"EAR", NULL, "EAR PA"},
2889 {"EAR PA", "NULL", "DAC1"},
2890 {"DAC1", "Switch", "DAC1 MUX"},
2891 {"DAC1", NULL, "CP"},
2892 {"DAC1", NULL, "EAR DRIVER"},
2893
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002894 {"CP", NULL, "RX_BIAS"},
2895
2896 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2897 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302898
2899 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002900 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002901 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2902 {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302903
2904 {"LINEOUT1", NULL, "LINEOUT1 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002905 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002906 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2907 {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
2908
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002909 {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
2910 {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
2911 {"ANC", NULL, "ANC1 FB MUX"},
2912
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302913
2914 /* Headset (RX MIX1 and RX MIX2) */
2915 {"HEADPHONE", NULL, "HPHL"},
2916 {"HEADPHONE", NULL, "HPHR"},
2917
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002918
Patrick Lai9b250b72012-05-24 14:45:57 -07002919 {"HPHL DAC", NULL, "CP"},
2920 {"HPHR DAC", NULL, "CP"},
2921
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302922 {"HPHL", NULL, "HPHL DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002923 {"HPHL DAC", "NULL", "RX2 CHAIN"},
2924 {"RX2 CHAIN", NULL, "DAC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302925 {"HPHR", NULL, "HPHR DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002926 {"HPHR DAC", NULL, "RX3 CHAIN"},
2927 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302928
2929 {"DAC1 MUX", "RX1", "RX1 CHAIN"},
2930 {"DAC2 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002931
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302932 {"DAC3 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002933 {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302934 {"DAC3 MUX", "RX2", "RX2 MIX1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002935
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302936 {"DAC4 MUX", "ON", "RX2 MIX1"},
2937
2938 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2939
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302940 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2941 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2942 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2943 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2944 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2945 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2946
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002947 /* ANC */
2948 {"ANC", NULL, "ANC1 MUX"},
2949 {"ANC", NULL, "ANC2 MUX"},
2950 {"ANC1 MUX", "ADC1", "ADC1"},
2951 {"ANC1 MUX", "ADC2", "ADC2"},
2952 {"ANC1 MUX", "ADC3", "ADC3"},
2953 {"ANC2 MUX", "ADC1", "ADC1"},
2954 {"ANC2 MUX", "ADC2", "ADC2"},
2955 {"ANC2 MUX", "ADC3", "ADC3"},
2956
2957 {"ANC", NULL, "CDC_CONN"},
2958
2959 {"RX2 MIX1", NULL, "ANC"},
2960 {"RX3 MIX1", NULL, "ANC"},
2961
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302962 /* SLIMBUS Connections */
Kuirong Wang906ac472012-07-09 12:54:44 -07002963 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2964
2965 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2966 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2967 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2968 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2969 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2970 /* SLIM_MUX("AIF1_PB", "AIF1 PB"), */
2971 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2972 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2973 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2974 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2975
2976 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2977 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2978 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2979 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302980
Kuirong Wang80dedd62012-12-07 19:16:24 +05302981 {"RX1 MIX1", NULL, "COMP2_CLK"},
2982 {"RX2 MIX1", NULL, "COMP1_CLK"},
2983 {"RX3 MIX1", NULL, "COMP1_CLK"},
2984
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302985 /* Slimbus port 5 is non functional in Sitar 1.0 */
2986 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2987 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2988 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2989 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2990 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302991 {"RX1 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302992 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2993 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2994 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2995 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2996 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302997 {"RX1 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302998 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2999 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
3000 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3001 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
3002 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303003 {"RX2 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303004 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3005 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
3006 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3007 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
3008 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303009 {"RX2 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303010 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3011 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
3012 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3013 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
3014 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303015 {"RX3 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303016 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3017 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
3018 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3019 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
3020 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303021 {"RX3 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303022
3023
3024 /* TX */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303025 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
3026 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
3027 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003028 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07003029 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
3030 {"SLIM TX5 MUX", "DEC2", "DEC2 MUX"},
3031 {"SLIM TX5 MUX", "DEC3", "DEC3 MUX"},
3032 {"SLIM TX5 MUX", "DEC4", "DEC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303033
3034 /* Decimator Inputs */
3035 {"DEC1 MUX", "DMIC1", "DMIC1"},
3036 {"DEC1 MUX", "DMIC4", "DMIC4"},
3037 {"DEC1 MUX", "ADC1", "ADC1"},
3038 {"DEC1 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003039 {"DEC1 MUX", "ADC3", "ADC3"},
3040 {"DEC1 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303041 {"DEC2 MUX", "DMIC2", "DMIC2"},
3042 {"DEC2 MUX", "DMIC3", "DMIC3"},
3043 {"DEC2 MUX", "ADC1", "ADC1"},
3044 {"DEC2 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003045 {"DEC2 MUX", "ADC3", "ADC3"},
3046 {"DEC2 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303047 {"DEC3 MUX", "DMIC3", "DMIC3"},
3048 {"DEC3 MUX", "ADC1", "ADC1"},
3049 {"DEC3 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003050 {"DEC3 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303051 {"DEC3 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07003052 {"DEC3 MUX", "DMIC4", "DMIC4"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003053 {"DEC3 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303054 {"DEC4 MUX", "DMIC4", "DMIC4"},
3055 {"DEC4 MUX", "ADC1", "ADC1"},
3056 {"DEC4 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003057 {"DEC4 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303058 {"DEC4 MUX", "DMIC3", "DMIC3"},
3059 {"DEC4 MUX", "DMIC2", "DMIC2"},
3060 {"DEC4 MUX", "DMIC1", "DMIC1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003061 {"DEC4 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303062
3063 /* ADC Connections */
3064 {"ADC1", NULL, "AMIC1"},
3065 {"ADC2", NULL, "AMIC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003066 {"ADC3", NULL, "AMIC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303067
3068 /* IIR */
3069 {"IIR1", NULL, "IIR1 INP1 MUX"},
3070 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05303071 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3072 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3073 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3074 {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
3075 {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
3076 {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
3077 {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
3078 {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
3079
3080 {"IIR2", NULL, "IIR2 INP1 MUX"},
3081 {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
3082 {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
3083 {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
3084 {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
3085 {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
3086 {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
3087 {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
3088 {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
3089 {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
3090
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303091 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3092 {"MIC BIAS1 External", NULL, "LDO_H"},
3093 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3094 {"MIC BIAS2 External", NULL, "LDO_H"},
3095};
3096
3097static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
3098{
3099 return sitar_reg_readable[reg];
3100}
3101
3102static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3103{
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07003104 int i;
3105
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303106 /* Registers lower than 0x100 are top level registers which can be
3107 * written by the Sitar core driver.
3108 */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303109 if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3110 return 1;
3111
3112 /* IIR Coeff registers are not cacheable */
3113 if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
3114 (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
3115 return 1;
3116
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07003117 for (i = 0; i < NUM_DECIMATORS; i++) {
3118 if (reg == SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * i))
3119 return 1;
3120 }
3121
3122 for (i = 0; i < NUM_INTERPOLATORS; i++) {
3123 if (reg == SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * i))
3124 return 1;
3125 }
Kuirong Wang80dedd62012-12-07 19:16:24 +05303126
3127 if ((reg == SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS) ||
3128 (reg == SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS))
3129 return 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303130 return 0;
3131}
3132
3133#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3134static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
3135 unsigned int value)
3136{
3137 int ret;
3138
Kuirong Wang906ac472012-07-09 12:54:44 -07003139 if (reg == SND_SOC_NOPM)
3140 return 0;
3141
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303142 BUG_ON(reg > SITAR_MAX_REGISTER);
3143
3144 if (!sitar_volatile(codec, reg)) {
3145 ret = snd_soc_cache_write(codec, reg, value);
3146 if (ret != 0)
3147 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3148 reg, ret);
3149 }
3150
3151 return wcd9xxx_reg_write(codec->control_data, reg, value);
3152}
3153static unsigned int sitar_read(struct snd_soc_codec *codec,
3154 unsigned int reg)
3155{
3156 unsigned int val;
3157 int ret;
3158
Kuirong Wang906ac472012-07-09 12:54:44 -07003159 if (reg == SND_SOC_NOPM)
3160 return 0;
3161
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303162 BUG_ON(reg > SITAR_MAX_REGISTER);
3163
3164 if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
3165 reg < codec->driver->reg_cache_size) {
3166 ret = snd_soc_cache_read(codec, reg, &val);
3167 if (ret >= 0) {
3168 return val;
3169 } else
3170 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3171 reg, ret);
3172 }
3173
3174 val = wcd9xxx_reg_read(codec->control_data, reg);
3175 return val;
3176}
3177
3178static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
3179{
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003180 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303181
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003182 if (SITAR_IS_1P0(sitar_core->version))
3183 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
3184
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003185 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303186 usleep_range(1000, 1000);
3187 snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
3188 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3189 0x80);
3190 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
3191 0x04);
3192 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
3193 0x01);
3194 usleep_range(1000, 1000);
3195 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3196 0x00);
3197}
3198
3199static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
3200 enum sitar_bandgap_type choice)
3201{
3202 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003203 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303204
3205 /* TODO lock resources accessed by audio streams and threaded
3206 * interrupt handlers
3207 */
3208
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303209 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303210 sitar->bandgap_type);
3211
3212 if (sitar->bandgap_type == choice)
3213 return;
3214
3215 if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
3216 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
3217 sitar_codec_enable_audio_mode_bandgap(codec);
3218 } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
Bhalchandra Gajare7708ee32012-05-24 17:37:37 -07003219 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303220 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
3221 0x2);
3222 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3223 0x80);
3224 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
3225 0x4);
3226 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
3227 0x1);
3228 usleep_range(1000, 1000);
3229 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
3230 0x00);
3231 } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
3232 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
3233 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
3234 usleep_range(100, 100);
3235 sitar_codec_enable_audio_mode_bandgap(codec);
3236 } else if (choice == SITAR_BANDGAP_OFF) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003237 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303238 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07003239 if (SITAR_IS_1P0(sitar_core->version))
3240 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
Asish Bhattacharya63032b42012-08-16 20:57:01 +05303241 0xF3, 0x61);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003242 usleep_range(1000, 1000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303243 } else {
3244 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
3245 }
3246 sitar->bandgap_type = choice;
3247}
3248
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003249static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
3250 int enable)
3251{
3252 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3253
3254 if (enable) {
3255 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
3256 snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
3257 usleep_range(5, 5);
3258 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
3259 0x80);
3260 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
3261 0x80);
3262 usleep_range(10, 10);
3263 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
3264 usleep_range(20, 20);
3265 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
3266 } else {
3267 snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
3268 0);
3269 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
3270 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
3271 }
3272 sitar->config_mode_active = enable ? true : false;
3273
3274 return 0;
3275}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303276
3277static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
3278 int config_mode)
3279{
3280 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3281
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303282 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303283
3284 if (config_mode) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003285 sitar_codec_enable_config_mode(codec, 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303286 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
3287 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
3288 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
3289 usleep_range(1000, 1000);
3290 } else
3291 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
3292
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003293 if (!config_mode && sitar->mbhc_polling_active) {
3294 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
3295 sitar_codec_enable_config_mode(codec, 0);
3296
3297 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303298
3299 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
3300 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
3301 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303302 usleep_range(50, 50);
3303 sitar->clock_active = true;
3304 return 0;
3305}
3306static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
3307{
3308 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303309 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303310 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
3311 ndelay(160);
3312 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
3313 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
3314 sitar->clock_active = false;
3315}
3316
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003317static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
3318{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003319 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003320 return 0;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003321 else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003322 return 1;
3323 else {
3324 BUG_ON(1);
3325 return -EINVAL;
3326 }
3327}
3328
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303329static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3330{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003331 u8 *n_ready, *n_cic;
3332 struct sitar_mbhc_btn_detect_cfg *btn_det;
3333 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303334
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003335 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303336
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003337 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
3338 sitar->mbhc_data.v_ins_hu & 0xFF);
3339 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
3340 (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303341
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003342 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
3343 sitar->mbhc_data.v_b1_hu & 0xFF);
3344 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
3345 (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
3346
3347 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
3348 sitar->mbhc_data.v_b1_h & 0xFF);
3349 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
3350 (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
3351
3352 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
3353 sitar->mbhc_data.v_brh & 0xFF);
3354 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
3355 (sitar->mbhc_data.v_brh >> 8) & 0xFF);
3356
3357 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
3358 sitar->mbhc_data.v_brl & 0xFF);
3359 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
3360 (sitar->mbhc_data.v_brl >> 8) & 0xFF);
3361
3362 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
3363 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
3364 n_ready[sitar_codec_mclk_index(sitar)]);
3365 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
3366 sitar->mbhc_data.npoll);
3367 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
3368 sitar->mbhc_data.nbounce_wait);
3369 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3370 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
3371 n_cic[sitar_codec_mclk_index(sitar)]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303372}
3373
3374static int sitar_startup(struct snd_pcm_substream *substream,
3375 struct snd_soc_dai *dai)
3376{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08003377 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
3378 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
3379 (wcd9xxx->dev->parent != NULL))
3380 pm_runtime_get_sync(wcd9xxx->dev->parent);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303381 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303382 substream->name, substream->stream);
3383
3384 return 0;
3385}
3386
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003387static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
3388{
3389 if (sitar->dev != NULL &&
3390 sitar->dev->parent != NULL) {
3391 pm_runtime_mark_last_busy(sitar->dev->parent);
3392 pm_runtime_put(sitar->dev->parent);
3393 }
3394}
3395
3396static void sitar_shutdown(struct snd_pcm_substream *substream,
3397 struct snd_soc_dai *dai)
3398{
3399 struct wcd9xxx *sitar_core = dev_get_drvdata(dai->codec->dev->parent);
3400 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3401 u32 active = 0;
3402
3403 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3404 substream->name, substream->stream);
3405 if (sitar->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3406 return;
3407
3408 if (dai->id <= NUM_CODEC_DAIS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003409 if (sitar->dai[dai->id].ch_mask) {
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003410 active = 1;
Joonwoo Park9bbb4d12012-11-09 19:58:11 -08003411 pr_debug("%s(): Codec DAI: chmask[%d] = 0x%lx\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003412 __func__, dai->id,
3413 sitar->dai[dai->id].ch_mask);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003414 }
3415 }
3416
3417 if (sitar_core != NULL && active == 0)
3418 sitar_codec_pm_runtime_put(sitar_core);
3419}
3420
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003421int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303422{
3423 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3424
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303425 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303426
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003427 if (dapm)
3428 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303429 if (mclk_enable) {
3430 sitar->mclk_enabled = true;
3431
3432 if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
3433 sitar_codec_pause_hs_polling(codec);
3434 sitar_codec_enable_bandgap(codec,
3435 SITAR_BANDGAP_AUDIO_MODE);
3436 sitar_codec_enable_clock_block(codec, 0);
3437 sitar_codec_calibrate_hs_polling(codec);
3438 sitar_codec_start_hs_polling(codec);
3439 } else {
3440 sitar_codec_enable_bandgap(codec,
3441 SITAR_BANDGAP_AUDIO_MODE);
3442 sitar_codec_enable_clock_block(codec, 0);
3443 }
3444 } else {
3445
3446 if (!sitar->mclk_enabled) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003447 if (dapm)
3448 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303449 pr_err("Error, MCLK already diabled\n");
3450 return -EINVAL;
3451 }
3452 sitar->mclk_enabled = false;
3453
3454 if (sitar->mbhc_polling_active) {
3455 if (!sitar->mclk_enabled) {
3456 sitar_codec_pause_hs_polling(codec);
3457 sitar_codec_enable_bandgap(codec,
3458 SITAR_BANDGAP_MBHC_MODE);
3459 sitar_enable_rx_bias(codec, 1);
3460 sitar_codec_enable_clock_block(codec, 1);
3461 sitar_codec_calibrate_hs_polling(codec);
3462 sitar_codec_start_hs_polling(codec);
3463 }
3464 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
3465 0x05, 0x01);
3466 } else {
3467 sitar_codec_disable_clock_block(codec);
3468 sitar_codec_enable_bandgap(codec,
3469 SITAR_BANDGAP_OFF);
3470 }
3471 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003472 if (dapm)
3473 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303474 return 0;
3475}
3476
3477static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
3478 int clk_id, unsigned int freq, int dir)
3479{
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303480 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303481 return 0;
3482}
3483
3484static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3485{
3486 u8 val = 0;
3487 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3488
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303489 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303490 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3491 case SND_SOC_DAIFMT_CBS_CFS:
3492 /* CPU is master */
3493 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3494 if (dai->id == AIF1_CAP)
3495 snd_soc_update_bits(dai->codec,
3496 SITAR_A_CDC_CLK_TX_I2S_CTL,
3497 SITAR_I2S_MASTER_MODE_MASK, 0);
3498 else if (dai->id == AIF1_PB)
3499 snd_soc_update_bits(dai->codec,
3500 SITAR_A_CDC_CLK_RX_I2S_CTL,
3501 SITAR_I2S_MASTER_MODE_MASK, 0);
3502 }
3503 break;
3504 case SND_SOC_DAIFMT_CBM_CFM:
3505 /* CPU is slave */
3506 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3507 val = SITAR_I2S_MASTER_MODE_MASK;
3508 if (dai->id == AIF1_CAP)
3509 snd_soc_update_bits(dai->codec,
3510 SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
3511 else if (dai->id == AIF1_PB)
3512 snd_soc_update_bits(dai->codec,
3513 SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
3514 }
3515 break;
3516 default:
3517 return -EINVAL;
3518 }
3519 return 0;
3520}
3521static int sitar_set_channel_map(struct snd_soc_dai *dai,
3522 unsigned int tx_num, unsigned int *tx_slot,
3523 unsigned int rx_num, unsigned int *rx_slot)
3524
3525{
3526 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003527 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303528 if (!tx_slot && !rx_slot) {
3529 pr_err("%s: Invalid\n", __func__);
3530 return -EINVAL;
3531 }
3532 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3533
Kuirong Wang906ac472012-07-09 12:54:44 -07003534 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3535 wcd9xxx_init_slimslave(core, core->slim->laddr,
3536 tx_num, tx_slot, rx_num, rx_slot);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303537 return 0;
3538}
3539
3540static int sitar_get_channel_map(struct snd_soc_dai *dai,
3541 unsigned int *tx_num, unsigned int *tx_slot,
3542 unsigned int *rx_num, unsigned int *rx_slot)
3543
3544{
Kuirong Wang906ac472012-07-09 12:54:44 -07003545 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(dai->codec);
3546 u32 i = 0;
3547 struct wcd9xxx_ch *ch;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303548
Kuirong Wang906ac472012-07-09 12:54:44 -07003549 switch (dai->id) {
3550 case AIF1_PB:
3551 if (!rx_slot || !rx_num) {
3552 pr_err("%s: Invalid rx_slot 0x%x or rx_num 0x%x\n",
3553 __func__, (u32) rx_slot, (u32) rx_num);
3554 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303555 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003556 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3557 list) {
3558 rx_slot[i++] = ch->ch_num;
3559 }
3560 *rx_num = i;
3561 break;
3562 case AIF1_CAP:
3563 if (!tx_slot || !tx_num) {
3564 pr_err("%s: Invalid tx_slot 0x%x or tx_num 0x%x\n",
3565 __func__, (u32) tx_slot, (u32) tx_num);
3566 return -EINVAL;
3567 }
3568 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3569 list) {
3570 tx_slot[i++] = ch->ch_num;
3571 }
3572 *tx_num = i;
3573 break;
3574 default:
3575 pr_err("%s: Invalid dai %d", __func__, dai->id);
3576 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303577 }
3578 return 0;
3579}
3580
3581static int sitar_hw_params(struct snd_pcm_substream *substream,
3582 struct snd_pcm_hw_params *params,
3583 struct snd_soc_dai *dai)
3584{
3585 struct snd_soc_codec *codec = dai->codec;
3586 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3587 u8 path, shift;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303588 u32 compander_fs;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303589 u16 tx_fs_reg, rx_fs_reg;
3590 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
3591
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303592 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303593
3594 switch (params_rate(params)) {
3595 case 8000:
3596 tx_fs_rate = 0x00;
3597 rx_fs_rate = 0x00;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303598 compander_fs = COMPANDER_FS_8KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303599 break;
3600 case 16000:
3601 tx_fs_rate = 0x01;
3602 rx_fs_rate = 0x20;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303603 compander_fs = COMPANDER_FS_16KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303604 break;
3605 case 32000:
3606 tx_fs_rate = 0x02;
3607 rx_fs_rate = 0x40;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303608 compander_fs = COMPANDER_FS_32KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303609 break;
3610 case 48000:
3611 tx_fs_rate = 0x03;
3612 rx_fs_rate = 0x60;
Kuirong Wang80dedd62012-12-07 19:16:24 +05303613 compander_fs = COMPANDER_FS_48KHZ;
3614 break;
3615 case 96000:
3616 tx_fs_rate = 0x04;
3617 rx_fs_rate = 0x80;
3618 compander_fs = COMPANDER_FS_96KHZ;
3619 break;
3620 case 192000:
3621 tx_fs_rate = 0x05;
3622 rx_fs_rate = 0xa0;
3623 compander_fs = COMPANDER_FS_192KHZ;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303624 break;
3625 default:
3626 pr_err("%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07003627 params_rate(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303628 return -EINVAL;
3629 }
3630
3631
3632 /**
3633 * If current dai is a tx dai, set sample rate to
3634 * all the txfe paths that are currently not active
3635 */
3636 if (dai->id == AIF1_CAP) {
3637
3638 tx_state = snd_soc_read(codec,
3639 SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3640
3641 for (path = 1, shift = 0;
3642 path <= NUM_DECIMATORS; path++, shift++) {
3643
3644 if (!(tx_state & (1 << shift))) {
3645 tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
3646 + (BITS_PER_REG*(path-1));
3647 snd_soc_update_bits(codec, tx_fs_reg,
3648 0x03, tx_fs_rate);
3649 }
3650 }
3651 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3652 switch (params_format(params)) {
3653 case SNDRV_PCM_FORMAT_S16_LE:
3654 snd_soc_update_bits(codec,
3655 SITAR_A_CDC_CLK_TX_I2S_CTL,
3656 0x20, 0x20);
3657 break;
3658 case SNDRV_PCM_FORMAT_S32_LE:
3659 snd_soc_update_bits(codec,
3660 SITAR_A_CDC_CLK_TX_I2S_CTL,
3661 0x20, 0x00);
3662 break;
3663 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003664 pr_err("%s: Unsupport format %d\n", __func__,
3665 params_format(params));
3666 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303667 }
3668 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
3669 0x03, tx_fs_rate);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303670 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003671 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303672 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303673 }
3674
3675 /**
3676 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3677 * with varying sample rates
3678 */
3679
3680 /**
3681 * If current dai is a rx dai, set sample rate to
3682 * all the rx paths that are currently not active
3683 */
3684 if (dai->id == AIF1_PB) {
3685
3686 rx_state = snd_soc_read(codec,
3687 SITAR_A_CDC_CLK_RX_B1_CTL);
3688
3689 for (path = 1, shift = 0;
3690 path <= NUM_INTERPOLATORS; path++, shift++) {
3691
3692 if (!(rx_state & (1 << shift))) {
3693 rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
3694 + (BITS_PER_REG*(path-1));
3695 snd_soc_update_bits(codec, rx_fs_reg,
3696 0xE0, rx_fs_rate);
Kuirong Wang80dedd62012-12-07 19:16:24 +05303697 if (comp_rx_path[shift] < COMPANDER_MAX)
3698 sitar->comp_fs[comp_rx_path[shift]]
3699 = compander_fs;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303700 }
3701 }
3702 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3703 switch (params_format(params)) {
3704 case SNDRV_PCM_FORMAT_S16_LE:
3705 snd_soc_update_bits(codec,
3706 SITAR_A_CDC_CLK_RX_I2S_CTL,
3707 0x20, 0x20);
3708 break;
3709 case SNDRV_PCM_FORMAT_S32_LE:
3710 snd_soc_update_bits(codec,
3711 SITAR_A_CDC_CLK_RX_I2S_CTL,
3712 0x20, 0x00);
3713 break;
3714 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003715 pr_err("%s: Unsupport format %d\n", __func__,
3716 params_format(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303717 break;
3718 }
3719 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
3720 0x03, (rx_fs_rate >> 0x05));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303721 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003722 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303723 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303724 }
3725
3726 return 0;
3727}
3728
3729static struct snd_soc_dai_ops sitar_dai_ops = {
3730 .startup = sitar_startup,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003731 .shutdown = sitar_shutdown,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303732 .hw_params = sitar_hw_params,
3733 .set_sysclk = sitar_set_dai_sysclk,
3734 .set_fmt = sitar_set_dai_fmt,
3735 .set_channel_map = sitar_set_channel_map,
3736 .get_channel_map = sitar_get_channel_map,
3737};
3738
3739static struct snd_soc_dai_driver sitar_dai[] = {
3740 {
3741 .name = "sitar_rx1",
3742 .id = AIF1_PB,
3743 .playback = {
3744 .stream_name = "AIF1 Playback",
3745 .rates = WCD9304_RATES,
3746 .formats = SITAR_FORMATS,
3747 .rate_max = 48000,
3748 .rate_min = 8000,
3749 .channels_min = 1,
3750 .channels_max = 2,
3751 },
3752 .ops = &sitar_dai_ops,
3753 },
3754 {
3755 .name = "sitar_tx1",
3756 .id = AIF1_CAP,
3757 .capture = {
3758 .stream_name = "AIF1 Capture",
3759 .rates = WCD9304_RATES,
3760 .formats = SITAR_FORMATS,
3761 .rate_max = 48000,
3762 .rate_min = 8000,
3763 .channels_min = 1,
3764 .channels_max = 2,
3765 },
3766 .ops = &sitar_dai_ops,
3767 },
3768};
3769
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303770static struct snd_soc_dai_driver sitar_i2s_dai[] = {
3771 {
3772 .name = "sitar_i2s_rx1",
3773 .id = AIF1_PB,
3774 .playback = {
3775 .stream_name = "AIF1 Playback",
3776 .rates = WCD9304_RATES,
3777 .formats = SITAR_FORMATS,
3778 .rate_max = 192000,
3779 .rate_min = 8000,
3780 .channels_min = 1,
3781 .channels_max = 4,
3782 },
3783 .ops = &sitar_dai_ops,
3784 },
3785 {
3786 .name = "sitar_i2s_tx1",
3787 .id = AIF1_CAP,
3788 .capture = {
3789 .stream_name = "AIF1 Capture",
3790 .rates = WCD9304_RATES,
3791 .formats = SITAR_FORMATS,
3792 .rate_max = 192000,
3793 .rate_min = 8000,
3794 .channels_min = 1,
3795 .channels_max = 4,
3796 },
3797 .ops = &sitar_dai_ops,
3798 },
3799};
3800
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003801static int sitar_codec_enable_chmask(struct sitar_priv *sitar,
3802 int event, int index)
3803{
Kuirong Wang906ac472012-07-09 12:54:44 -07003804 int ret = 0;
3805 struct wcd9xxx_ch *ch;
3806
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003807 switch (event) {
3808 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003809 list_for_each_entry(ch,
3810 &sitar->dai[index].wcd9xxx_ch_list, list) {
3811 ret = wcd9xxx_get_slave_port(ch->ch_num);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003812 if (ret < 0) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003813 pr_err("%s: Invalid slave port ID: %d\n",
3814 __func__, ret);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003815 ret = -EINVAL;
3816 break;
3817 }
3818 sitar->dai[index].ch_mask |= 1 << ret;
3819 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003820 break;
3821 case SND_SOC_DAPM_POST_PMD:
3822 ret = wait_event_timeout(sitar->dai[index].dai_wait,
3823 (sitar->dai[index].ch_mask == 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07003824 msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003825 if (!ret) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003826 pr_err("%s: Slim close tx/rx wait timeout\n",
3827 __func__);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003828 ret = -EINVAL;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003829 } else {
3830 ret = 0;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003831 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003832 break;
3833 }
3834 return ret;
3835}
3836
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303837static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3838 struct snd_kcontrol *kcontrol, int event)
3839{
Kuirong Wang906ac472012-07-09 12:54:44 -07003840 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303841 struct snd_soc_codec *codec = w->codec;
3842 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003843 int ret = 0;
3844 struct wcd9xxx_codec_dai_data *dai;
3845
3846 core = dev_get_drvdata(codec->dev->parent);
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003847
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303848 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003849 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003850 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3851 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303852 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003853 }
3854
Kuirong Wang906ac472012-07-09 12:54:44 -07003855 dai = &sitar_p->dai[w->shift];
3856
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303857 switch (event) {
3858 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003859 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3860 w->shift);
3861 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3862 dai->rate, dai->bit_width,
3863 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303864 break;
3865 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003866 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3867 dai->grph);
3868 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3869 w->shift);
3870 if (ret < 0) {
3871 ret = wcd9xxx_disconnect_port(core,
3872 &dai->wcd9xxx_ch_list,
3873 dai->grph);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003874 pr_info("%s: Disconnect RX port ret = %d\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003875 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303876 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003877 if (core != NULL)
3878 sitar_codec_pm_runtime_put(core);
3879 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303880 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003881 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303882}
3883
3884static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3885 struct snd_kcontrol *kcontrol, int event)
3886{
Kuirong Wang906ac472012-07-09 12:54:44 -07003887 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303888 struct snd_soc_codec *codec = w->codec;
3889 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003890 struct wcd9xxx_codec_dai_data *dai;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003891 int ret = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303892
Kuirong Wang906ac472012-07-09 12:54:44 -07003893 core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303894
3895 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003896 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003897 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3898 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303899 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003900 }
3901
Kuirong Wang906ac472012-07-09 12:54:44 -07003902 dai = &sitar_p->dai[w->shift];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303903 switch (event) {
3904 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003905 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3906 w->shift);
3907 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3908 dai->rate, dai->bit_width,
3909 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303910 break;
3911 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003912 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3913 dai->grph);
3914 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3915 w->shift);
3916 if (ret < 0) {
3917 ret = wcd9xxx_disconnect_port(core,
3918 &dai->wcd9xxx_ch_list,
3919 dai->grph);
3920 pr_info("%s: Disconnect RX port ret = %d\n",
3921 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303922 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003923 if (core != NULL)
3924 sitar_codec_pm_runtime_put(core);
3925 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303926 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003927 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303928}
3929
3930
3931static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
3932{
3933 u8 bias_msb, bias_lsb;
3934 short bias_value;
3935
3936 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
3937 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
3938 bias_value = (bias_msb << 8) | bias_lsb;
3939 return bias_value;
3940}
3941
3942static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
3943{
3944 u8 bias_msb, bias_lsb;
3945 short bias_value;
3946
3947 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
3948 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
3949 bias_value = (bias_msb << 8) | bias_lsb;
3950 return bias_value;
3951}
3952
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003953static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
3954 bool on)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303955{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003956 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
3957}
3958
3959static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3960 bool override_bypass, bool noreldetection)
3961{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303962 short bias_value;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003963 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07003964 struct wcd9xxx *core = codec->control_data;
3965 struct wcd9xxx_core_resource *core_res = &core->core_res;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003966
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07003967 wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003968 if (noreldetection)
3969 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303970
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003971 /* Turn on the override */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003972 if (!override_bypass)
3973 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303974 if (dce) {
3975 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3976 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
3977 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003978 usleep_range(sitar->mbhc_data.t_sta_dce,
3979 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303980 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003981 usleep_range(sitar->mbhc_data.t_dce,
3982 sitar->mbhc_data.t_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303983 bias_value = sitar_codec_read_dce_result(codec);
3984 } else {
3985 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3986 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
3987 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003988 usleep_range(sitar->mbhc_data.t_sta_dce,
3989 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303990 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003991 usleep_range(sitar->mbhc_data.t_sta,
3992 sitar->mbhc_data.t_sta);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303993 bias_value = sitar_codec_read_sta_result(codec);
3994 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3995 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
3996 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003997 /* Turn off the override after measuring mic voltage */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003998 if (!override_bypass)
3999 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4000
4001 if (noreldetection)
4002 sitar_turn_onoff_rel_detection(codec, true);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004003 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304004
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304005 return bias_value;
4006}
4007
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004008static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4009 bool norel)
4010{
4011 return __sitar_codec_sta_dce(codec, dce, false, norel);
4012}
4013
4014static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
4015{
4016 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4017 const struct sitar_mbhc_general_cfg *generic =
4018 SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
4019
4020 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
4021 sitar_codec_enable_config_mode(codec, 1);
4022
4023 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4024 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
4025
4026 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
4027
4028 usleep_range(generic->t_shutdown_plug_rem,
4029 generic->t_shutdown_plug_rem);
4030
4031 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
4032 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
4033 sitar_codec_enable_config_mode(codec, 0);
4034
4035 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
4036}
4037
4038static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
4039{
4040 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4041
4042 sitar_codec_shutdown_hs_removal_detect(codec);
4043
4044 if (!sitar->mclk_enabled) {
4045 sitar_codec_disable_clock_block(codec);
4046 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
4047 }
4048
4049 sitar->mbhc_polling_active = false;
4050 sitar->mbhc_state = MBHC_STATE_NONE;
4051}
4052
4053/* called only from interrupt which is under codec_resource_lock acquisition */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304054static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
4055{
4056 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304057 short bias_value;
4058 u8 cfilt_mode;
4059
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004060 if (!sitar->mbhc_cfg.calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304061 pr_err("Error, no sitar calibration\n");
4062 return -ENODEV;
4063 }
4064
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304065 if (!sitar->mclk_enabled) {
4066 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
4067 sitar_enable_rx_bias(codec, 1);
4068 sitar_codec_enable_clock_block(codec, 1);
4069 }
4070
4071 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
4072
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304073 /* Make sure CFILT is in fast mode, save current mode */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004074 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
4075 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
4076
4077 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304078
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304079 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4080 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
4081
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004082 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
4083 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
4084 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
4085
4086 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304087 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4088 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
4089
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004090 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304091 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4092
4093 sitar_codec_calibrate_hs_polling(codec);
4094
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004095 /* don't flip override */
4096 bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004097 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
4098 cfilt_mode);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304099 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
4100
4101 return bias_value;
4102}
4103
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004104static int sitar_cancel_btn_work(struct sitar_priv *sitar)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304105{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004106 int r = 0;
4107 struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004108 struct wcd9xxx_core_resource *core_res = &core->core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304109
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004110 if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
4111 /* if scheduled mbhc_btn_dwork is canceled from here,
4112 * we have to unlock from here instead btn_work */
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004113 wcd9xxx_unlock_sleep(core_res);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004114 r = 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304115 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004116 return r;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304117}
4118
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004119
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004120static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4121 s16 vin_mv)
4122{
4123 short diff, zero;
4124 struct sitar_priv *sitar;
4125 u32 mb_mv, in;
4126
4127 sitar = snd_soc_codec_get_drvdata(codec);
4128 mb_mv = sitar->mbhc_data.micb_mv;
4129
4130 if (mb_mv == 0) {
4131 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4132 return -EINVAL;
4133 }
4134
4135 if (dce) {
4136 diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
4137 zero = sitar->mbhc_data.dce_z;
4138 } else {
4139 diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
4140 zero = sitar->mbhc_data.sta_z;
4141 }
4142 in = (u32) diff * vin_mv;
4143
4144 return (u16) (in / mb_mv) + zero;
4145}
4146
4147static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4148 u16 bias_value)
4149{
4150 struct sitar_priv *sitar;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004151 s16 value, z, mb;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004152 s32 mv;
4153
4154 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004155 value = bias_value;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004156
4157 if (dce) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004158 z = (sitar->mbhc_data.dce_z);
4159 mb = (sitar->mbhc_data.dce_mb);
4160 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004161 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004162 z = (sitar->mbhc_data.sta_z);
4163 mb = (sitar->mbhc_data.sta_mb);
4164 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004165 }
4166
4167 return mv;
4168}
4169
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004170static void btn_lpress_fn(struct work_struct *work)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304171{
4172 struct delayed_work *delayed_work;
4173 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004174 short bias_value;
4175 int dce_mv, sta_mv;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004176 struct wcd9xxx *core;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004177 struct wcd9xxx_core_resource *core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304178
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004179 pr_debug("%s:\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304180
4181 delayed_work = to_delayed_work(work);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004182 sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004183 core = dev_get_drvdata(sitar->codec->dev->parent);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004184 core_res = &core->core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304185
4186 if (sitar) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004187 if (sitar->mbhc_cfg.button_jack) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004188 bias_value = sitar_codec_read_sta_result(sitar->codec);
4189 sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004190 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004191 bias_value = sitar_codec_read_dce_result(sitar->codec);
4192 dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004193 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004194 pr_debug("%s: Reporting long button press event"
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004195 " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
4196 sitar_snd_soc_jack_report(sitar,
4197 sitar->mbhc_cfg.button_jack,
4198 sitar->buttons_pressed,
4199 sitar->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304200 }
4201 } else {
4202 pr_err("%s: Bad sitar private data\n", __func__);
4203 }
4204
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004205 pr_debug("%s: leave\n", __func__);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004206 wcd9xxx_unlock_sleep(core_res);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304207}
4208
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004209
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004210void sitar_mbhc_cal(struct snd_soc_codec *codec)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304211{
4212 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004213 struct sitar_mbhc_btn_detect_cfg *btn_det;
4214 u8 cfilt_mode, bg_mode;
4215 u8 ncic, nmeas, navg;
4216 u32 mclk_rate;
4217 u32 dce_wait, sta_wait;
4218 u8 *n_cic;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004219 void *calibration;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004220 struct wcd9xxx *core = codec->control_data;
4221 struct wcd9xxx_core_resource *core_res = &core->core_res;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004222
4223 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004224 calibration = sitar->mbhc_cfg.calibration;
4225
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004226 wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004227 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004228
4229 /* First compute the DCE / STA wait times
4230 * depending on tunable parameters.
4231 * The value is computed in microseconds
4232 */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004233 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004234 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
4235 ncic = n_cic[sitar_codec_mclk_index(sitar)];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004236 nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4237 navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4238 mclk_rate = sitar->mbhc_cfg.mclk_rate;
4239 dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004240 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
4241
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004242 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4243 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004244
4245 /* LDOH and CFILT are already configured during pdata handling.
4246 * Only need to make sure CFILT and bandgap are in Fast mode.
4247 * Need to restore defaults once calculation is done.
4248 */
4249 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
4250 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4251 bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
4252 0x02);
4253
4254 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4255 * to perform ADC calibration
4256 */
4257 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004258 sitar->mbhc_cfg.micbias << 5);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004259 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4260 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004261 snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004262 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4263
4264 /* DCE measurement for 0 volts */
4265 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
4266 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
4267 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
4268 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
4269 usleep_range(100, 100);
4270 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
4271 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
4272 sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
4273
4274 /* DCE measurment for MB voltage */
4275 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
4276 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
4277 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
4278 usleep_range(100, 100);
4279 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
4280 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
4281 sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
4282
4283 /* Sta measuremnt for 0 volts */
4284 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
4285 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
4286 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
4287 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
4288 usleep_range(100, 100);
4289 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
4290 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
4291 sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
4292
4293 /* STA Measurement for MB Voltage */
4294 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
4295 usleep_range(100, 100);
4296 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
4297 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
4298 sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
4299
4300 /* Restore default settings. */
4301 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4302 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
4303 cfilt_mode);
4304 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4305
4306 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
4307 usleep_range(100, 100);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004308
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004309 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004310 sitar_turn_onoff_rel_detection(codec, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004311}
4312
4313void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
4314 const enum sitar_mbhc_btn_det_mem mem)
4315{
4316 void *ret = &btn_det->_v_btn_low;
4317
4318 switch (mem) {
4319 case SITAR_BTN_DET_GAIN:
4320 ret += sizeof(btn_det->_n_cic);
4321 case SITAR_BTN_DET_N_CIC:
4322 ret += sizeof(btn_det->_n_ready);
4323 case SITAR_BTN_DET_N_READY:
4324 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4325 case SITAR_BTN_DET_V_BTN_HIGH:
4326 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4327 case SITAR_BTN_DET_V_BTN_LOW:
4328 /* do nothing */
4329 break;
4330 default:
4331 ret = NULL;
4332 }
4333
4334 return ret;
4335}
4336
4337static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
4338{
4339 struct sitar_priv *sitar;
4340 s16 btn_mv = 0, btn_delta_mv;
4341 struct sitar_mbhc_btn_detect_cfg *btn_det;
4342 struct sitar_mbhc_plug_type_cfg *plug_type;
4343 u16 *btn_high;
4344 u8 *n_ready;
4345 int i;
4346
4347 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004348 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
4349 plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004350
4351 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004352 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004353 sitar->mbhc_data.npoll = 9;
4354 sitar->mbhc_data.nbounce_wait = 30;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004355 } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004356 sitar->mbhc_data.npoll = 7;
4357 sitar->mbhc_data.nbounce_wait = 23;
4358 }
4359
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004360 sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
4361 (sitar->mbhc_cfg.mclk_rate / 1000) *
4362 n_ready[sitar_codec_mclk_index(sitar)]) +
4363 10;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004364 sitar->mbhc_data.v_ins_hu =
4365 sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4366 sitar->mbhc_data.v_ins_h =
4367 sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4368
4369 btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
4370 for (i = 0; i < btn_det->num_btn; i++)
4371 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4372
4373 sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
4374 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4375
4376 sitar->mbhc_data.v_b1_hu =
4377 sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
4378
4379 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4380
4381 sitar->mbhc_data.v_b1_huc =
4382 sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4383
4384 sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004385 sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004386
4387 sitar->mbhc_data.v_no_mic =
4388 sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4389}
4390
4391void sitar_mbhc_init(struct snd_soc_codec *codec)
4392{
4393 struct sitar_priv *sitar;
4394 struct sitar_mbhc_general_cfg *generic;
4395 struct sitar_mbhc_btn_detect_cfg *btn_det;
4396 int n;
4397 u8 *n_cic, *gain;
4398
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004399 pr_err("%s(): ENTER\n", __func__);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004400 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004401 generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
4402 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004403
4404 for (n = 0; n < 8; n++) {
4405 if (n != 7) {
4406 snd_soc_update_bits(codec,
4407 SITAR_A_CDC_MBHC_FIR_B1_CFG,
4408 0x07, n);
4409 snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
4410 btn_det->c[n]);
4411 }
4412 }
4413 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
4414 btn_det->nc);
4415
4416 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
4417 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
4418 n_cic[sitar_codec_mclk_index(sitar)]);
4419
4420 gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
4421 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
4422 gain[sitar_codec_mclk_index(sitar)] << 3);
4423
4424 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4425 generic->mbhc_nsa << 4);
4426
4427 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4428 btn_det->n_meas);
4429
4430 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4431
4432 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4433
4434 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
4435 btn_det->mbhc_nsc << 3);
4436
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004437 snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
4438 sitar->mbhc_cfg.micbias);
4439
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004440 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004441
4442 snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
4443
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004444}
4445
4446static bool sitar_mbhc_fw_validate(const struct firmware *fw)
4447{
4448 u32 cfg_offset;
4449 struct sitar_mbhc_imped_detect_cfg *imped_cfg;
4450 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
4451
4452 if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
4453 return false;
4454
4455 /* previous check guarantees that there is enough fw data up
4456 * to num_btn
4457 */
4458 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
4459 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4460 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
4461 return false;
4462
4463 /* previous check guarantees that there is enough fw data up
4464 * to start of impedance detection configuration
4465 */
4466 imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
4467 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4468
4469 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
4470 return false;
4471
4472 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
4473 return false;
4474
4475 return true;
4476}
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004477
4478
4479static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
4480{
4481 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
4482}
4483
4484/* called under codec_resource_lock acquisition */
4485void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
4486{
4487 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4488 u8 wg_time;
4489
4490 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
4491 wg_time += 1;
4492
4493 /* If headphone PA is on, check if userspace receives
4494 * removal event to sync-up PA's state */
4495 if (sitar_is_hph_pa_on(codec)) {
4496 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4497 set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
4498 set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
4499 } else {
4500 pr_debug("%s PA is off\n", __func__);
4501 }
4502
4503 if (sitar_is_hph_dac_on(codec, 1))
4504 set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
4505 if (sitar_is_hph_dac_on(codec, 0))
4506 set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
4507
4508 snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
4509 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
4510 0xC0, 0x00);
4511 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
4512 0xC0, 0x00);
4513 usleep_range(wg_time * 1000, wg_time * 1000);
4514}
4515
4516static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
4517{
4518 bool pa_turned_on = false;
4519 struct snd_soc_codec *codec = sitar->codec;
4520 u8 wg_time;
4521
4522 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
4523 wg_time += 1;
4524
4525 if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
4526 &sitar->hph_pa_dac_state)) {
4527 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4528 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
4529 0xC0, 0xC0);
4530 }
4531 if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
4532 &sitar->hph_pa_dac_state)) {
4533 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4534 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
4535 0xC0, 0xC0);
4536 }
4537
4538 if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
4539 &sitar->hph_pa_dac_state)) {
4540 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4541 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
4542 1 << 4);
4543 pa_turned_on = true;
4544 }
4545 if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
4546 &sitar->hph_pa_dac_state)) {
4547 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4548 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
4549 1 << 5);
4550 pa_turned_on = true;
4551 }
4552
4553 if (pa_turned_on) {
4554 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4555 __func__);
4556 usleep_range(wg_time * 1000, wg_time * 1000);
4557 }
4558}
4559
4560static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4561 enum snd_jack_types jack_type)
4562{
4563 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4564
4565 if (!insertion) {
4566 /* Report removal */
4567 sitar->hph_status &= ~jack_type;
4568 if (sitar->mbhc_cfg.headset_jack) {
4569 /* cancel possibly scheduled btn work and
4570 * report release if we reported button press */
4571 if (sitar_cancel_btn_work(sitar)) {
4572 pr_debug("%s: button press is canceled\n",
4573 __func__);
4574 } else if (sitar->buttons_pressed) {
4575 pr_debug("%s: Reporting release for reported "
4576 "button press %d\n", __func__,
4577 jack_type);
4578 sitar_snd_soc_jack_report(sitar,
4579 sitar->mbhc_cfg.button_jack, 0,
4580 sitar->buttons_pressed);
4581 sitar->buttons_pressed &=
4582 ~SITAR_JACK_BUTTON_MASK;
4583 }
4584 pr_debug("%s: Reporting removal %d\n", __func__,
4585 jack_type);
4586 sitar_snd_soc_jack_report(sitar,
4587 sitar->mbhc_cfg.headset_jack,
4588 sitar->hph_status,
4589 SITAR_JACK_MASK);
4590 }
4591 sitar_set_and_turnoff_hph_padac(codec);
4592 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004593 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004594 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004595 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004596 sitar->current_plug = PLUG_TYPE_NONE;
4597 sitar->mbhc_polling_active = false;
4598 } else {
4599 /* Report insertion */
4600 sitar->hph_status |= jack_type;
4601
4602 if (jack_type == SND_JACK_HEADPHONE)
4603 sitar->current_plug = PLUG_TYPE_HEADPHONE;
4604 else if (jack_type == SND_JACK_HEADSET) {
4605 sitar->mbhc_polling_active = true;
4606 sitar->current_plug = PLUG_TYPE_HEADSET;
4607 }
4608 if (sitar->mbhc_cfg.headset_jack) {
4609 pr_debug("%s: Reporting insertion %d\n", __func__,
4610 jack_type);
4611 sitar_snd_soc_jack_report(sitar,
4612 sitar->mbhc_cfg.headset_jack,
4613 sitar->hph_status,
4614 SITAR_JACK_MASK);
4615 }
4616 sitar_clr_and_turnon_hph_padac(sitar);
4617 }
4618}
4619
4620
4621static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
4622{
4623 return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
4624 sitar->mbhc_cfg.gpio_level_insert);
4625}
4626
4627static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
4628 int mic_volt, int mic_volt_prev)
4629{
4630 int delta = abs(mic_volt - mic_volt_prev);
4631 if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
4632 pr_debug("%s: volt delta %dmv\n", __func__, delta);
4633 return true;
4634 }
4635 return false;
4636}
4637
4638static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
4639 s32 mic_volt)
4640{
4641 bool invalid = false;
4642
4643 if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
4644 && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
4645 invalid = true;
4646 }
4647
4648 return invalid;
4649}
4650
4651static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
4652 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
4653 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
4654{
4655 int i;
4656 bool r = false;
4657 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4658 struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
4659 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4660
4661 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
4662 if (mic_mv[i] < plug_type_ptr->v_no_mic)
4663 plug_type[i] = PLUG_TYPE_HEADPHONE;
4664 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
4665 plug_type[i] = PLUG_TYPE_HEADSET;
4666 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
4667 plug_type[i] = PLUG_TYPE_HIGH_HPH;
4668
4669 r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
4670 if (!r && i > 0) {
4671 if (plug_type[i-1] != plug_type[i])
4672 r = true;
4673 else
4674 r = sitar_is_invalid_insert_delta(codec,
4675 mic_mv[i],
4676 mic_mv[i - 1]);
4677 }
4678 }
4679
4680 return r;
4681}
4682
4683/* called under codec_resource_lock acquisition */
4684void sitar_find_plug_and_report(struct snd_soc_codec *codec,
4685 enum sitar_mbhc_plug_type plug_type)
4686{
4687 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4688
4689 if (plug_type == PLUG_TYPE_HEADPHONE
4690 && sitar->current_plug == PLUG_TYPE_NONE) {
4691 /* Nothing was reported previously
4692 * reporte a headphone
4693 */
4694 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4695 sitar_codec_cleanup_hs_polling(codec);
4696 } else if (plug_type == PLUG_TYPE_HEADSET) {
4697 /* If Headphone was reported previously, this will
4698 * only report the mic line
4699 */
4700 sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
4701 msleep(100);
4702 sitar_codec_start_hs_polling(codec);
4703 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
4704 if (sitar->current_plug == PLUG_TYPE_NONE)
4705 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4706 sitar_codec_cleanup_hs_polling(codec);
4707 pr_debug("setup mic trigger for further detection\n");
4708 sitar->lpi_enabled = true;
4709 /* TODO ::: sitar_codec_enable_hs_detect */
4710 pr_err("%s(): High impedence hph not supported\n", __func__);
4711 }
4712}
4713
4714/* should be called under interrupt context that hold suspend */
4715static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
4716{
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004717 struct wcd9xxx *core = sitar->codec->control_data;
4718 struct wcd9xxx_core_resource *core_res = &core->core_res;
4719
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004720 pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
4721 sitar->hs_detect_work_stop = false;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004722 wcd9xxx_lock_sleep(core_res);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004723 schedule_work(&sitar->hs_correct_plug_work);
4724}
4725
4726/* called under codec_resource_lock acquisition */
4727static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
4728{
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004729 struct wcd9xxx *core = sitar->codec->control_data;
4730 struct wcd9xxx_core_resource *core_res = &core->core_res;
4731
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004732 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
4733 sitar->hs_detect_work_stop = true;
4734 wmb();
4735 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4736 if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
4737 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004738 wcd9xxx_unlock_sleep(core_res);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004739 }
4740 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4741}
4742
4743static void sitar_hs_correct_gpio_plug(struct work_struct *work)
4744{
4745 struct sitar_priv *sitar;
4746 struct snd_soc_codec *codec;
4747 int retry = 0, i;
4748 bool correction = false;
4749 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4750 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4751 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4752 unsigned long timeout;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004753 struct wcd9xxx *core;
4754 struct wcd9xxx_core_resource *core_res;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004755
4756 sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
4757 codec = sitar->codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004758 core = sitar->codec->control_data;
4759 core_res = &core->core_res;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004760
4761 pr_debug("%s: enter\n", __func__);
4762 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4763
4764 /* Keep override on during entire plug type correction work.
4765 *
4766 * This is okay under the assumption that any GPIO irqs which use
4767 * MBHC block cancel and sync this work so override is off again
4768 * prior to GPIO interrupt handler's MBHC block usage.
4769 * Also while this correction work is running, we can guarantee
4770 * DAPM doesn't use any MBHC block as this work only runs with
4771 * headphone detection.
4772 */
4773 sitar_turn_onoff_override(codec, true);
4774
4775 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4776 while (!time_after(jiffies, timeout)) {
4777 ++retry;
4778 rmb();
4779 if (sitar->hs_detect_work_stop) {
4780 pr_debug("%s: stop requested\n", __func__);
4781 break;
4782 }
4783
4784 msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
4785 if (sitar_hs_gpio_level_remove(sitar)) {
4786 pr_debug("%s: GPIO value is low\n", __func__);
4787 break;
4788 }
4789
4790 /* can race with removal interrupt */
4791 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4792 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4793 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4794 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4795 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
4796 __func__, retry, mic_mv[i], mb_v[i]);
4797 }
4798 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4799
4800 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4801 pr_debug("Invalid plug in attempt # %d\n", retry);
4802 if (retry == NUM_ATTEMPTS_TO_REPORT &&
4803 sitar->current_plug == PLUG_TYPE_NONE) {
4804 sitar_codec_report_plug(codec, 1,
4805 SND_JACK_HEADPHONE);
4806 }
4807 } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
4808 plug_type) &&
4809 plug_type[0] == PLUG_TYPE_HEADPHONE) {
4810 pr_debug("Good headphone detected, continue polling mic\n");
4811 if (sitar->current_plug == PLUG_TYPE_NONE) {
4812 sitar_codec_report_plug(codec, 1,
4813 SND_JACK_HEADPHONE);
4814 }
4815 } else {
4816 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4817 /* Turn off override */
4818 sitar_turn_onoff_override(codec, false);
4819 sitar_find_plug_and_report(codec, plug_type[0]);
4820 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4821 pr_debug("Attempt %d found correct plug %d\n", retry,
4822 plug_type[0]);
4823 correction = true;
4824 break;
4825 }
4826 }
4827
4828 /* Turn off override */
4829 if (!correction)
4830 sitar_turn_onoff_override(codec, false);
4831
4832 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4833 pr_debug("%s: leave\n", __func__);
4834 /* unlock sleep */
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004835 wcd9xxx_unlock_sleep(core_res);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004836}
4837
4838/* called under codec_resource_lock acquisition */
4839static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
4840{
4841 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4842 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4843 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4844 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4845 int i;
4846
4847 pr_debug("%s: enter\n", __func__);
4848
4849 sitar_turn_onoff_override(codec, true);
4850 mb_v[0] = sitar_codec_setup_hs_polling(codec);
4851 mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
4852 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
4853
4854 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4855 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4856 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4857 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
4858 mic_mv[i]);
4859 }
4860 sitar_turn_onoff_override(codec, false);
4861
4862 if (sitar_hs_gpio_level_remove(sitar)) {
4863 pr_debug("%s: GPIO value is low when determining plug\n",
4864 __func__);
4865 return;
4866 }
4867
4868 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4869 sitar_schedule_hs_detect_plug(sitar);
4870 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
4871 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4872 sitar_schedule_hs_detect_plug(sitar);
4873 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
4874 pr_debug("%s: Valid plug found, determine plug type\n",
4875 __func__);
4876 sitar_find_plug_and_report(codec, plug_type[0]);
4877 }
4878
4879}
4880
4881/* called under codec_resource_lock acquisition */
4882static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
4883{
4884 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4885 const struct sitar_mbhc_plug_detect_cfg *plug_det =
4886 SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
4887
4888 if (plug_det->t_ins_complete > 20)
4889 msleep(plug_det->t_ins_complete);
4890 else
4891 usleep_range(plug_det->t_ins_complete * 1000,
4892 plug_det->t_ins_complete * 1000);
4893
4894 if (sitar_hs_gpio_level_remove(sitar))
4895 pr_debug("%s: GPIO value is low when determining "
4896 "plug\n", __func__);
4897 else
4898 sitar_codec_decide_gpio_plug(codec);
4899
4900 return;
4901}
4902
4903static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
4904{
4905 bool insert;
4906 struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
4907 bool is_removed = false;
4908
4909 pr_debug("%s: enter\n", __func__);
4910
4911 priv->in_gpio_handler = true;
4912 /* Wait here for debounce time */
4913 usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
4914 SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
4915
4916 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4917
4918 /* cancel pending button press */
4919 if (sitar_cancel_btn_work(priv))
4920 pr_debug("%s: button press is canceled\n", __func__);
4921
4922 insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4923 priv->mbhc_cfg.gpio_level_insert);
4924 if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
4925 priv->lpi_enabled = false;
4926 wmb();
4927
4928 /* cancel detect plug */
4929 sitar_cancel_hs_detect_plug(priv);
4930
4931 /* Disable Mic Bias pull down and HPH Switch to GND */
4932 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
4933 0x00);
4934 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
4935 sitar_codec_detect_plug_type(codec);
4936 } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
4937 priv->lpi_enabled = false;
4938 wmb();
4939
4940 /* cancel detect plug */
4941 sitar_cancel_hs_detect_plug(priv);
4942
4943 if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
4944 sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
4945 is_removed = true;
4946 } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
4947 sitar_codec_pause_hs_polling(codec);
4948 sitar_codec_cleanup_hs_polling(codec);
4949 sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
4950 is_removed = true;
4951 }
4952
4953 if (is_removed) {
4954 /* Enable Mic Bias pull down and HPH Switch to GND */
4955 snd_soc_update_bits(codec,
4956 priv->mbhc_bias_regs.ctl_reg, 0x01,
4957 0x01);
4958 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
4959 0x01);
4960 /* Make sure mic trigger is turned off */
4961 snd_soc_update_bits(codec,
4962 priv->mbhc_bias_regs.ctl_reg,
4963 0x01, 0x01);
4964 snd_soc_update_bits(codec,
4965 priv->mbhc_bias_regs.mbhc_reg,
4966 0x90, 0x00);
4967 /* Reset MBHC State Machine */
4968 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4969 0x08, 0x08);
4970 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4971 0x08, 0x00);
4972 /* Turn off override */
4973 sitar_turn_onoff_override(codec, false);
4974 }
4975 }
4976
4977 priv->in_gpio_handler = false;
4978 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4979 pr_debug("%s: leave\n", __func__);
4980}
4981
4982static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
4983{
4984 int r = IRQ_HANDLED;
4985 struct snd_soc_codec *codec = data;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004986 struct wcd9xxx *core = codec->control_data;
4987 struct wcd9xxx_core_resource *core_res = &core->core_res;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004988
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004989 if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004990 pr_warn("%s(): Failed to hold suspend\n", __func__);
4991 r = IRQ_NONE;
4992 } else {
4993 sitar_hs_gpio_handler(codec);
4994 wcd9xxx_unlock_sleep(codec->control_data);
4995 }
4996 return r;
4997}
4998
4999static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
5000{
5001 int rc = 0;
5002 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5003
5004 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5005 sitar_mbhc_init(codec);
5006 sitar_mbhc_cal(codec);
5007 sitar_mbhc_calc_thres(codec);
5008 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5009 sitar_codec_calibrate_hs_polling(codec);
5010
5011 /* Enable Mic Bias pull down and HPH Switch to GND */
5012 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
5013 0x01, 0x01);
5014 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
5015 0x01, 0x01);
5016
5017 rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
5018 NULL,
5019 sitar_mechanical_plug_detect_irq,
5020 (IRQF_TRIGGER_RISING |
5021 IRQF_TRIGGER_FALLING),
5022 "sitar-hs-gpio", codec);
5023
5024 if (!IS_ERR_VALUE(rc)) {
5025 rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
5026 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
5027 0x10, 0x10);
5028 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005029 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005030 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005031 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005032 /* Bootup time detection */
5033 sitar_hs_gpio_handler(codec);
5034 }
5035
5036 return rc;
5037}
5038
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005039static void mbhc_fw_read(struct work_struct *work)
5040{
5041 struct delayed_work *dwork;
5042 struct sitar_priv *sitar;
5043 struct snd_soc_codec *codec;
5044 const struct firmware *fw;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005045 int ret = -1, retry = 0;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005046
5047 dwork = to_delayed_work(work);
5048 sitar = container_of(dwork, struct sitar_priv,
5049 mbhc_firmware_dwork);
5050 codec = sitar->codec;
5051
5052 while (retry < MBHC_FW_READ_ATTEMPTS) {
5053 retry++;
5054 pr_info("%s:Attempt %d to request MBHC firmware\n",
5055 __func__, retry);
5056 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
5057 codec->dev);
5058
5059 if (ret != 0) {
5060 usleep_range(MBHC_FW_READ_TIMEOUT,
5061 MBHC_FW_READ_TIMEOUT);
5062 } else {
5063 pr_info("%s: MBHC Firmware read succesful\n", __func__);
5064 break;
5065 }
5066 }
5067
5068 if (ret != 0) {
5069 pr_err("%s: Cannot load MBHC firmware use default cal\n",
5070 __func__);
5071 } else if (sitar_mbhc_fw_validate(fw) == false) {
5072 pr_err("%s: Invalid MBHC cal data size use default cal\n",
5073 __func__);
5074 release_firmware(fw);
5075 } else {
5076 sitar->calibration = (void *)fw->data;
5077 sitar->mbhc_fw = fw;
5078 }
5079
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005080 sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005081}
5082
5083int sitar_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005084 const struct sitar_mbhc_config *cfg)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005085{
5086 struct sitar_priv *sitar;
5087 int rc = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305088
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005089 if (!codec || !cfg->calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305090 pr_err("Error: no codec or calibration\n");
5091 return -EINVAL;
5092 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005093
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005094 if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
5095 if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005096 pr_err("Error: clock rate %dHz is not yet supported\n",
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005097 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005098 else
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005099 pr_err("Error: unsupported clock rate %d\n",
5100 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005101 return -EINVAL;
5102 }
5103
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305104 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005105 sitar->mbhc_cfg = *cfg;
5106 sitar->in_gpio_handler = false;
5107 sitar->current_plug = PLUG_TYPE_NONE;
5108 sitar->lpi_enabled = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305109 sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
5110
5111 /* Put CFILT in fast mode by default */
5112 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005113 0x40, SITAR_CFILT_FAST_MODE);
5114
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005115 INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005116 INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305117 INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
5118 INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005119 INIT_WORK(&sitar->hs_correct_plug_work,
5120 sitar_hs_correct_gpio_plug);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005121
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005122 if (!sitar->mbhc_cfg.read_fw_bin) {
5123 rc = sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005124 } else {
5125 schedule_delayed_work(&sitar->mbhc_firmware_dwork,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005126 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305127 }
5128
5129 return rc;
5130}
5131EXPORT_SYMBOL_GPL(sitar_hs_detect);
5132
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005133static int sitar_determine_button(const struct sitar_priv *priv,
5134 const s32 bias_mv)
5135{
5136 s16 *v_btn_low, *v_btn_high;
5137 struct sitar_mbhc_btn_detect_cfg *btn_det;
5138 int i, btn = -1;
5139
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005140 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005141 v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
5142 v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
5143 SITAR_BTN_DET_V_BTN_HIGH);
5144 for (i = 0; i < btn_det->num_btn; i++) {
5145 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
5146 btn = i;
5147 break;
5148 }
5149 }
5150
5151 if (btn == -1)
5152 pr_debug("%s: couldn't find button number for mic mv %d\n",
5153 __func__, bias_mv);
5154
5155 return btn;
5156}
5157
5158static int sitar_get_button_mask(const int btn)
5159{
5160 int mask = 0;
5161 switch (btn) {
5162 case 0:
5163 mask = SND_JACK_BTN_0;
5164 break;
5165 case 1:
5166 mask = SND_JACK_BTN_1;
5167 break;
5168 case 2:
5169 mask = SND_JACK_BTN_2;
5170 break;
5171 case 3:
5172 mask = SND_JACK_BTN_3;
5173 break;
5174 case 4:
5175 mask = SND_JACK_BTN_4;
5176 break;
5177 case 5:
5178 mask = SND_JACK_BTN_5;
5179 break;
5180 case 6:
5181 mask = SND_JACK_BTN_6;
5182 break;
5183 case 7:
5184 mask = SND_JACK_BTN_7;
5185 break;
5186 }
5187 return mask;
5188}
5189
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005190
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305191static irqreturn_t sitar_dce_handler(int irq, void *data)
5192{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005193 int i, mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005194 short dce, sta, bias_value_dce;
5195 s32 mv, stamv, bias_mv_dce;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005196 int btn = -1, meas = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305197 struct sitar_priv *priv = data;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005198 const struct sitar_mbhc_btn_detect_cfg *d =
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005199 SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005200 short btnmeas[d->n_btn_meas + 1];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305201 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005202 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005203 struct wcd9xxx_core_resource *core_res = &core->core_res;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005204 int n_btn_meas = d->n_btn_meas;
5205 u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305206
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005207 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305208
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005209 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5210 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5211 pr_debug("%s: mbhc is being recovered, skip button press\n",
5212 __func__);
5213 goto done;
5214 }
5215
5216 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5217
5218 if (!priv->mbhc_polling_active) {
5219 pr_warn("%s: mbhc polling is not active, skip button press\n",
5220 __func__);
5221 goto done;
5222 }
5223
5224 dce = sitar_codec_read_dce_result(codec);
5225 mv = sitar_codec_sta_dce_v(codec, 1, dce);
5226
5227 /* If GPIO interrupt already kicked in, ignore button press */
5228 if (priv->in_gpio_handler) {
5229 pr_debug("%s: GPIO State Changed, ignore button press\n",
5230 __func__);
5231 btn = -1;
5232 goto done;
5233 }
5234
5235 if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
5236 if (priv->mbhc_last_resume &&
5237 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5238 pr_debug("%s: Button is already released shortly after "
5239 "resume\n", __func__);
5240 n_btn_meas = 0;
5241 } else {
5242 pr_debug("%s: Button is already released without "
5243 "resume", __func__);
5244 sta = sitar_codec_read_sta_result(codec);
5245 stamv = sitar_codec_sta_dce_v(codec, 0, sta);
5246 btn = sitar_determine_button(priv, mv);
5247 if (btn != sitar_determine_button(priv, stamv))
5248 btn = -1;
5249 goto done;
5250 }
5251 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305252
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005253 /* determine pressed button */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005254 btnmeas[meas++] = sitar_determine_button(priv, mv);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005255 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005256 meas - 1, dce, mv, btnmeas[meas - 1]);
5257 if (n_btn_meas == 0)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005258 btn = btnmeas[0];
5259 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005260 bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005261 bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
5262 btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
5263 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
5264 __func__, meas, bias_value_dce, bias_mv_dce,
5265 btnmeas[meas]);
5266 /* if large enough measurements are collected,
5267 * start to check if last all n_btn_con measurements were
5268 * in same button low/high range */
5269 if (meas + 1 >= d->n_btn_con) {
5270 for (i = 0; i < d->n_btn_con; i++)
5271 if ((btnmeas[meas] < 0) ||
5272 (btnmeas[meas] != btnmeas[meas - i]))
5273 break;
5274 if (i == d->n_btn_con) {
5275 /* button pressed */
5276 btn = btnmeas[meas];
5277 break;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005278 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5279 /* if left measurements are less than n_btn_con,
5280 * it's impossible to find button number */
5281 break;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005282 }
5283 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005284 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305285
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005286 if (btn >= 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005287 if (priv->in_gpio_handler) {
5288 pr_debug("%s: GPIO already triggered, ignore button "
5289 "press\n", __func__);
5290 goto done;
5291 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005292 mask = sitar_get_button_mask(btn);
5293 priv->buttons_pressed |= mask;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005294 wcd9xxx_lock_sleep(core_res);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005295 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5296 msecs_to_jiffies(400)) == 0) {
5297 WARN(1, "Button pressed twice without release"
5298 "event\n");
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005299 wcd9xxx_unlock_sleep(core_res);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005300 }
5301 } else {
5302 pr_debug("%s: bogus button press, too short press?\n",
5303 __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305304 }
5305
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005306 done:
5307 pr_debug("%s: leave\n", __func__);
5308 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305309 return IRQ_HANDLED;
5310}
5311
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005312static int sitar_is_fake_press(struct sitar_priv *priv)
5313{
5314 int i;
5315 int r = 0;
5316 struct snd_soc_codec *codec = priv->codec;
5317 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
5318 short mb_v;
5319
5320 for (i = 0; i < dces; i++) {
5321 usleep_range(10000, 10000);
5322 if (i == 0) {
5323 mb_v = sitar_codec_sta_dce(codec, 0, true);
5324 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5325 sitar_codec_sta_dce_v(codec, 0, mb_v));
5326 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
5327 mb_v > (short)priv->mbhc_data.v_ins_hu) {
5328 r = 1;
5329 break;
5330 }
5331 } else {
5332 mb_v = sitar_codec_sta_dce(codec, 1, true);
5333 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5334 sitar_codec_sta_dce_v(codec, 1, mb_v));
5335 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
5336 mb_v > (short)priv->mbhc_data.v_ins_h) {
5337 r = 1;
5338 break;
5339 }
5340 }
5341 }
5342
5343 return r;
5344}
5345
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305346static irqreturn_t sitar_release_handler(int irq, void *data)
5347{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005348 int ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305349 struct sitar_priv *priv = data;
5350 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305351
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005352 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305353
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005354 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5355 priv->mbhc_state = MBHC_STATE_RELEASE;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305356
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005357 if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
5358 ret = sitar_cancel_btn_work(priv);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305359 if (ret == 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005360 pr_debug("%s: Reporting long button release event\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005361 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005362 if (priv->mbhc_cfg.button_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305363 sitar_snd_soc_jack_report(priv,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005364 priv->mbhc_cfg.button_jack, 0,
5365 priv->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305366 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005367 if (sitar_is_fake_press(priv)) {
5368 pr_debug("%s: Fake button press interrupt\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005369 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005370 } else if (priv->mbhc_cfg.button_jack) {
5371 if (priv->in_gpio_handler) {
5372 pr_debug("%s: GPIO kicked in, ignore\n",
5373 __func__);
5374 } else {
5375 pr_debug("%s: Reporting short button 0 "
5376 "press and release\n",
5377 __func__);
5378 sitar_snd_soc_jack_report(priv,
5379 priv->mbhc_cfg.button_jack,
5380 priv->buttons_pressed,
5381 priv->buttons_pressed);
5382 sitar_snd_soc_jack_report(priv,
5383 priv->mbhc_cfg.button_jack, 0,
5384 priv->buttons_pressed);
5385 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305386 }
5387 }
5388
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005389 priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
5390 }
5391
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005392 sitar_codec_calibrate_hs_polling(codec);
5393
5394 if (priv->mbhc_cfg.gpio)
5395 msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
5396
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305397 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005398
5399 pr_debug("%s: leave\n", __func__);
5400 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
5401
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305402 return IRQ_HANDLED;
5403}
5404
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305405static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
5406{
5407 struct sitar_priv *sitar = data;
5408 struct snd_soc_codec *codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005409 struct wcd9xxx *core;
5410 struct wcd9xxx_core_resource *core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305411
5412 pr_info("%s: received HPHL OCP irq\n", __func__);
5413
5414 if (sitar) {
5415 codec = sitar->codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005416 core = codec->control_data;
5417 core_res = &core->core_res;
5418
Patrick Lai71579f02013-03-16 13:05:00 -07005419 if ((sitar->hphlocp_cnt < SITAR_OCP_ATTEMPT) &&
5420 (!sitar->hphrocp_cnt)) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305421 pr_info("%s: retry\n", __func__);
Patrick Lai71579f02013-03-16 13:05:00 -07005422 sitar->hphlocp_cnt++;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305423 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005424 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305425 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005426 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305427 } else {
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005428 wcd9xxx_disable_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005429 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305430 sitar->hph_status |= SND_JACK_OC_HPHL;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005431 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305432 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005433 sitar->mbhc_cfg.headset_jack,
5434 sitar->hph_status,
5435 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305436 }
5437 } else {
5438 pr_err("%s: Bad sitar private data\n", __func__);
5439 }
5440
5441 return IRQ_HANDLED;
5442}
5443
5444static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
5445{
5446 struct sitar_priv *sitar = data;
5447 struct snd_soc_codec *codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005448 struct wcd9xxx *core;
5449 struct wcd9xxx_core_resource *core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305450
5451 pr_info("%s: received HPHR OCP irq\n", __func__);
5452
5453 if (sitar) {
5454 codec = sitar->codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005455 core = codec->control_data;
5456 core_res = &core->core_res;
5457
Patrick Lai71579f02013-03-16 13:05:00 -07005458 if ((sitar->hphrocp_cnt < SITAR_OCP_ATTEMPT) &&
5459 (!sitar->hphlocp_cnt)) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305460 pr_info("%s: retry\n", __func__);
Patrick Lai71579f02013-03-16 13:05:00 -07005461 sitar->hphrocp_cnt++;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305462 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
5463 0x00);
5464 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
5465 0x10);
5466 } else {
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005467 wcd9xxx_disable_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005468 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305469 sitar->hph_status |= SND_JACK_OC_HPHR;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005470 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305471 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005472 sitar->mbhc_cfg.headset_jack,
5473 sitar->hph_status,
5474 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305475 }
5476 } else {
5477 pr_err("%s: Bad sitar private data\n", __func__);
5478 }
5479
5480 return IRQ_HANDLED;
5481}
5482
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305483static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
5484{
5485 struct sitar_priv *priv = data;
5486 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005487 struct wcd9xxx *core = codec->control_data;
5488 struct wcd9xxx_core_resource *core_res = &core->core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305489
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005490 pr_debug("%s: enter\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005491 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005492 wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305493
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305494 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5495
5496 /* Turn off both HPH and MIC line schmitt triggers */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005497 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305498 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005499 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305500
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005501 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305502
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005503 rmb();
5504 if (priv->lpi_enabled)
5505 msleep(100);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305506
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005507 rmb();
5508 if (!priv->lpi_enabled) {
5509 pr_debug("%s: lpi is disabled\n", __func__);
5510 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5511 priv->mbhc_cfg.gpio_level_insert) {
5512 pr_debug("%s: Valid insertion, "
5513 "detect plug type\n", __func__);
5514 sitar_codec_decide_gpio_plug(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305515 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005516 pr_debug("%s: Invalid insertion, "
5517 "stop plug detection\n", __func__);
5518 }
5519 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
5520 return IRQ_HANDLED;
5521}
5522
5523static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5524{
5525 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5526 struct sitar_mbhc_plug_type_cfg *plug_type =
5527 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
5528
5529 return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
5530 && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
5531 && (mic_mv > plug_type->v_no_mic)
5532 && (mic_mv < plug_type->v_hs_max)) ? true : false;
5533}
5534
5535/* called under codec_resource_lock acquisition
5536 * returns true if mic voltage range is back to normal insertion
5537 * returns false either if timedout or removed */
5538static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
5539{
5540 int i;
5541 bool timedout, settled = false;
5542 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5543 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5544 unsigned long retry = 0, timeout;
5545 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
5546
5547 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
5548 while (!(timedout = time_after(jiffies, timeout))) {
5549 retry++;
5550 if (sitar_hs_gpio_level_remove(sitar)) {
5551 pr_debug("%s: GPIO indicates removal\n", __func__);
5552 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305553 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005554
5555 if (retry > 1)
5556 msleep(250);
5557 else
5558 msleep(50);
5559
5560 if (sitar_hs_gpio_level_remove(sitar)) {
5561 pr_debug("%s: GPIO indicates removal\n", __func__);
5562 break;
5563 }
5564
5565 sitar_turn_onoff_override(codec, true);
5566 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5567 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
5568 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
5569 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
5570 __func__, retry, mic_mv[i], mb_v[i]);
5571 }
5572 sitar_turn_onoff_override(codec, false);
5573
5574 if (sitar_hs_gpio_level_remove(sitar)) {
5575 pr_debug("%s: GPIO indicates removal\n", __func__);
5576 break;
5577 }
5578
5579 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5580 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5581 break;
5582
5583 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5584 pr_debug("%s: MIC voltage settled\n", __func__);
5585 settled = true;
5586 msleep(200);
5587 break;
5588 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305589 }
5590
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005591 if (timedout)
5592 pr_debug("%s: Microphone did not settle in %d seconds\n",
5593 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
5594 return settled;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305595}
5596
5597static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
5598{
5599 struct sitar_priv *priv = data;
5600 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305601
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005602 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305603
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005604 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5605 if (sitar_hs_remove_settle(codec))
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305606 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005607 pr_debug("%s: remove settle done\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305608
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005609 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305610 return IRQ_HANDLED;
5611}
5612
5613
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305614
5615static irqreturn_t sitar_slimbus_irq(int irq, void *data)
5616{
5617 struct sitar_priv *priv = data;
5618 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005619 unsigned long slimbus_value;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005620 int i, j, k, port_id, ch_mask_temp;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305621 u8 val;
5622
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305623
5624 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
5625 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
5626 SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
5627 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005628 port_id = i*8 + j;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305629 val = wcd9xxx_interface_reg_read(codec->control_data,
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005630 SITAR_SLIM_PGD_PORT_INT_SOURCE0 + port_id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305631 if (val & 0x1)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005632 pr_err_ratelimited("overflow error on port %x, value %x\n",
5633 port_id, val);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305634 if (val & 0x2)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005635 pr_err_ratelimited("underflow error on port %x,value %x\n",
5636 port_id, val);
5637 if (val & 0x4) {
5638 pr_debug("%s: port %x disconnect value %x\n",
5639 __func__, port_id, val);
5640 for (k = 0; k < ARRAY_SIZE(sitar_dai); k++) {
5641 ch_mask_temp = 1 << port_id;
5642 if (ch_mask_temp &
5643 priv->dai[k].ch_mask) {
5644 priv->dai[k].ch_mask &=
5645 ~ch_mask_temp;
5646 if (!priv->dai[k].ch_mask)
5647 wake_up(
5648 &priv->dai[k].dai_wait);
5649 }
5650 }
5651 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305652 }
5653 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005654 SITAR_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
5655 val = 0x0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305656 }
5657
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305658 return IRQ_HANDLED;
5659}
5660
5661
5662static int sitar_handle_pdata(struct sitar_priv *sitar)
5663{
5664 struct snd_soc_codec *codec = sitar->codec;
5665 struct wcd9xxx_pdata *pdata = sitar->pdata;
5666 int k1, k2, rc = 0;
5667 u8 leg_mode = pdata->amic_settings.legacy_mode;
5668 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
5669 u8 txfe_buff = pdata->amic_settings.txfe_buff;
5670 u8 flag = pdata->amic_settings.use_pdata;
5671 u8 i = 0, j = 0;
5672 u8 val_txfe = 0, value = 0;
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305673 int amic_reg_count = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305674
5675 if (!pdata) {
5676 rc = -ENODEV;
5677 goto done;
5678 }
5679
5680 /* Make sure settings are correct */
5681 if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
5682 (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
5683 (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
5684 rc = -EINVAL;
5685 goto done;
5686 }
5687
5688 /* figure out k value */
5689 k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
5690 pdata->micbias.cfilt1_mv);
5691 k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
5692 pdata->micbias.cfilt2_mv);
5693
5694 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
5695 rc = -EINVAL;
5696 goto done;
5697 }
5698
5699 /* Set voltage level and always use LDO */
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07005700 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
5701 (pdata->micbias.ldoh_v << 2));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305702
5703 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
5704 (k1 << 2));
5705 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
5706 (k2 << 2));
5707
5708 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
5709 (pdata->micbias.bias1_cfilt_sel << 5));
5710 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
5711 (pdata->micbias.bias2_cfilt_sel << 5));
5712
Bhalchandra Gajare15dbeaa2012-06-26 12:53:07 -07005713 /* Set micbias capless mode */
5714 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x10,
5715 (pdata->micbias.bias1_cap_mode << 4));
5716 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
5717 (pdata->micbias.bias2_cap_mode << 4));
5718
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305719 amic_reg_count = (NUM_AMIC % 2) ? NUM_AMIC + 1 : NUM_AMIC;
5720 for (i = 0; i < amic_reg_count; j++, i += 2) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305721 if (flag & (0x01 << i)) {
5722 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
5723 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
5724 val_txfe = val_txfe |
5725 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
5726 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5727 0x10, value);
5728 snd_soc_update_bits(codec,
5729 SITAR_A_TX_1_2_TEST_EN + j * 10,
5730 0x30, val_txfe);
5731 }
5732 if (flag & (0x01 << (i + 1))) {
5733 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
5734 val_txfe = (txfe_bypass &
5735 (0x01 << (i + 1))) ? 0x02 : 0x00;
5736 val_txfe |= (txfe_buff &
5737 (0x01 << (i + 1))) ? 0x01 : 0x00;
5738 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5739 0x01, value);
5740 snd_soc_update_bits(codec,
5741 SITAR_A_TX_1_2_TEST_EN + j * 10,
5742 0x03, val_txfe);
5743 }
5744 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005745 if (flag & 0x40) {
5746 value = (leg_mode & 0x40) ? 0x10 : 0x00;
5747 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
5748 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
5749 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
5750 0x13, value);
5751 }
5752
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305753
5754 if (pdata->ocp.use_pdata) {
5755 /* not defined in CODEC specification */
5756 if (pdata->ocp.hph_ocp_limit == 1 ||
5757 pdata->ocp.hph_ocp_limit == 5) {
5758 rc = -EINVAL;
5759 goto done;
5760 }
5761 snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
5762 0x0F, pdata->ocp.num_attempts);
5763 snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
5764 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
5765 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
5766 0xE0, (pdata->ocp.hph_ocp_limit << 5));
5767 }
5768done:
5769 return rc;
5770}
5771
5772static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
5773
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305774 SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
5775 SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
5776
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305777 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
5778 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
5779
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305780 SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
5781 SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
5782 SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
5783
Simmi Pateriya6dc02f72012-10-08 13:28:31 +05305784 SITAR_REG_VAL(SITAR_A_RX_LINE_BIAS_PA, 0xA7),
5785
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305786 SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
Asish Bhattacharya2e1d7522012-05-25 15:08:40 +05305787 SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
5788 SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305789
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305790 SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
5791
5792 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
Bhalchandra Gajare8a0bb372012-10-03 18:41:01 -07005793 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x5B),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305794
5795};
5796
5797static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
5798{
5799 u32 i;
5800 for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
5801 snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
5802 sitar_1_1_reg_defaults[i].val);
5803
5804}
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305805
5806static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
5807 {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
5808};
5809
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305810static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
5811 /* Initialize current threshold to 350MA
5812 * number of wait and run cycles to 4096
5813 */
Bhalchandra Gajare33f74302012-06-14 15:12:51 -07005814 {SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305815 {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
5816
5817 {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
5818
5819 /* Initialize gain registers to use register gain */
5820 {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
5821 {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
5822 {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
5823 {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
5824
Kuirong Wangccb29c62012-06-15 11:09:07 -07005825 /* Set the MICBIAS default output as pull down*/
5826 {SITAR_A_MICB_1_CTL, 0x01, 0x01},
5827 {SITAR_A_MICB_2_CTL, 0x01, 0x01},
5828
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305829 /* Initialize mic biases to differential mode */
5830 {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
5831 {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
5832
5833 {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
5834
5835 /* Use 16 bit sample size for TX1 to TX6 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005836 {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305837 {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
5838 {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
5839 {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
5840 {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005841 {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305842
5843 /* Use 16 bit sample size for RX */
5844 {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
5845 {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
5846
5847 /*enable HPF filter for TX paths */
5848 {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005849 {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07005850
5851 /*enable External clock select*/
5852 {SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305853};
5854
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305855static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
5856{
5857 u32 i;
5858 for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
5859 snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
5860 sitar_i2c_codec_reg_init_val[i].mask,
5861 sitar_i2c_codec_reg_init_val[i].val);
5862}
5863
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305864static void sitar_codec_init_reg(struct snd_soc_codec *codec)
5865{
5866 u32 i;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305867 for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
5868 snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
5869 sitar_codec_reg_init_val[i].mask,
5870 sitar_codec_reg_init_val[i].val);
5871}
5872
5873static int sitar_codec_probe(struct snd_soc_codec *codec)
5874{
Kuirong Wang906ac472012-07-09 12:54:44 -07005875 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305876 struct sitar_priv *sitar;
5877 struct snd_soc_dapm_context *dapm = &codec->dapm;
5878 int ret = 0;
5879 int i;
5880 u8 sitar_version;
Kuirong Wang906ac472012-07-09 12:54:44 -07005881 void *ptr = NULL;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005882 struct wcd9xxx_core_resource *core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305883
5884 codec->control_data = dev_get_drvdata(codec->dev->parent);
Kuirong Wang906ac472012-07-09 12:54:44 -07005885 core = codec->control_data;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005886 core_res = &core->core_res;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305887
5888 sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
5889 if (!sitar) {
5890 dev_err(codec->dev, "Failed to allocate private data\n");
5891 return -ENOMEM;
5892 }
5893
Bhalchandra Gajaref0fde762012-07-17 15:27:30 -07005894 for (i = 0; i < NUM_DECIMATORS; i++) {
5895 tx_hpf_work[i].sitar = sitar;
5896 tx_hpf_work[i].decimator = i + 1;
5897 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
5898 tx_hpf_corner_freq_callback);
5899 }
5900
5901
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305902 /* Make sure mbhc micbias register addresses are zeroed out */
5903 memset(&sitar->mbhc_bias_regs, 0,
5904 sizeof(struct mbhc_micbias_regs));
5905 sitar->cfilt_k_value = 0;
5906 sitar->mbhc_micbias_switched = false;
5907
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005908 /* Make sure mbhc intenal calibration data is zeroed out */
5909 memset(&sitar->mbhc_data, 0,
5910 sizeof(struct mbhc_internal_cal_data));
5911 sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
5912 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
5913 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305914 snd_soc_codec_set_drvdata(codec, sitar);
5915
5916 sitar->mclk_enabled = false;
5917 sitar->bandgap_type = SITAR_BANDGAP_OFF;
5918 sitar->clock_active = false;
5919 sitar->config_mode_active = false;
5920 sitar->mbhc_polling_active = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305921 sitar->no_mic_headset_override = false;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005922 mutex_init(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305923 sitar->codec = codec;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005924 sitar->mbhc_state = MBHC_STATE_NONE;
5925 sitar->mbhc_last_resume = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305926 sitar->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305927 sitar_update_reg_defaults(codec);
5928 sitar_codec_init_reg(codec);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305929 sitar->intf_type = wcd9xxx_get_intf_type();
5930 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
5931 sitar_i2c_codec_init_reg(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305932
Kuirong Wang80dedd62012-12-07 19:16:24 +05305933 for (i = 0; i < COMPANDER_MAX; i++) {
5934 sitar->comp_enabled[i] = 0;
5935 sitar->comp_fs[i] = COMPANDER_FS_48KHZ;
5936 }
5937
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305938 ret = sitar_handle_pdata(sitar);
5939 if (IS_ERR_VALUE(ret)) {
5940 pr_err("%s: bad pdata\n", __func__);
5941 goto err_pdata;
5942 }
5943
Steve Mucklef132c6c2012-06-06 18:30:57 -07005944 snd_soc_add_codec_controls(codec, sitar_snd_controls,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305945 ARRAY_SIZE(sitar_snd_controls));
5946 snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
5947 ARRAY_SIZE(sitar_dapm_widgets));
Kuirong Wang906ac472012-07-09 12:54:44 -07005948
5949 ptr = kmalloc((sizeof(sitar_rx_chs) +
5950 sizeof(sitar_tx_chs)), GFP_KERNEL);
5951 if (!ptr) {
5952 pr_err("%s: no mem for slim chan ctl data\n", __func__);
5953 ret = -ENOMEM;
5954 goto err_nomem_slimch;
5955 }
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305956 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
5957 snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
5958 ARRAY_SIZE(sitar_dapm_i2s_widgets));
5959 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5960 ARRAY_SIZE(audio_i2s_map));
Kuirong Wang906ac472012-07-09 12:54:44 -07005961 for (i = 0; i < ARRAY_SIZE(sitar_i2s_dai); i++)
5962 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305963 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005964 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
5965 for (i = 0; i < NUM_CODEC_DAIS; i++) {
5966 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
5967 init_waitqueue_head(&sitar->dai[i].dai_wait);
5968 }
5969 }
5970 core->num_rx_port = SITAR_RX_MAX;
5971 core->rx_chs = ptr;
5972 memcpy(core->rx_chs, sitar_rx_chs, sizeof(sitar_rx_chs));
5973 core->num_tx_port = SITAR_TX_MAX;
5974 core->tx_chs = ptr + sizeof(sitar_rx_chs);
5975 memcpy(core->tx_chs, sitar_tx_chs, sizeof(sitar_tx_chs));
5976
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305977 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
5978
5979 sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
5980 pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
5981
5982 sitar_version &= 0x1F;
5983 pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
5984
5985 snd_soc_dapm_sync(dapm);
5986
5987
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005988 ret = wcd9xxx_request_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005989 WCD9XXX_IRQ_MBHC_INSERTION,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305990 sitar_hs_insert_irq, "Headset insert detect", sitar);
5991 if (ret) {
5992 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005993 WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305994 goto err_insert_irq;
5995 }
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005996 wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305997
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005998 ret = wcd9xxx_request_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005999 WCD9XXX_IRQ_MBHC_REMOVAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306000 sitar_hs_remove_irq, "Headset remove detect", sitar);
6001 if (ret) {
6002 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006003 WCD9XXX_IRQ_MBHC_REMOVAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306004 goto err_remove_irq;
6005 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306006
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006007 ret = wcd9xxx_request_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006008 WCD9XXX_IRQ_MBHC_POTENTIAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306009 sitar_dce_handler, "DC Estimation detect", sitar);
6010 if (ret) {
6011 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006012 WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306013 goto err_potential_irq;
6014 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306015
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006016 ret = wcd9xxx_request_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006017 WCD9XXX_IRQ_MBHC_RELEASE,
6018 sitar_release_handler,
6019 "Button Release detect", 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_MBHC_RELEASE);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306023 goto err_release_irq;
6024 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306025
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006026 ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006027 sitar_slimbus_irq, "SLIMBUS Slave", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306028 if (ret) {
6029 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006030 WCD9XXX_IRQ_SLIMBUS);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306031 goto err_slimbus_irq;
6032 }
6033
6034 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
6035 wcd9xxx_interface_reg_write(codec->control_data,
6036 SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
6037
6038
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006039 ret = wcd9xxx_request_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006040 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
6041 sitar_hphl_ocp_irq,
6042 "HPH_L OCP detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306043 if (ret) {
6044 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006045 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306046 goto err_hphl_ocp_irq;
6047 }
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006048 wcd9xxx_disable_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006049 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306050
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006051 ret = wcd9xxx_request_irq(core_res,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006052 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
6053 sitar_hphr_ocp_irq, "HPH_R OCP detect",
6054 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306055 if (ret) {
6056 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006057 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306058 goto err_hphr_ocp_irq;
6059 }
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006060 wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306061
Steve Mucklef132c6c2012-06-06 18:30:57 -07006062 codec->ignore_pmdown_time = 1;
6063
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306064#ifdef CONFIG_DEBUG_FS
6065 debug_sitar_priv = sitar;
6066#endif
6067
6068 return ret;
6069
6070err_hphr_ocp_irq:
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006071 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006072 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306073err_hphl_ocp_irq:
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006074 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306075err_slimbus_irq:
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006076 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306077err_release_irq:
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006078 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006079 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306080err_potential_irq:
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006081 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306082err_remove_irq:
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006083 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006084 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306085err_insert_irq:
Kuirong Wang906ac472012-07-09 12:54:44 -07006086 kfree(ptr);
6087err_nomem_slimch:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306088err_pdata:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006089 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306090 kfree(sitar);
6091 return ret;
6092}
6093static int sitar_codec_remove(struct snd_soc_codec *codec)
6094{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306095 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006096 struct wcd9xxx *core = codec->control_data;
6097 struct wcd9xxx_core_resource *core_res = &core->core_res;
6098
6099 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
6100 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
6101 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006102 sitar);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07006103 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
6104 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006105 sitar);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006106 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306107 sitar_codec_disable_clock_block(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006108 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306109 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08006110 if (sitar->mbhc_fw)
6111 release_firmware(sitar->mbhc_fw);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006112 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306113 kfree(sitar);
6114 return 0;
6115}
6116static struct snd_soc_codec_driver soc_codec_dev_sitar = {
6117 .probe = sitar_codec_probe,
6118 .remove = sitar_codec_remove,
6119 .read = sitar_read,
6120 .write = sitar_write,
6121
6122 .readable_register = sitar_readable,
6123 .volatile_register = sitar_volatile,
6124
6125 .reg_cache_size = SITAR_CACHE_SIZE,
6126 .reg_cache_default = sitar_reg_defaults,
6127 .reg_word_size = 1,
6128};
6129
6130#ifdef CONFIG_DEBUG_FS
6131static struct dentry *debugfs_poke;
6132
6133static int codec_debug_open(struct inode *inode, struct file *file)
6134{
6135 file->private_data = inode->i_private;
6136 return 0;
6137}
6138
6139static ssize_t codec_debug_write(struct file *filp,
6140 const char __user *ubuf, size_t cnt, loff_t *ppos)
6141{
6142 char lbuf[32];
6143 char *buf;
6144 int rc;
6145
6146 if (cnt > sizeof(lbuf) - 1)
6147 return -EINVAL;
6148
6149 rc = copy_from_user(lbuf, ubuf, cnt);
6150 if (rc)
6151 return -EFAULT;
6152
6153 lbuf[cnt] = '\0';
6154 buf = (char *)lbuf;
6155 debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
6156 ? false : true;
6157
6158 return rc;
6159}
6160
6161static const struct file_operations codec_debug_ops = {
6162 .open = codec_debug_open,
6163 .write = codec_debug_write,
6164};
6165#endif
6166
6167#ifdef CONFIG_PM
6168static int sitar_suspend(struct device *dev)
6169{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08006170 dev_dbg(dev, "%s: system suspend\n", __func__);
6171 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306172}
6173
6174static int sitar_resume(struct device *dev)
6175{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006176 struct platform_device *pdev = to_platform_device(dev);
6177 struct sitar_priv *sitar = platform_get_drvdata(pdev);
Asish Bhattacharya1d069532012-03-07 13:25:24 -08006178 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07006179 sitar->mbhc_last_resume = jiffies;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08006180 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306181}
6182
6183static const struct dev_pm_ops sitar_pm_ops = {
6184 .suspend = sitar_suspend,
6185 .resume = sitar_resume,
6186};
6187#endif
6188
6189static int __devinit sitar_probe(struct platform_device *pdev)
6190{
6191 int ret = 0;
6192 pr_err("%s\n", __func__);
6193#ifdef CONFIG_DEBUG_FS
6194 debugfs_poke = debugfs_create_file("TRRS",
6195 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
6196
6197#endif
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05306198 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
6199 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306200 sitar_dai, ARRAY_SIZE(sitar_dai));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05306201 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
6202 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
6203 sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05306204 return ret;
6205}
6206static int __devexit sitar_remove(struct platform_device *pdev)
6207{
6208 snd_soc_unregister_codec(&pdev->dev);
6209
6210#ifdef CONFIG_DEBUG_FS
6211 debugfs_remove(debugfs_poke);
6212#endif
6213 return 0;
6214}
6215static struct platform_driver sitar_codec_driver = {
6216 .probe = sitar_probe,
6217 .remove = sitar_remove,
6218 .driver = {
6219 .name = "sitar_codec",
6220 .owner = THIS_MODULE,
6221#ifdef CONFIG_PM
6222 .pm = &sitar_pm_ops,
6223#endif
6224 },
6225};
6226
6227static int __init sitar_codec_init(void)
6228{
6229 return platform_driver_register(&sitar_codec_driver);
6230}
6231
6232static void __exit sitar_codec_exit(void)
6233{
6234 platform_driver_unregister(&sitar_codec_driver);
6235}
6236
6237module_init(sitar_codec_init);
6238module_exit(sitar_codec_exit);
6239
6240MODULE_DESCRIPTION("Sitar codec driver");
6241MODULE_VERSION("1.0");
6242MODULE_LICENSE("GPL v2");