blob: 36d5d6bfd8c2f64fadbdaa6f24a11469a1279897 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/firmware.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
21#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/jack.h>
28#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/tlv.h>
31#include <linux/bitops.h>
32#include <linux/delay.h>
Asish Bhattacharya1d069532012-03-07 13:25:24 -080033#include <linux/pm_runtime.h>
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070034#include <linux/kernel.h>
35#include <linux/gpio.h>
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -070036#include <linux/wait.h>
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053037#include "wcd9304.h"
38
39#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
40 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
Asish Bhattacharyab9afc732012-08-01 15:11:24 +053041#define ADC_DMIC_SEL_ADC 0
42#define ADC_DMIC_SEL_DMIC 1
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053043
Asish Bhattacharya34aa1982012-09-20 14:24:05 +053044#define NUM_AMIC 3
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053045#define NUM_DECIMATORS 4
46#define NUM_INTERPOLATORS 3
47#define BITS_PER_REG 8
Kuirong Wang906ac472012-07-09 12:54:44 -070048
49enum {
50 AIF1_PB = 0,
51 AIF1_CAP,
52 NUM_CODEC_DAIS,
53};
54
55struct wcd9xxx_ch sitar_rx_chs[SITAR_RX_MAX] = {
56 WCD9XXX_CH(10, 0),
57 WCD9XXX_CH(11, 1),
58 WCD9XXX_CH(12, 2),
59 WCD9XXX_CH(13, 3),
60 WCD9XXX_CH(14, 4)
61};
62
63struct wcd9xxx_ch sitar_tx_chs[SITAR_TX_MAX] = {
64 WCD9XXX_CH(0, 0),
65 WCD9XXX_CH(1, 1),
66 WCD9XXX_CH(2, 2),
67 WCD9XXX_CH(3, 3),
68 WCD9XXX_CH(4, 4),
69};
70
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080071#define SITAR_CFILT_FAST_MODE 0x00
72#define SITAR_CFILT_SLOW_MODE 0x40
73#define MBHC_FW_READ_ATTEMPTS 15
74#define MBHC_FW_READ_TIMEOUT 2000000
75
Kuirong Wang906ac472012-07-09 12:54:44 -070076#define SLIM_CLOSE_TIMEOUT 1000
77
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080078#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
79
80#define SITAR_I2S_MASTER_MODE_MASK 0x08
81
82#define SITAR_OCP_ATTEMPT 1
83
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080084#define SITAR_MCLK_RATE_12288KHZ 12288000
85#define SITAR_MCLK_RATE_9600KHZ 9600000
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053086
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080087#define SITAR_FAKE_INS_THRESHOLD_MS 2500
88#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070089#define SITAR_MBHC_BUTTON_MIN 0x8000
90#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
91
92#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
93#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
94
95#define MBHC_NUM_DCE_PLUG_DETECT 3
96#define SITAR_MBHC_FAKE_INSERT_LOW 10
97#define SITAR_MBHC_FAKE_INSERT_HIGH 80
98#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
99#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
100#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
101#define NUM_ATTEMPTS_TO_REPORT 5
102#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
103#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530104
105static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
106static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
107static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
108static struct snd_soc_dai_driver sitar_dai[];
109static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
110 struct snd_kcontrol *kcontrol, int event);
111static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
112 struct snd_kcontrol *kcontrol, int event);
113
114enum sitar_bandgap_type {
115 SITAR_BANDGAP_OFF = 0,
116 SITAR_BANDGAP_AUDIO_MODE,
117 SITAR_BANDGAP_MBHC_MODE,
118};
119
120struct mbhc_micbias_regs {
121 u16 cfilt_val;
122 u16 cfilt_ctl;
123 u16 mbhc_reg;
124 u16 int_rbias;
125 u16 ctl_reg;
126 u8 cfilt_sel;
127};
128
129/* Codec supports 2 IIR filters */
130enum {
131 IIR1 = 0,
132 IIR2,
133 IIR_MAX,
134};
135/* Codec supports 5 bands */
136enum {
137 BAND1 = 0,
138 BAND2,
139 BAND3,
140 BAND4,
141 BAND5,
142 BAND_MAX,
143};
144
145/* Flags to track of PA and DAC state.
146 * PA and DAC should be tracked separately as AUXPGA loopback requires
147 * only PA to be turned on without DAC being on. */
148enum sitar_priv_ack_flags {
149 SITAR_HPHL_PA_OFF_ACK = 0,
150 SITAR_HPHR_PA_OFF_ACK,
151 SITAR_HPHL_DAC_OFF_ACK,
152 SITAR_HPHR_DAC_OFF_ACK
153};
154
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800155/* Data used by MBHC */
156struct mbhc_internal_cal_data {
157 u16 dce_z;
158 u16 dce_mb;
159 u16 sta_z;
160 u16 sta_mb;
161 u32 t_sta_dce;
162 u32 t_dce;
163 u32 t_sta;
164 u32 micb_mv;
165 u16 v_ins_hu;
166 u16 v_ins_h;
167 u16 v_b1_hu;
168 u16 v_b1_h;
169 u16 v_b1_huc;
170 u16 v_brh;
171 u16 v_brl;
172 u16 v_no_mic;
173 u8 npoll;
174 u8 nbounce_wait;
175};
176
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700177enum sitar_mbhc_plug_type {
178 PLUG_TYPE_INVALID = -1,
179 PLUG_TYPE_NONE,
180 PLUG_TYPE_HEADSET,
181 PLUG_TYPE_HEADPHONE,
182 PLUG_TYPE_HIGH_HPH,
183};
184
185enum sitar_mbhc_state {
186 MBHC_STATE_NONE = -1,
187 MBHC_STATE_POTENTIAL,
188 MBHC_STATE_POTENTIAL_RECOVERY,
189 MBHC_STATE_RELEASE,
190};
191
Kuirong Wang906ac472012-07-09 12:54:44 -0700192static const u32 vport_check_table[NUM_CODEC_DAIS] = {
193 0, /* AIF1_PB */
194 0, /* AIF1_CAP */
195};
196
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530197struct sitar_priv {
198 struct snd_soc_codec *codec;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800199 u32 mclk_freq;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530200 u32 adc_count;
201 u32 cfilt1_cnt;
202 u32 cfilt2_cnt;
203 u32 cfilt3_cnt;
204 u32 rx_bias_count;
205 enum sitar_bandgap_type bandgap_type;
206 bool mclk_enabled;
207 bool clock_active;
208 bool config_mode_active;
209 bool mbhc_polling_active;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800210 unsigned long mbhc_fake_ins_start;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530211 int buttons_pressed;
212
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800213 enum sitar_micbias_num micbias;
214 /* void* calibration contains:
215 * struct sitar_mbhc_general_cfg generic;
216 * struct sitar_mbhc_plug_detect_cfg plug_det;
217 * struct sitar_mbhc_plug_type_cfg plug_type;
218 * struct sitar_mbhc_btn_detect_cfg btn_det;
219 * struct sitar_mbhc_imped_detect_cfg imped_det;
220 * Note: various size depends on btn_det->num_btn
221 */
222 void *calibration;
223 struct mbhc_internal_cal_data mbhc_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530224
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530225 struct wcd9xxx_pdata *pdata;
226 u32 anc_slot;
227
228 bool no_mic_headset_override;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530229
230 struct mbhc_micbias_regs mbhc_bias_regs;
231 u8 cfilt_k_value;
232 bool mbhc_micbias_switched;
233
234 /* track PA/DAC state */
235 unsigned long hph_pa_dac_state;
236
237 /*track sitar interface type*/
238 u8 intf_type;
239
240 u32 hph_status; /* track headhpone status */
241 /* define separate work for left and right headphone OCP to avoid
242 * additional checking on which OCP event to report so no locking
243 * to ensure synchronization is required
244 */
245 struct work_struct hphlocp_work; /* reporting left hph ocp off */
246 struct work_struct hphrocp_work; /* reporting right hph ocp off */
247
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530248 u8 hphlocp_cnt; /* headphone left ocp retry */
249 u8 hphrocp_cnt; /* headphone right ocp retry */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800250
251 /* Callback function to enable MCLK */
252 int (*mclk_cb) (struct snd_soc_codec*, int);
253
254 /* Work to perform MBHC Firmware Read */
255 struct delayed_work mbhc_firmware_dwork;
256 const struct firmware *mbhc_fw;
257
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530258 /* num of slim ports required */
Kuirong Wang906ac472012-07-09 12:54:44 -0700259 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700260
261 /* Currently, only used for mbhc purpose, to protect
262 * concurrent execution of mbhc threaded irq handlers and
263 * kill race between DAPM and MBHC.But can serve as a
264 * general lock to protect codec resource
265 */
266 struct mutex codec_resource_lock;
267
268 struct sitar_mbhc_config mbhc_cfg;
269 bool in_gpio_handler;
270 u8 current_plug;
271 bool lpi_enabled;
272 enum sitar_mbhc_state mbhc_state;
273 struct work_struct hs_correct_plug_work;
274 bool hs_detect_work_stop;
275 struct delayed_work mbhc_btn_dwork;
276 unsigned long mbhc_last_resume; /* in jiffies */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530277};
278
279#ifdef CONFIG_DEBUG_FS
280struct sitar_priv *debug_sitar_priv;
281#endif
282
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700283static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
284 struct snd_ctl_elem_value *ucontrol)
285{
286 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
287 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
288 ucontrol->value.integer.value[0] = sitar->anc_slot;
289 return 0;
290}
291
292static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
293 struct snd_ctl_elem_value *ucontrol)
294{
295 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
296 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
297 sitar->anc_slot = ucontrol->value.integer.value[0];
298 return 0;
299}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530300
301static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
302 struct snd_ctl_elem_value *ucontrol)
303{
304 u8 ear_pa_gain;
305 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
306
307 ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
308
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700309 ear_pa_gain &= 0xE0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530310
311 if (ear_pa_gain == 0x00) {
312 ucontrol->value.integer.value[0] = 0;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700313 } else if (ear_pa_gain == 0x80) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530314 ucontrol->value.integer.value[0] = 1;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700315 } else if (ear_pa_gain == 0xA0) {
316 ucontrol->value.integer.value[0] = 2;
317 } else if (ear_pa_gain == 0xE0) {
318 ucontrol->value.integer.value[0] = 3;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530319 } else {
320 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
321 __func__, ear_pa_gain);
322 return -EINVAL;
323 }
324
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530325 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530326
327 return 0;
328}
329
330static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
331 struct snd_ctl_elem_value *ucontrol)
332{
333 u8 ear_pa_gain;
334 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
335
336 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
337 ucontrol->value.integer.value[0]);
338
339 switch (ucontrol->value.integer.value[0]) {
340 case 0:
341 ear_pa_gain = 0x00;
342 break;
343 case 1:
344 ear_pa_gain = 0x80;
345 break;
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700346 case 2:
347 ear_pa_gain = 0xA0;
348 break;
349 case 3:
350 ear_pa_gain = 0xE0;
351 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530352 default:
353 return -EINVAL;
354 }
355
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700356 snd_soc_update_bits(codec, SITAR_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530357 return 0;
358}
359
360static int sitar_get_iir_enable_audio_mixer(
361 struct snd_kcontrol *kcontrol,
362 struct snd_ctl_elem_value *ucontrol)
363{
364 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
365 int iir_idx = ((struct soc_multi_mixer_control *)
366 kcontrol->private_value)->reg;
367 int band_idx = ((struct soc_multi_mixer_control *)
368 kcontrol->private_value)->shift;
369
370 ucontrol->value.integer.value[0] =
371 snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
372 (1 << band_idx);
373
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530374 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530375 iir_idx, band_idx,
376 (uint32_t)ucontrol->value.integer.value[0]);
377 return 0;
378}
379
380static int sitar_put_iir_enable_audio_mixer(
381 struct snd_kcontrol *kcontrol,
382 struct snd_ctl_elem_value *ucontrol)
383{
384 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
385 int iir_idx = ((struct soc_multi_mixer_control *)
386 kcontrol->private_value)->reg;
387 int band_idx = ((struct soc_multi_mixer_control *)
388 kcontrol->private_value)->shift;
389 int value = ucontrol->value.integer.value[0];
390
391 /* Mask first 5 bits, 6-8 are reserved */
392 snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
393 (1 << band_idx), (value << band_idx));
394
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530395 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530396 iir_idx, band_idx, value);
397 return 0;
398}
399static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
400 int iir_idx, int band_idx,
401 int coeff_idx)
402{
403 /* Address does not automatically update if reading */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530404 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530405 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530406 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530407
408 /* Mask bits top 2 bits since they are reserved */
409 return ((snd_soc_read(codec,
410 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
411 (snd_soc_read(codec,
412 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
413 (snd_soc_read(codec,
414 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
415 (snd_soc_read(codec,
416 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
417 0x3FFFFFFF;
418}
419
420static int sitar_get_iir_band_audio_mixer(
421 struct snd_kcontrol *kcontrol,
422 struct snd_ctl_elem_value *ucontrol)
423{
424 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
425 int iir_idx = ((struct soc_multi_mixer_control *)
426 kcontrol->private_value)->reg;
427 int band_idx = ((struct soc_multi_mixer_control *)
428 kcontrol->private_value)->shift;
429
430 ucontrol->value.integer.value[0] =
431 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
432 ucontrol->value.integer.value[1] =
433 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
434 ucontrol->value.integer.value[2] =
435 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
436 ucontrol->value.integer.value[3] =
437 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
438 ucontrol->value.integer.value[4] =
439 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
440
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530441 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530442 "%s: IIR #%d band #%d b1 = 0x%x\n"
443 "%s: IIR #%d band #%d b2 = 0x%x\n"
444 "%s: IIR #%d band #%d a1 = 0x%x\n"
445 "%s: IIR #%d band #%d a2 = 0x%x\n",
446 __func__, iir_idx, band_idx,
447 (uint32_t)ucontrol->value.integer.value[0],
448 __func__, iir_idx, band_idx,
449 (uint32_t)ucontrol->value.integer.value[1],
450 __func__, iir_idx, band_idx,
451 (uint32_t)ucontrol->value.integer.value[2],
452 __func__, iir_idx, band_idx,
453 (uint32_t)ucontrol->value.integer.value[3],
454 __func__, iir_idx, band_idx,
455 (uint32_t)ucontrol->value.integer.value[4]);
456 return 0;
457}
458
459static void set_iir_band_coeff(struct snd_soc_codec *codec,
460 int iir_idx, int band_idx,
461 int coeff_idx, uint32_t value)
462{
463 /* Mask top 3 bits, 6-8 are reserved */
464 /* Update address manually each time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530465 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530466 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530467 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530468
469 /* Mask top 2 bits, 7-8 are reserved */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530470 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530471 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530472 (value >> 24) & 0x3F);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530473
474 /* Isolate 8bits at a time */
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530475 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530476 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530477 (value >> 16) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530478
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530479 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530480 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530481 (value >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530482
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530483 snd_soc_write(codec,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530484 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530485 value & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530486}
487
488static int sitar_put_iir_band_audio_mixer(
489 struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_value *ucontrol)
491{
492 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
493 int iir_idx = ((struct soc_multi_mixer_control *)
494 kcontrol->private_value)->reg;
495 int band_idx = ((struct soc_multi_mixer_control *)
496 kcontrol->private_value)->shift;
497
498 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
499 ucontrol->value.integer.value[0]);
500 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
501 ucontrol->value.integer.value[1]);
502 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
503 ucontrol->value.integer.value[2]);
504 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
505 ucontrol->value.integer.value[3]);
506 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
507 ucontrol->value.integer.value[4]);
508
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530509 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530510 "%s: IIR #%d band #%d b1 = 0x%x\n"
511 "%s: IIR #%d band #%d b2 = 0x%x\n"
512 "%s: IIR #%d band #%d a1 = 0x%x\n"
513 "%s: IIR #%d band #%d a2 = 0x%x\n",
514 __func__, iir_idx, band_idx,
515 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
516 __func__, iir_idx, band_idx,
517 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
518 __func__, iir_idx, band_idx,
519 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
520 __func__, iir_idx, band_idx,
521 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
522 __func__, iir_idx, band_idx,
523 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
524 return 0;
525}
526
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700527static const char * const sitar_ear_pa_gain_text[] = {"POS_6_DB",
528 "POS_2_DB", "NEG_2P5_DB", "NEG_12_DB"};
529
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530530static const struct soc_enum sitar_ear_pa_gain_enum[] = {
Bhalchandra Gajare36d82a42012-06-11 16:09:06 -0700531 SOC_ENUM_SINGLE_EXT(4, sitar_ear_pa_gain_text),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530532};
533
534/*cut of frequency for high pass filter*/
535static const char *cf_text[] = {
536 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
537};
538
539static const struct soc_enum cf_dec1_enum =
540 SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
541
542static const struct soc_enum cf_rxmix1_enum =
543 SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
544
545static const struct snd_kcontrol_new sitar_snd_controls[] = {
546
547 SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
548 sitar_pa_gain_get, sitar_pa_gain_put),
549
550 SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
551 line_gain),
552 SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
553 line_gain),
554
555 SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
556 line_gain),
557 SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
558 line_gain),
559
560 SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
561 -84, 40, digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800562 SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
563 -84, 40, digital_gain),
564 SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
565 -84, 40, digital_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530566
567 SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
568 digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800569 SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
570 digital_gain),
571 SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
572 digital_gain),
573 SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
574 digital_gain),
575
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530576 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
577 40, digital_gain),
578 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
579 40, digital_gain),
580 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
581 40, digital_gain),
582 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
583 40, digital_gain),
584 SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
585 SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800586 SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530587
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700588 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
589 sitar_put_anc_slot),
590
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530591 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
592
593 SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
594
595 SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
596
597 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
598
599 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
600 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
601 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
602 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
603 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
604 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
605 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
606 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
607 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
608 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
609 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
610 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
611 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
612 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
613 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
614 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
615 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
616 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
617 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
618 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
619
620 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
621 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
622 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
623 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
624 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
625 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
626 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
627 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
628 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
629 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
630 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
631 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
632 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
633 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
634 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
635 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
636 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
637 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
638 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
639 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
640};
641
642static const char *rx_mix1_text[] = {
643 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
644 "RX5"
645};
646
647static const char *rx_dac1_text[] = {
648 "ZERO", "RX1", "RX2"
649};
650
651static const char *rx_dac2_text[] = {
652 "ZERO", "RX1",
653};
654
655static const char *rx_dac3_text[] = {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800656 "ZERO", "RX1", "INV_RX1", "RX2"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530657};
658
659static const char *rx_dac4_text[] = {
660 "ZERO", "ON"
661};
662
663static const char *sb_tx1_mux_text[] = {
664 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
665 "DEC1"
666};
667
668static const char *sb_tx2_mux_text[] = {
669 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
670 "DEC2"
671};
672
673static const char *sb_tx3_mux_text[] = {
674 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
675 "DEC3"
676};
677
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800678static const char *sb_tx4_mux_text[] = {
679 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
680 "DEC4"
681};
682
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530683static const char *sb_tx5_mux_text[] = {
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -0700684 "ZERO", "RMIX1", "RMIX2", "RMIX3", "DEC1", "DEC2", "DEC3", "DEC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530685};
686
687static const char *dec1_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700688 "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530689};
690
691static const char *dec2_mux_text[] = {
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700692 "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530693};
694
695static const char *dec3_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -0700696 "ZERO", "DMIC3", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC2", "DMIC4"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530697};
698
699static const char *dec4_mux_text[] = {
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -0700700 "ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530701};
702
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700703static const char const *anc_mux_text[] = {
704 "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
705 "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
706};
707
708static const char const *anc1_fb_mux_text[] = {
709 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
710};
711
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530712static const char const *iir_inp1_text[] = {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530713 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
714 "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
715};
716
717static const struct soc_enum rx_mix1_inp1_chain_enum =
718 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
719
720static const struct soc_enum rx_mix1_inp2_chain_enum =
721 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
722
723static const struct soc_enum rx2_mix1_inp1_chain_enum =
724 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
725
726static const struct soc_enum rx2_mix1_inp2_chain_enum =
727 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
728
729static const struct soc_enum rx3_mix1_inp1_chain_enum =
730 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
731
732static const struct soc_enum rx3_mix1_inp2_chain_enum =
733 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
734
735static const struct soc_enum rx_dac1_enum =
736 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
737
738static const struct soc_enum rx_dac2_enum =
739 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
740
741static const struct soc_enum rx_dac3_enum =
742 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
743
744static const struct soc_enum rx_dac4_enum =
745 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
746
747static const struct soc_enum sb_tx5_mux_enum =
748 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
749
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800750static const struct soc_enum sb_tx4_mux_enum =
751 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
752
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530753static const struct soc_enum sb_tx3_mux_enum =
754 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
755
756static const struct soc_enum sb_tx2_mux_enum =
757 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
758
759static const struct soc_enum sb_tx1_mux_enum =
760 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
761
762static const struct soc_enum dec1_mux_enum =
763 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
764
765static const struct soc_enum dec2_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800766 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530767
768static const struct soc_enum dec3_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800769 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530770
771static const struct soc_enum dec4_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800772 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530773
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700774static const struct soc_enum anc1_mux_enum =
775 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
776
777static const struct soc_enum anc2_mux_enum =
778 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
779
780static const struct soc_enum anc1_fb_mux_enum =
781 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
782
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530783static const struct soc_enum iir1_inp1_mux_enum =
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530784 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir_inp1_text);
785
786static const struct soc_enum iir2_inp1_mux_enum =
787 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ2_B1_CTL, 0, 16, iir_inp1_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530788
789static const struct snd_kcontrol_new rx_mix1_inp1_mux =
790 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
791
792static const struct snd_kcontrol_new rx_mix1_inp2_mux =
793 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
794
795static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
796 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
797
798static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
799 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
800
801static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
802 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
803
804static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
805 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
806
807static const struct snd_kcontrol_new rx_dac1_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800808 SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530809
810static const struct snd_kcontrol_new rx_dac2_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800811 SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530812
813static const struct snd_kcontrol_new rx_dac3_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800814 SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530815
816static const struct snd_kcontrol_new rx_dac4_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800817 SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530818
819static const struct snd_kcontrol_new sb_tx5_mux =
820 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
821
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800822static const struct snd_kcontrol_new sb_tx4_mux =
823 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
824
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530825static const struct snd_kcontrol_new sb_tx3_mux =
826 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
827
828static const struct snd_kcontrol_new sb_tx2_mux =
829 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
830
831static const struct snd_kcontrol_new sb_tx1_mux =
832 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
833
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530834static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
835 struct snd_ctl_elem_value *ucontrol)
836 {
837 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
838 struct snd_soc_dapm_widget *w = wlist->widgets[0];
839 struct snd_soc_codec *codec = w->codec;
840 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
841 unsigned int dec_mux, decimator;
842 char *dec_name = NULL;
843 char *widget_name = NULL;
844 char *temp;
845 u16 tx_mux_ctl_reg;
846 u8 adc_dmic_sel = 0x0;
847 int ret = 0;
848
849 if (ucontrol->value.enumerated.item[0] > e->max - 1)
850 return -EINVAL;
851
852 dec_mux = ucontrol->value.enumerated.item[0];
853
854 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
855 if (!widget_name)
856 return -ENOMEM;
857 temp = widget_name;
858
859 dec_name = strsep(&widget_name, " ");
860 widget_name = temp;
861 if (!dec_name) {
862 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
863 ret = -EINVAL;
864 goto out;
865 }
866
867 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
868 if (ret < 0) {
869 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
870 ret = -EINVAL;
871 goto out;
872 }
873
874 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
875 "dec_mux = %u\n", __func__, w->name, dec_name, decimator,
876 dec_mux);
877
878
879 switch (decimator) {
880 case 1:
881 case 2:
882 if ((dec_mux == 1) || (dec_mux == 6))
883 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
884 else
885 adc_dmic_sel = ADC_DMIC_SEL_ADC;
886 break;
887 case 3:
888 if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
889 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
890 else
891 adc_dmic_sel = ADC_DMIC_SEL_ADC;
892 break;
893 case 4:
894 if ((dec_mux == 1) || (dec_mux == 5)
895 || (dec_mux == 6) || (dec_mux == 7))
896 adc_dmic_sel = ADC_DMIC_SEL_DMIC;
897 else
898 adc_dmic_sel = ADC_DMIC_SEL_ADC;
899 break;
900 default:
901 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
902 ret = -EINVAL;
903 goto out;
904 }
905
906 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
907
908 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
909
910 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
911out:
912 kfree(widget_name);
913 return ret;
914}
915
916#define WCD9304_DEC_ENUM(xname, xenum) \
917{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
918 .info = snd_soc_info_enum_double, \
919 .get = snd_soc_dapm_get_enum_double, \
920 .put = wcd9304_put_dec_enum, \
921 .private_value = (unsigned long)&xenum }
922
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530923static const struct snd_kcontrol_new dec1_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530924 WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530925
926static const struct snd_kcontrol_new dec2_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530927 WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530928
929static const struct snd_kcontrol_new dec3_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530930 WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530931
932static const struct snd_kcontrol_new dec4_mux =
Asish Bhattacharyab9afc732012-08-01 15:11:24 +0530933 WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530934
935static const struct snd_kcontrol_new iir1_inp1_mux =
936 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
937
Asish Bhattacharyaa7354892012-05-28 12:49:01 +0530938static const struct snd_kcontrol_new iir2_inp1_mux =
939 SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
940
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -0700941static const struct snd_kcontrol_new anc1_mux =
942 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
943
944static const struct snd_kcontrol_new anc2_mux =
945 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
946
947static const struct snd_kcontrol_new anc1_fb_mux =
948 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
949
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530950static const struct snd_kcontrol_new dac1_switch[] = {
951 SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
952};
953
Kuirong Wang906ac472012-07-09 12:54:44 -0700954static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
955 struct snd_ctl_elem_value *ucontrol)
956{
957 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
958 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
959
960 ucontrol->value.integer.value[0] = widget->value;
961 return 0;
962}
963
964static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
965 struct snd_ctl_elem_value *ucontrol)
966{
967 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
968 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
969 struct snd_soc_codec *codec = widget->codec;
970 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
971 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
972 struct soc_multi_mixer_control *mixer =
973 ((struct soc_multi_mixer_control *)kcontrol->private_value);
974 u32 dai_id = widget->shift;
975 u32 port_id = mixer->shift;
976 u32 enable = ucontrol->value.integer.value[0];
977
978 mutex_lock(&codec->mutex);
979
980 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
981 if (dai_id != AIF1_CAP) {
982 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
983 __func__);
984 mutex_unlock(&codec->mutex);
985 return -EINVAL;
986 }
987 }
988
989 switch (dai_id) {
990 case AIF1_CAP:
991 if (enable && !(widget->value & 1 << port_id)) {
Kuirong Wangdcc392e2012-10-19 00:33:38 -0700992 if (wcd9xxx_tx_vport_validation(
993 vport_check_table[dai_id],
994 port_id,
995 sitar_p->dai)) {
Kuirong Wang906ac472012-07-09 12:54:44 -0700996 pr_info("%s: TX%u is used by other virtual port\n",
997 __func__, port_id + 1);
998 mutex_unlock(&codec->mutex);
999 return -EINVAL;
1000 }
1001 widget->value |= 1 << port_id;
1002 list_add_tail(&core->tx_chs[port_id].list,
1003 &sitar_p->dai[dai_id].wcd9xxx_ch_list);
1004 } else if (!enable && (widget->value & 1 << port_id)) {
1005 widget->value &= ~(1<<port_id);
1006 list_del_init(&core->tx_chs[port_id].list);
1007 } else {
1008 if (enable)
1009 pr_info("%s: TX%u port is used by this virtual port\n",
1010 __func__, port_id + 1);
1011 else
1012 pr_info("%s: TX%u port is not used by this virtual port\n",
1013 __func__, port_id + 1);
1014 /* avoid update power function */
1015 mutex_unlock(&codec->mutex);
1016 return 0;
1017 }
1018 break;
1019 default:
1020 pr_err("Unknown AIF %d\n", dai_id);
1021 mutex_unlock(&codec->mutex);
1022 return -EINVAL;
1023 }
1024
1025 pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
1026 widget->name, widget->sname, widget->value, widget->shift);
1027 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1028 mutex_unlock(&codec->mutex);
1029 return 0;
1030}
1031
1032static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1033 struct snd_ctl_elem_value *ucontrol)
1034{
1035 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1036 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1037
1038 ucontrol->value.enumerated.item[0] = widget->value;
1039 return 0;
1040}
1041
1042static const char * const slim_rx_mux_text[] = {
1043 "ZERO", "AIF1_PB"
1044};
1045
1046static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1047 struct snd_ctl_elem_value *ucontrol)
1048{
1049 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1050 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1051 struct snd_soc_codec *codec = widget->codec;
1052 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
1053 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1054 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1055 u32 port_id = widget->shift;
1056
1057 widget->value = ucontrol->value.enumerated.item[0];
1058
1059 mutex_lock(&codec->mutex);
1060
1061 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1062 if (widget->value > 1) {
1063 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1064 __func__);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001065 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001066 }
1067 }
1068
1069 switch (widget->value) {
1070 case 0:
1071 list_del_init(&core->rx_chs[port_id].list);
1072 break;
1073 case 1:
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001074 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
1075 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list))
1076 goto pr_err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001077 list_add_tail(&core->rx_chs[port_id].list,
1078 &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
1079 break;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001080 break;
Kuirong Wang906ac472012-07-09 12:54:44 -07001081 default:
1082 pr_err("Unknown AIF %d\n", widget->value);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001083 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001084 }
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001085
1086
Kuirong Wang906ac472012-07-09 12:54:44 -07001087 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001088
Kuirong Wang906ac472012-07-09 12:54:44 -07001089 mutex_unlock(&codec->mutex);
1090 return 0;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001091pr_err:
1092 pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
1093 __func__, port_id + 1);
1094err:
1095 mutex_unlock(&codec->mutex);
1096 return -EINVAL;
Kuirong Wang906ac472012-07-09 12:54:44 -07001097}
1098
1099static const struct soc_enum slim_rx_mux_enum =
1100 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1101
1102static const struct snd_kcontrol_new sitar_aif_pb_mux[SITAR_RX_MAX] = {
1103 SOC_DAPM_ENUM_EXT("SLIM RX1 MUX", slim_rx_mux_enum,
1104 slim_rx_mux_get, slim_rx_mux_put),
1105 SOC_DAPM_ENUM_EXT("SLIM RX2 MUX", slim_rx_mux_enum,
1106 slim_rx_mux_get, slim_rx_mux_put),
1107 SOC_DAPM_ENUM_EXT("SLIM RX3 MUX", slim_rx_mux_enum,
1108 slim_rx_mux_get, slim_rx_mux_put),
1109 SOC_DAPM_ENUM_EXT("SLIM RX4 MUX", slim_rx_mux_enum,
1110 slim_rx_mux_get, slim_rx_mux_put),
1111 SOC_DAPM_ENUM_EXT("SLIM RX5 MUX", slim_rx_mux_enum,
1112 slim_rx_mux_get, slim_rx_mux_put)
1113};
1114
1115static const struct snd_kcontrol_new sitar_aif_cap_mixer[SITAR_TX_MAX] = {
1116 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, SITAR_TX1, 1, 0,
1117 slim_tx_mixer_get, slim_tx_mixer_put),
1118 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, SITAR_TX2, 1, 0,
1119 slim_tx_mixer_get, slim_tx_mixer_put),
1120 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, SITAR_TX3, 1, 0,
1121 slim_tx_mixer_get, slim_tx_mixer_put),
1122 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, SITAR_TX4, 1, 0,
1123 slim_tx_mixer_get, slim_tx_mixer_put),
1124 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, SITAR_TX5, 1, 0,
1125 slim_tx_mixer_get, slim_tx_mixer_put),
1126};
1127
1128
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301129static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
1130 int enable)
1131{
1132 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1133
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301134 pr_debug("%s %d\n", __func__, enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301135
1136 if (enable) {
1137 sitar->adc_count++;
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001138 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL,
1139 0x02, 0x02);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301140 } else {
1141 sitar->adc_count--;
1142 if (!sitar->adc_count) {
1143 if (!sitar->mbhc_polling_active)
Bhalchandra Gajare5d260e32012-07-18 16:30:29 -07001144 snd_soc_update_bits(codec,
1145 SITAR_A_CDC_CLK_OTHR_CTL, 0xE0, 0x0);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301146 }
1147 }
1148}
1149
1150static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
1151 struct snd_kcontrol *kcontrol, int event)
1152{
1153 struct snd_soc_codec *codec = w->codec;
1154 u16 adc_reg;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001155 u8 init_bit_shift;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301156
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301157 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301158
1159 if (w->reg == SITAR_A_TX_1_2_EN)
1160 adc_reg = SITAR_A_TX_1_2_TEST_CTL;
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001161 else if (w->reg == SITAR_A_TX_3_EN)
1162 adc_reg = SITAR_A_TX_3_TEST_CTL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301163 else {
1164 pr_err("%s: Error, invalid adc register\n", __func__);
1165 return -EINVAL;
1166 }
1167
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001168 if (w->shift == 3)
1169 init_bit_shift = 6;
1170 else if (w->shift == 7)
1171 init_bit_shift = 7;
1172 else {
1173 pr_err("%s: Error, invalid init bit postion adc register\n",
1174 __func__);
1175 return -EINVAL;
1176 }
1177
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301178 switch (event) {
1179 case SND_SOC_DAPM_PRE_PMU:
1180 sitar_codec_enable_adc_block(codec, 1);
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001181 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1182 1 << init_bit_shift);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301183 break;
1184 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001185
1186 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1187
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301188 break;
1189 case SND_SOC_DAPM_POST_PMD:
1190 sitar_codec_enable_adc_block(codec, 0);
1191 break;
1192 }
1193 return 0;
1194}
1195
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001196static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
1197 struct snd_kcontrol *kcontrol, int event)
1198{
1199 struct snd_soc_codec *codec = w->codec;
1200
1201 pr_debug("%s %s %d\n", __func__, w->name, event);
1202
1203 switch (event) {
1204 case SND_SOC_DAPM_PRE_PMU:
1205 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1206 break;
1207
1208 case SND_SOC_DAPM_POST_PMD:
1209 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1210 break;
1211 }
1212 return 0;
1213}
1214
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001215static void sitar_enable_classg(struct snd_soc_codec *codec,
1216 bool enable)
1217{
1218
1219 if (enable) {
1220 snd_soc_update_bits(codec,
1221 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x00);
1222 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x00);
1223 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
1224 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
1225
1226 } else {
1227 snd_soc_update_bits(codec,
1228 SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x10);
1229 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x03);
1230 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
1231 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
1232 }
1233}
1234
1235static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
1236{
1237 u8 hph_reg_val = 0;
1238 hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
1239
1240 return (hph_reg_val & 0x30) ? true : false;
1241}
1242
1243static bool sitar_is_line_pa_on(struct snd_soc_codec *codec)
1244{
1245 u8 line_reg_val = 0;
1246 line_reg_val = snd_soc_read(codec, SITAR_A_RX_LINE_CNP_EN);
1247
1248 return (line_reg_val & 0x03) ? true : false;
1249}
1250
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301251static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1252 struct snd_kcontrol *kcontrol, int event)
1253{
1254 struct snd_soc_codec *codec = w->codec;
1255 u16 lineout_gain_reg;
1256
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301257 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301258
1259 switch (w->shift) {
1260 case 0:
1261 lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
1262 break;
1263 case 1:
1264 lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
1265 break;
1266 default:
1267 pr_err("%s: Error, incorrect lineout register value\n",
1268 __func__);
1269 return -EINVAL;
1270 }
1271
1272 switch (event) {
1273 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001274 if (sitar_is_hph_pa_on(codec)) {
1275 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1276 0x20, 0x00);
1277 sitar_enable_classg(codec, false);
1278 } else {
1279 snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
1280 0x20, 0x20);
1281 sitar_enable_classg(codec, true);
1282 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001283 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301284 break;
1285 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001286 pr_debug("%s: sleeping 32 ms after %s PA turn on\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301287 __func__, w->name);
Bhalchandra Gajare37e7e612012-10-09 12:37:20 -07001288 usleep_range(32000, 32000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301289 break;
1290 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001291 if (sitar_is_hph_pa_on(codec))
1292 sitar_enable_classg(codec, true);
1293 else
1294 sitar_enable_classg(codec, false);
1295
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001296 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301297 break;
1298 }
1299 return 0;
1300}
1301
1302static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1303 struct snd_kcontrol *kcontrol, int event)
1304{
1305 struct snd_soc_codec *codec = w->codec;
Asish Bhattacharyab9afc732012-08-01 15:11:24 +05301306 u16 tx_dmic_ctl_reg;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301307 u8 dmic_clk_sel, dmic_clk_en;
1308 unsigned int dmic;
1309 int ret;
1310
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07001311 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301312 if (ret < 0) {
1313 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1314 return -EINVAL;
1315 }
1316
1317 switch (dmic) {
1318 case 1:
1319 case 2:
1320 dmic_clk_sel = 0x02;
1321 dmic_clk_en = 0x01;
1322 break;
1323 case 3:
1324 case 4:
1325 dmic_clk_sel = 0x08;
1326 dmic_clk_en = 0x04;
1327 break;
1328
1329 break;
1330
1331 default:
1332 pr_err("%s: Invalid DMIC Selection\n", __func__);
1333 return -EINVAL;
1334 }
1335
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301336 tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1337
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301338 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301339
1340 switch (event) {
1341 case SND_SOC_DAPM_PRE_PMU:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301342 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1343 dmic_clk_sel, dmic_clk_sel);
1344
1345 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1346
1347 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1348 dmic_clk_en, dmic_clk_en);
1349 break;
1350 case SND_SOC_DAPM_POST_PMD:
1351 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
1352 dmic_clk_en, 0);
1353 break;
1354 }
1355 return 0;
1356}
1357
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07001358static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
1359 struct snd_kcontrol *kcontrol, int event)
1360{
1361 struct snd_soc_codec *codec = w->codec;
1362 const char *filename;
1363 const struct firmware *fw;
1364 int i;
1365 int ret;
1366 int num_anc_slots;
1367 struct anc_header *anc_head;
1368 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1369 u32 anc_writes_size = 0;
1370 int anc_size_remaining;
1371 u32 *anc_ptr;
1372 u16 reg;
1373 u8 mask, val, old_val;
1374
1375 pr_debug("%s %d\n", __func__, event);
1376 switch (event) {
1377 case SND_SOC_DAPM_PRE_PMU:
1378
1379 /* Use the same firmware file as that of WCD9310,
1380 * since the register sequences are same for
1381 * WCD9310 and WCD9304
1382 */
1383 filename = "wcd9310/wcd9310_anc.bin";
1384
1385 ret = request_firmware(&fw, filename, codec->dev);
1386 if (ret != 0) {
1387 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1388 ret);
1389 return -ENODEV;
1390 }
1391
1392 if (fw->size < sizeof(struct anc_header)) {
1393 dev_err(codec->dev, "Not enough data\n");
1394 release_firmware(fw);
1395 return -ENOMEM;
1396 }
1397
1398 /* First number is the number of register writes */
1399 anc_head = (struct anc_header *)(fw->data);
1400 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1401 anc_size_remaining = fw->size - sizeof(struct anc_header);
1402 num_anc_slots = anc_head->num_anc_slots;
1403
1404 if (sitar->anc_slot >= num_anc_slots) {
1405 dev_err(codec->dev, "Invalid ANC slot selected\n");
1406 release_firmware(fw);
1407 return -EINVAL;
1408 }
1409
1410 for (i = 0; i < num_anc_slots; i++) {
1411
1412 if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
1413 dev_err(codec->dev, "Invalid register format\n");
1414 release_firmware(fw);
1415 return -EINVAL;
1416 }
1417 anc_writes_size = (u32)(*anc_ptr);
1418 anc_size_remaining -= sizeof(u32);
1419 anc_ptr += 1;
1420
1421 if (anc_writes_size * SITAR_PACKED_REG_SIZE
1422 > anc_size_remaining) {
1423 dev_err(codec->dev, "Invalid register format\n");
1424 release_firmware(fw);
1425 return -ENOMEM;
1426 }
1427
1428 if (sitar->anc_slot == i)
1429 break;
1430
1431 anc_size_remaining -= (anc_writes_size *
1432 SITAR_PACKED_REG_SIZE);
1433 anc_ptr += anc_writes_size;
1434 }
1435 if (i == num_anc_slots) {
1436 dev_err(codec->dev, "Selected ANC slot not present\n");
1437 release_firmware(fw);
1438 return -ENOMEM;
1439 }
1440
1441 for (i = 0; i < anc_writes_size; i++) {
1442 SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1443 mask, val);
1444 old_val = snd_soc_read(codec, reg);
1445 snd_soc_write(codec, reg, (old_val & ~mask) |
1446 (val & mask));
1447 }
1448
1449 release_firmware(fw);
1450
1451 /* For Sitar, it is required to enable both Feed-forward
1452 * and Feed back clocks to enable ANC
1453 */
1454 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
1455
1456 break;
1457
1458 case SND_SOC_DAPM_POST_PMD:
1459 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1460 snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
1461 break;
1462 }
1463 return 0;
1464}
1465
1466
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301467static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
1468{
1469 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001470 int mbhc_state = sitar->mbhc_state;
1471
1472 pr_debug("%s: enter\n", __func__);
1473 if (!sitar->mbhc_polling_active) {
1474 pr_debug("Polling is not active, do not start polling\n");
1475 return;
1476 }
1477 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
1478
1479
1480 if (!sitar->no_mic_headset_override) {
1481 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1482 pr_debug("%s recovering MBHC state macine\n", __func__);
1483 sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
1484 /* set to max button press threshold */
1485 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
1486 0x7F);
1487 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
1488 0xFF);
1489 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
1490 0x7F);
1491 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
1492 0xFF);
1493 /* set to max */
1494 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
1495 0x7F);
1496 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
1497 0xFF);
1498 }
1499 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301500
1501 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001502 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
1503 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1504 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301505}
1506
1507static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
1508{
1509 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1510
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001511 pr_debug("%s: enter\n", __func__);
1512 if (!sitar->mbhc_polling_active) {
1513 pr_debug("polling not active, nothing to pause\n");
1514 return;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301515 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001516
1517 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1518 pr_debug("%s: leave\n", __func__);
1519
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301520}
1521
1522static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1523 int mode)
1524{
1525 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1526 u8 reg_mode_val, cur_mode_val;
1527 bool mbhc_was_polling = false;
1528
1529 if (mode)
1530 reg_mode_val = SITAR_CFILT_FAST_MODE;
1531 else
1532 reg_mode_val = SITAR_CFILT_SLOW_MODE;
1533
1534 cur_mode_val = snd_soc_read(codec,
1535 sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
1536
1537 if (cur_mode_val != reg_mode_val) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001538 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301539 if (sitar->mbhc_polling_active) {
1540 sitar_codec_pause_hs_polling(codec);
1541 mbhc_was_polling = true;
1542 }
1543 snd_soc_update_bits(codec,
1544 sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1545 if (mbhc_was_polling)
1546 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001547 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301548 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301549 cur_mode_val, reg_mode_val);
1550 } else {
1551 pr_err("%s: CFILT Value is already %x\n",
1552 __func__, cur_mode_val);
1553 }
1554}
1555
1556static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1557 u8 cfilt_sel, int inc)
1558{
1559 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1560 u32 *cfilt_cnt_ptr = NULL;
1561 u16 micb_cfilt_reg;
1562
1563 switch (cfilt_sel) {
1564 case SITAR_CFILT1_SEL:
1565 cfilt_cnt_ptr = &sitar->cfilt1_cnt;
1566 micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
1567 break;
1568 case SITAR_CFILT2_SEL:
1569 cfilt_cnt_ptr = &sitar->cfilt2_cnt;
1570 micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
1571 break;
1572 default:
1573 return; /* should not happen */
1574 }
1575
1576 if (inc) {
1577 if (!(*cfilt_cnt_ptr)++) {
1578 /* Switch CFILT to slow mode if MBHC CFILT being used */
1579 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1580 sitar_codec_switch_cfilt_mode(codec, 0);
1581
1582 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1583 }
1584 } else {
1585 /* check if count not zero, decrement
1586 * then check if zero, go ahead disable cfilter
1587 */
1588 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1589 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1590
1591 /* Switch CFILT to fast mode if MBHC CFILT being used */
1592 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1593 sitar_codec_switch_cfilt_mode(codec, 1);
1594 }
1595 }
1596}
1597
1598static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1599{
1600 int rc = -EINVAL;
1601 unsigned min_mv, max_mv;
1602
1603 switch (ldoh_v) {
1604 case SITAR_LDOH_1P95_V:
1605 min_mv = 160;
1606 max_mv = 1800;
1607 break;
1608 case SITAR_LDOH_2P35_V:
1609 min_mv = 200;
1610 max_mv = 2200;
1611 break;
1612 case SITAR_LDOH_2P75_V:
1613 min_mv = 240;
1614 max_mv = 2600;
1615 break;
1616 case SITAR_LDOH_2P85_V:
1617 min_mv = 250;
1618 max_mv = 2700;
1619 break;
1620 default:
1621 goto done;
1622 }
1623
1624 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1625 goto done;
1626
1627 for (rc = 4; rc <= 44; rc++) {
1628 min_mv = max_mv * (rc) / 44;
1629 if (min_mv >= cfilt_mv) {
1630 rc -= 4;
1631 break;
1632 }
1633 }
1634done:
1635 return rc;
1636}
1637
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301638static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1639{
1640 u8 hph_reg_val = 0;
1641 if (left)
1642 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001643 SITAR_A_RX_HPH_L_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301644 else
1645 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001646 SITAR_A_RX_HPH_R_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301647
1648 return (hph_reg_val & 0xC0) ? true : false;
1649}
1650
1651static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
1652 int vddio_switch)
1653{
1654 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1655 int cfilt_k_val;
1656 bool mbhc_was_polling = false;
1657
1658 switch (vddio_switch) {
1659 case 1:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001660 if (sitar->mbhc_micbias_switched == 0 &&
1661 sitar->mbhc_polling_active) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301662
1663 sitar_codec_pause_hs_polling(codec);
1664 /* Enable Mic Bias switch to VDDIO */
1665 sitar->cfilt_k_value = snd_soc_read(codec,
1666 sitar->mbhc_bias_regs.cfilt_val);
1667 cfilt_k_val = sitar_find_k_value(
1668 sitar->pdata->micbias.ldoh_v, 1800);
1669 snd_soc_update_bits(codec,
1670 sitar->mbhc_bias_regs.cfilt_val,
1671 0xFC, (cfilt_k_val << 2));
1672
1673 snd_soc_update_bits(codec,
1674 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1675 snd_soc_update_bits(codec,
1676 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1677 sitar_codec_start_hs_polling(codec);
1678
1679 sitar->mbhc_micbias_switched = true;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301680 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301681 __func__);
1682 }
1683 break;
1684
1685 case 0:
1686 if (sitar->mbhc_micbias_switched) {
1687 if (sitar->mbhc_polling_active) {
1688 sitar_codec_pause_hs_polling(codec);
1689 mbhc_was_polling = true;
1690 }
1691 /* Disable Mic Bias switch to VDDIO */
1692 if (sitar->cfilt_k_value != 0)
1693 snd_soc_update_bits(codec,
1694 sitar->mbhc_bias_regs.cfilt_val, 0XFC,
1695 sitar->cfilt_k_value);
1696 snd_soc_update_bits(codec,
1697 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1698 snd_soc_update_bits(codec,
1699 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1700
1701 if (mbhc_was_polling)
1702 sitar_codec_start_hs_polling(codec);
1703
1704 sitar->mbhc_micbias_switched = false;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301705 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301706 __func__);
1707 }
1708 break;
1709 }
1710}
1711
1712static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1713 struct snd_kcontrol *kcontrol, int event)
1714{
1715 struct snd_soc_codec *codec = w->codec;
1716 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1717 u16 micb_int_reg;
1718 int micb_line;
1719 u8 cfilt_sel_val = 0;
1720 char *internal1_text = "Internal1";
1721 char *internal2_text = "Internal2";
1722
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301723 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301724 switch (w->reg) {
1725 case SITAR_A_MICB_1_CTL:
1726 micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
1727 cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
1728 micb_line = SITAR_MICBIAS1;
1729 break;
1730 case SITAR_A_MICB_2_CTL:
1731 micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
1732 cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
1733 micb_line = SITAR_MICBIAS2;
1734 break;
1735 default:
1736 pr_err("%s: Error, invalid micbias register\n", __func__);
1737 return -EINVAL;
1738 }
1739
1740 switch (event) {
1741 case SND_SOC_DAPM_PRE_PMU:
1742 /* Decide whether to switch the micbias for MBHC */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001743 if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
1744 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301745 sitar_codec_switch_micbias(codec, 0);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001746 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1747 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301748
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001749 snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301750 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
1751
1752 if (strnstr(w->name, internal1_text, 30))
1753 snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
1754 else if (strnstr(w->name, internal2_text, 30))
1755 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1756 break;
1757 case SND_SOC_DAPM_POST_PMU:
1758 if (sitar->mbhc_polling_active &&
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07001759 sitar->mbhc_cfg.micbias == micb_line) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001760 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301761 sitar_codec_pause_hs_polling(codec);
1762 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001763 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301764 }
1765 break;
1766 case SND_SOC_DAPM_POST_PMD:
1767
1768 if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
1769 && sitar_is_hph_pa_on(codec))
1770 sitar_codec_switch_micbias(codec, 1);
1771
1772 if (strnstr(w->name, internal1_text, 30))
1773 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1774 else if (strnstr(w->name, internal2_text, 30))
1775 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1776 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
1777 break;
1778 }
1779
1780 return 0;
1781}
1782
1783static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
1784 struct snd_kcontrol *kcontrol, int event)
1785{
1786 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001787 u16 dec_reset_reg, gain_reg;
1788 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301789
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301790 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301791
1792 if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1793 dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
1794 else {
1795 pr_err("%s: Error, incorrect dec\n", __func__);
1796 return -EINVAL;
1797 }
1798
1799 switch (event) {
1800 case SND_SOC_DAPM_PRE_PMU:
1801 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1802 1 << w->shift);
1803 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1804 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001805 case SND_SOC_DAPM_POST_PMU:
1806 /* Reprogram the digital gain after power up of Decimator */
1807 gain_reg = SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * w->shift);
1808 current_gain = snd_soc_read(codec, gain_reg);
1809 snd_soc_write(codec, gain_reg, current_gain);
1810 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301811 }
1812 return 0;
1813}
1814
1815static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
1816 struct snd_kcontrol *kcontrol, int event)
1817{
1818 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001819 u16 gain_reg;
1820 u8 current_gain;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301821
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301822 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301823
1824 switch (event) {
1825 case SND_SOC_DAPM_PRE_PMU:
1826 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1827 1 << w->shift, 1 << w->shift);
1828 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1829 1 << w->shift, 0x0);
1830 break;
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07001831 case SND_SOC_DAPM_POST_PMU:
1832 /* Reprogram gain after power up interpolator */
1833 gain_reg = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * w->shift);
1834 current_gain = snd_soc_read(codec, gain_reg);
1835 snd_soc_write(codec, gain_reg, current_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301836 }
1837 return 0;
1838}
1839
1840static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1841 struct snd_kcontrol *kcontrol, int event)
1842{
1843 switch (event) {
1844 case SND_SOC_DAPM_POST_PMU:
1845 case SND_SOC_DAPM_POST_PMD:
1846 usleep_range(1000, 1000);
1847 pr_debug("LDO_H\n");
1848 break;
1849 }
1850 return 0;
1851}
1852
1853static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1854{
1855 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1856
1857 if (enable) {
1858 sitar->rx_bias_count++;
1859 if (sitar->rx_bias_count == 1)
1860 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1861 0x80, 0x80);
1862 } else {
1863 sitar->rx_bias_count--;
1864 if (!sitar->rx_bias_count)
1865 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1866 0x80, 0x00);
1867 }
1868}
1869
1870static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1871 struct snd_kcontrol *kcontrol, int event)
1872{
1873 struct snd_soc_codec *codec = w->codec;
1874
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301875 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301876
1877 switch (event) {
1878 case SND_SOC_DAPM_PRE_PMU:
1879 sitar_enable_rx_bias(codec, 1);
1880 break;
1881 case SND_SOC_DAPM_POST_PMD:
1882 sitar_enable_rx_bias(codec, 0);
1883 break;
1884 }
1885 return 0;
1886}
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001887static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301888 struct snd_kcontrol *kcontrol, int event)
1889{
1890 struct snd_soc_codec *codec = w->codec;
1891
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301892 pr_debug("%s %s %d\n", __func__, w->name, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301893
1894 switch (event) {
1895 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07001896 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
1897 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
1898 0x30, 0x20);
1899 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
1900 0x0C, 0x08);
1901 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301902 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1903 break;
1904 case SND_SOC_DAPM_POST_PMD:
1905 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07001906 if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
1907 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
1908 0x30, 0x10);
1909 snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
1910 0x0C, 0x04);
1911 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301912 break;
1913 }
1914 return 0;
1915}
1916
1917static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
1918 struct snd_soc_jack *jack, int status,
1919 int mask)
1920{
1921 /* XXX: wake_lock_timeout()? */
Laxminath Kasamc24dc6f2012-12-07 11:10:35 +05301922 snd_soc_jack_report_no_dapm(jack, status, mask);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301923}
1924
1925static void hphocp_off_report(struct sitar_priv *sitar,
1926 u32 jack_status, int irq)
1927{
1928 struct snd_soc_codec *codec;
1929
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001930 if (!sitar) {
1931 pr_err("%s: Bad sitar private data\n", __func__);
1932 return;
1933 }
1934
1935 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1936 codec = sitar->codec;
1937 if (sitar->hph_status & jack_status) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301938 sitar->hph_status &= ~jack_status;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001939 if (sitar->mbhc_cfg.headset_jack)
1940 sitar_snd_soc_jack_report(sitar,
1941 sitar->mbhc_cfg.headset_jack,
1942 sitar->hph_status,
1943 SITAR_JACK_MASK);
1944 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1945 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301946 /* reset retry counter as PA is turned off signifying
1947 * start of new OCP detection session
1948 */
Joonwoo Parkf6574c72012-10-10 17:29:57 -07001949 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301950 sitar->hphlocp_cnt = 0;
1951 else
1952 sitar->hphrocp_cnt = 0;
1953 wcd9xxx_enable_irq(codec->control_data, irq);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301954 }
1955}
1956
1957static void hphlocp_off_report(struct work_struct *work)
1958{
1959 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
1960 hphlocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07001961 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
1962 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301963}
1964
1965static void hphrocp_off_report(struct work_struct *work)
1966{
1967 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
1968 hphrocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07001969 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
1970 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301971}
1972
1973static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
1974 struct snd_kcontrol *kcontrol, int event)
1975{
1976 struct snd_soc_codec *codec = w->codec;
1977 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1978 u8 mbhc_micb_ctl_val;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301979 pr_debug("%s: event = %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301980
1981 switch (event) {
1982 case SND_SOC_DAPM_PRE_PMU:
1983 mbhc_micb_ctl_val = snd_soc_read(codec,
1984 sitar->mbhc_bias_regs.ctl_reg);
1985
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001986 if (!(mbhc_micb_ctl_val & 0x80)) {
1987 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301988 sitar_codec_switch_micbias(codec, 1);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001989 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1990 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301991
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08001992 if (sitar_is_line_pa_on(codec))
1993 sitar_enable_classg(codec, false);
1994 else
1995 sitar_enable_classg(codec, true);
1996
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301997 break;
1998
1999 case SND_SOC_DAPM_POST_PMD:
2000 /* schedule work is required because at the time HPH PA DAPM
2001 * event callback is called by DAPM framework, CODEC dapm mutex
2002 * would have been locked while snd_soc_jack_report also
2003 * attempts to acquire same lock.
2004 */
2005 if (w->shift == 5) {
2006 clear_bit(SITAR_HPHL_PA_OFF_ACK,
2007 &sitar->hph_pa_dac_state);
2008 clear_bit(SITAR_HPHL_DAC_OFF_ACK,
2009 &sitar->hph_pa_dac_state);
2010 if (sitar->hph_status & SND_JACK_OC_HPHL)
2011 schedule_work(&sitar->hphlocp_work);
2012 } else if (w->shift == 4) {
2013 clear_bit(SITAR_HPHR_PA_OFF_ACK,
2014 &sitar->hph_pa_dac_state);
2015 clear_bit(SITAR_HPHR_DAC_OFF_ACK,
2016 &sitar->hph_pa_dac_state);
2017 if (sitar->hph_status & SND_JACK_OC_HPHR)
2018 schedule_work(&sitar->hphrocp_work);
2019 }
2020
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002021 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
2022 sitar_codec_switch_micbias(codec, 0);
2023 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302024
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302025 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302026 w->name);
2027 usleep_range(10000, 10000);
2028
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002029 if (sitar_is_line_pa_on(codec))
2030 sitar_enable_classg(codec, true);
2031 else
2032 sitar_enable_classg(codec, false);
2033
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302034 break;
2035 }
2036 return 0;
2037}
2038
2039static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
2040 struct mbhc_micbias_regs *micbias_regs)
2041{
2042 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302043 unsigned int cfilt;
2044
Patrick Laia5062da2012-05-11 17:55:09 -07002045 switch (sitar->mbhc_cfg.micbias) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302046 case SITAR_MICBIAS1:
2047 cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
2048 micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
2049 micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
2050 micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
2051 break;
2052 case SITAR_MICBIAS2:
2053 cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
2054 micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
2055 micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
2056 micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
2057 break;
2058 default:
2059 /* Should never reach here */
2060 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
2061 return;
2062 }
2063
2064 micbias_regs->cfilt_sel = cfilt;
2065
2066 switch (cfilt) {
2067 case SITAR_CFILT1_SEL:
2068 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
2069 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002070 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302071 break;
2072 case SITAR_CFILT2_SEL:
2073 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
2074 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002075 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302076 break;
2077 }
2078}
2079
2080static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
2081 struct snd_kcontrol *kcontrol, int event)
2082{
2083 struct snd_soc_codec *codec = w->codec;
2084
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302085 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302086 switch (event) {
2087 case SND_SOC_DAPM_POST_PMU:
2088 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2089 0x01);
2090 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
2091 usleep_range(200, 200);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302092 break;
2093 case SND_SOC_DAPM_PRE_PMD:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302094 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
Bhalchandra Gajaredf93d702012-11-28 16:59:35 -08002095 /*
2096 * This delay is for the class G controller to settle down
2097 * after turn OFF. The delay is as per the hardware spec for
2098 * the codec
2099 */
2100 usleep_range(20, 20);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302101 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
2102 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302103 break;
2104 }
2105 return 0;
2106}
2107
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002108static int sitar_ear_pa_event(struct snd_soc_dapm_widget *w,
2109 struct snd_kcontrol *kcontrol, int event)
2110{
2111 switch (event) {
2112 case SND_SOC_DAPM_POST_PMU:
2113 pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
2114 __func__);
2115 msleep(20);
2116 break;
2117 case SND_SOC_DAPM_POST_PMD:
2118 pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
2119 __func__);
2120 msleep(20);
2121 break;
2122 }
2123 return 0;
2124}
2125
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302126static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
2127 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
2128 4, 0, NULL, 0),
2129 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
2130 0, NULL, 0),
2131};
2132
2133static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
2134 /*RX stuff */
2135 SND_SOC_DAPM_OUTPUT("EAR"),
2136
Bhalchandra Gajare1fa994d2012-10-09 12:34:44 -07002137 SND_SOC_DAPM_PGA_E("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0,
2138 sitar_ear_pa_event, SND_SOC_DAPM_POST_PMU |
2139 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302140 SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
2141 ARRAY_SIZE(dac1_switch)),
2142 SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07002143
2144 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
2145 AIF1_PB, 0, sitar_codec_enable_slimrx,
2146 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2147
2148 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, SITAR_RX1, 0,
2149 &sitar_aif_pb_mux[SITAR_RX1]),
2150 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, SITAR_RX2, 0,
2151 &sitar_aif_pb_mux[SITAR_RX2]),
2152 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, SITAR_RX3, 0,
2153 &sitar_aif_pb_mux[SITAR_RX3]),
2154 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, SITAR_RX4, 0,
2155 &sitar_aif_pb_mux[SITAR_RX4]),
2156 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, SITAR_RX5, 0,
2157 &sitar_aif_pb_mux[SITAR_RX5]),
2158
2159 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2160 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
2161 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
2162 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
2163 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302164
2165 /* Headphone */
2166 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2167 SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
2168 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2169 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302170
2171 SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
2172 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2173 SND_SOC_DAPM_POST_PMD),
2174
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002175 SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
2176 sitar_hph_dac_event,
2177 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302178 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
Bhalchandra Gajare66131712012-05-07 14:12:26 -07002179 sitar_hph_dac_event,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302180 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2181
2182 /* Speaker */
2183 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
2184 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
2185
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002186 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
2187 , sitar_lineout_dac_event,
2188 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2189 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
2190 , sitar_lineout_dac_event,
2191 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2192
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302193 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
2194 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2195 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2196 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
2197 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
2198 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2199
2200 SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002201 0, sitar_codec_reset_interpolator,
2202 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302203 SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002204 0, sitar_codec_reset_interpolator,
2205 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302206 SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002207 0, sitar_codec_reset_interpolator,
2208 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302209
2210 SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
2211 &rx_dac1_mux),
2212 SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
2213 &rx_dac2_mux),
2214 SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
2215 &rx_dac3_mux),
2216 SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
2217 &rx_dac4_mux),
2218
2219 SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
2220 SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
2221 SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
2222
2223 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2224 &rx_mix1_inp1_mux),
2225 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2226 &rx_mix1_inp2_mux),
2227 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2228 &rx2_mix1_inp1_mux),
2229 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2230 &rx2_mix1_inp2_mux),
2231 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2232 &rx3_mix1_inp1_mux),
2233 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2234 &rx3_mix1_inp2_mux),
2235
2236 SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
2237 sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2238 SND_SOC_DAPM_PRE_PMD),
2239 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2240 sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2241 SND_SOC_DAPM_POST_PMD),
2242
2243 SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
2244 sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2245 /* TX */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002246
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302247 SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2248 0),
2249 SND_SOC_DAPM_INPUT("AMIC1"),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002250 SND_SOC_DAPM_INPUT("AMIC2"),
2251 SND_SOC_DAPM_INPUT("AMIC3"),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302252 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
2253 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2254 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2255 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
2256 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2257 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2258
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302259 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
2260 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2261 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2262 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
2263 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2264 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2265 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
2266 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2267 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2268
2269 SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
2270 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2271 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2272 SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
2273 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2274 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002275 SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
2276 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2277 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302278
2279 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 -07002280 &dec1_mux, sitar_codec_enable_dec,
2281 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002282 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 -07002283 &dec2_mux, sitar_codec_enable_dec,
2284 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002285 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 -07002286 &dec3_mux, sitar_codec_enable_dec,
2287 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002288 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 -07002289 &dec4_mux, sitar_codec_enable_dec,
2290 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302291
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002292 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2293 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2294
2295 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2296 sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2297 SND_SOC_DAPM_POST_PMD),
2298
2299 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2300
Kuirong Wang906ac472012-07-09 12:54:44 -07002301 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
2302 AIF1_CAP, 0, sitar_codec_enable_slimtx,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302303 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2304
Kuirong Wang906ac472012-07-09 12:54:44 -07002305 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
2306 sitar_aif_cap_mixer, ARRAY_SIZE(sitar_aif_cap_mixer)),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302307
Kuirong Wang906ac472012-07-09 12:54:44 -07002308 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, SITAR_TX1, 0,
2309 &sb_tx1_mux),
2310 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, SITAR_TX2, 0,
2311 &sb_tx2_mux),
2312 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2313 &sb_tx3_mux),
2314 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2315 &sb_tx4_mux),
2316 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, SITAR_TX3, 0,
2317 &sb_tx5_mux),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302318
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002319 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
2320 0, sitar_codec_enable_slimtx,
2321 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2322
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302323 /* Digital Mic Inputs */
2324 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2325 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2326 SND_SOC_DAPM_POST_PMD),
2327 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2328 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2329 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302330 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2331 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2332 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302333 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2334 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2335 SND_SOC_DAPM_POST_PMD),
2336
2337 /* Sidetone */
2338 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2339 SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302340 SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
2341 SND_SOC_DAPM_PGA("IIR2", SITAR_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302342
2343};
2344
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302345static const struct snd_soc_dapm_route audio_i2s_map[] = {
2346 {"RX_I2S_CLK", NULL, "CP"},
2347 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2348 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2349 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2350 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2351 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2352
2353 {"SLIM TX1", NULL, "TX_I2S_CLK"},
2354 {"SLIM TX2", NULL, "TX_I2S_CLK"},
2355 {"SLIM TX3", NULL, "TX_I2S_CLK"},
2356 {"SLIM TX4", NULL, "TX_I2S_CLK"},
2357};
Kuirong Wang906ac472012-07-09 12:54:44 -07002358#define SLIM_MIXER(x) (\
2359 {x, "SLIM TX1", "SLIM TX1 MUX"}, \
2360 {x, "SLIM TX2", "SLIM TX2 MUX"}, \
2361 {x, "SLIM TX3", "SLIM TX3 MUX"}, \
2362 {x, "SLIM TX4", "SLIM TX4 MUX"})
2363
2364
2365#define SLIM_MUX(x, y) (\
2366 {"SLIM RX1 MUX", x, y}, \
2367 {"SLIM RX2 MUX", x, y}, \
2368 {"SLIM RX3 MUX", x, y}, \
2369 {"SLIM RX4 MUX", x, y})
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05302370
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302371static const struct snd_soc_dapm_route audio_map[] = {
2372 /* Earpiece (RX MIX1) */
2373 {"EAR", NULL, "EAR PA"},
2374 {"EAR PA", "NULL", "DAC1"},
2375 {"DAC1", "Switch", "DAC1 MUX"},
2376 {"DAC1", NULL, "CP"},
2377 {"DAC1", NULL, "EAR DRIVER"},
2378
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002379 {"CP", NULL, "RX_BIAS"},
2380
2381 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2382 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302383
2384 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002385 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002386 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2387 {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302388
2389 {"LINEOUT1", NULL, "LINEOUT1 PA"},
Bhalchandra Gajareaca4f5b2012-06-13 15:05:15 -07002390 {"LINEOUT2 PA", NULL, "CP"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002391 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2392 {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
2393
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002394 {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
2395 {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
2396 {"ANC", NULL, "ANC1 FB MUX"},
2397
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302398
2399 /* Headset (RX MIX1 and RX MIX2) */
2400 {"HEADPHONE", NULL, "HPHL"},
2401 {"HEADPHONE", NULL, "HPHR"},
2402
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002403
Patrick Lai9b250b72012-05-24 14:45:57 -07002404 {"HPHL DAC", NULL, "CP"},
2405 {"HPHR DAC", NULL, "CP"},
2406
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302407 {"HPHL", NULL, "HPHL DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002408 {"HPHL DAC", "NULL", "RX2 CHAIN"},
2409 {"RX2 CHAIN", NULL, "DAC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302410 {"HPHR", NULL, "HPHR DAC"},
Bhalchandra Gajarecb370232012-07-26 10:44:53 -07002411 {"HPHR DAC", NULL, "RX3 CHAIN"},
2412 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302413
2414 {"DAC1 MUX", "RX1", "RX1 CHAIN"},
2415 {"DAC2 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002416
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302417 {"DAC3 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002418 {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302419 {"DAC3 MUX", "RX2", "RX2 MIX1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002420
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302421 {"DAC4 MUX", "ON", "RX2 MIX1"},
2422
2423 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2424
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302425 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2426 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2427 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2428 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2429 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2430 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2431
Bhalchandra Gajare160c64a2012-06-06 18:31:50 -07002432 /* ANC */
2433 {"ANC", NULL, "ANC1 MUX"},
2434 {"ANC", NULL, "ANC2 MUX"},
2435 {"ANC1 MUX", "ADC1", "ADC1"},
2436 {"ANC1 MUX", "ADC2", "ADC2"},
2437 {"ANC1 MUX", "ADC3", "ADC3"},
2438 {"ANC2 MUX", "ADC1", "ADC1"},
2439 {"ANC2 MUX", "ADC2", "ADC2"},
2440 {"ANC2 MUX", "ADC3", "ADC3"},
2441
2442 {"ANC", NULL, "CDC_CONN"},
2443
2444 {"RX2 MIX1", NULL, "ANC"},
2445 {"RX3 MIX1", NULL, "ANC"},
2446
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302447 /* SLIMBUS Connections */
Kuirong Wang906ac472012-07-09 12:54:44 -07002448 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2449
2450 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2451 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2452 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2453 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2454 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2455 /* SLIM_MUX("AIF1_PB", "AIF1 PB"), */
2456 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2457 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2458 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2459 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2460
2461 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2462 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2463 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2464 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302465
2466 /* Slimbus port 5 is non functional in Sitar 1.0 */
2467 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2468 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2469 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2470 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2471 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302472 {"RX1 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302473 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2474 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2475 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2476 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2477 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302478 {"RX1 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302479 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2480 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2481 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2482 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2483 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302484 {"RX2 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302485 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2486 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2487 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2488 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2489 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302490 {"RX2 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302491 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2492 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2493 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2494 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2495 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302496 {"RX3 MIX1 INP1", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302497 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2498 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2499 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2500 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2501 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302502 {"RX3 MIX1 INP2", "IIR2", "IIR2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302503
2504
2505 /* TX */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302506 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2507 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
2508 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002509 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaree6a30f72012-05-23 19:46:21 -07002510 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
2511 {"SLIM TX5 MUX", "DEC2", "DEC2 MUX"},
2512 {"SLIM TX5 MUX", "DEC3", "DEC3 MUX"},
2513 {"SLIM TX5 MUX", "DEC4", "DEC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302514
2515 /* Decimator Inputs */
2516 {"DEC1 MUX", "DMIC1", "DMIC1"},
2517 {"DEC1 MUX", "DMIC4", "DMIC4"},
2518 {"DEC1 MUX", "ADC1", "ADC1"},
2519 {"DEC1 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002520 {"DEC1 MUX", "ADC3", "ADC3"},
2521 {"DEC1 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302522 {"DEC2 MUX", "DMIC2", "DMIC2"},
2523 {"DEC2 MUX", "DMIC3", "DMIC3"},
2524 {"DEC2 MUX", "ADC1", "ADC1"},
2525 {"DEC2 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002526 {"DEC2 MUX", "ADC3", "ADC3"},
2527 {"DEC2 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302528 {"DEC3 MUX", "DMIC3", "DMIC3"},
2529 {"DEC3 MUX", "ADC1", "ADC1"},
2530 {"DEC3 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002531 {"DEC3 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302532 {"DEC3 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajare9e5a4772012-05-31 12:22:33 -07002533 {"DEC3 MUX", "DMIC4", "DMIC4"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002534 {"DEC3 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302535 {"DEC4 MUX", "DMIC4", "DMIC4"},
2536 {"DEC4 MUX", "ADC1", "ADC1"},
2537 {"DEC4 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002538 {"DEC4 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302539 {"DEC4 MUX", "DMIC3", "DMIC3"},
2540 {"DEC4 MUX", "DMIC2", "DMIC2"},
2541 {"DEC4 MUX", "DMIC1", "DMIC1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002542 {"DEC4 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302543
2544 /* ADC Connections */
2545 {"ADC1", NULL, "AMIC1"},
2546 {"ADC2", NULL, "AMIC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002547 {"ADC3", NULL, "AMIC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302548
2549 /* IIR */
2550 {"IIR1", NULL, "IIR1 INP1 MUX"},
2551 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
Asish Bhattacharyaa7354892012-05-28 12:49:01 +05302552 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2553 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2554 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2555 {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
2556 {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
2557 {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
2558 {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
2559 {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
2560
2561 {"IIR2", NULL, "IIR2 INP1 MUX"},
2562 {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
2563 {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
2564 {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
2565 {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
2566 {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
2567 {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
2568 {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
2569 {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
2570 {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
2571
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302572 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2573 {"MIC BIAS1 External", NULL, "LDO_H"},
2574 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2575 {"MIC BIAS2 External", NULL, "LDO_H"},
2576};
2577
2578static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
2579{
2580 return sitar_reg_readable[reg];
2581}
2582
2583static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2584{
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002585 int i;
2586
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302587 /* Registers lower than 0x100 are top level registers which can be
2588 * written by the Sitar core driver.
2589 */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302590 if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2591 return 1;
2592
2593 /* IIR Coeff registers are not cacheable */
2594 if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
2595 (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
2596 return 1;
2597
Bhalchandra Gajareddd45102012-06-13 17:12:34 -07002598 for (i = 0; i < NUM_DECIMATORS; i++) {
2599 if (reg == SITAR_A_CDC_TX1_VOL_CTL_GAIN + (8 * i))
2600 return 1;
2601 }
2602
2603 for (i = 0; i < NUM_INTERPOLATORS; i++) {
2604 if (reg == SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * i))
2605 return 1;
2606 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302607 return 0;
2608}
2609
2610#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2611static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
2612 unsigned int value)
2613{
2614 int ret;
2615
Kuirong Wang906ac472012-07-09 12:54:44 -07002616 if (reg == SND_SOC_NOPM)
2617 return 0;
2618
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302619 BUG_ON(reg > SITAR_MAX_REGISTER);
2620
2621 if (!sitar_volatile(codec, reg)) {
2622 ret = snd_soc_cache_write(codec, reg, value);
2623 if (ret != 0)
2624 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2625 reg, ret);
2626 }
2627
2628 return wcd9xxx_reg_write(codec->control_data, reg, value);
2629}
2630static unsigned int sitar_read(struct snd_soc_codec *codec,
2631 unsigned int reg)
2632{
2633 unsigned int val;
2634 int ret;
2635
Kuirong Wang906ac472012-07-09 12:54:44 -07002636 if (reg == SND_SOC_NOPM)
2637 return 0;
2638
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302639 BUG_ON(reg > SITAR_MAX_REGISTER);
2640
2641 if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
2642 reg < codec->driver->reg_cache_size) {
2643 ret = snd_soc_cache_read(codec, reg, &val);
2644 if (ret >= 0) {
2645 return val;
2646 } else
2647 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2648 reg, ret);
2649 }
2650
2651 val = wcd9xxx_reg_read(codec->control_data, reg);
2652 return val;
2653}
2654
2655static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2656{
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002657 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302658
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002659 if (SITAR_IS_1P0(sitar_core->version))
2660 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
2661
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002662 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302663 usleep_range(1000, 1000);
2664 snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
2665 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2666 0x80);
2667 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
2668 0x04);
2669 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
2670 0x01);
2671 usleep_range(1000, 1000);
2672 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2673 0x00);
2674}
2675
2676static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
2677 enum sitar_bandgap_type choice)
2678{
2679 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002680 struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302681
2682 /* TODO lock resources accessed by audio streams and threaded
2683 * interrupt handlers
2684 */
2685
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302686 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302687 sitar->bandgap_type);
2688
2689 if (sitar->bandgap_type == choice)
2690 return;
2691
2692 if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
2693 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2694 sitar_codec_enable_audio_mode_bandgap(codec);
2695 } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
Bhalchandra Gajare7708ee32012-05-24 17:37:37 -07002696 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302697 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
2698 0x2);
2699 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2700 0x80);
2701 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
2702 0x4);
2703 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
2704 0x1);
2705 usleep_range(1000, 1000);
2706 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
2707 0x00);
2708 } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
2709 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2710 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
2711 usleep_range(100, 100);
2712 sitar_codec_enable_audio_mode_bandgap(codec);
2713 } else if (choice == SITAR_BANDGAP_OFF) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002714 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302715 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07002716 if (SITAR_IS_1P0(sitar_core->version))
2717 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
Asish Bhattacharya63032b42012-08-16 20:57:01 +05302718 0xF3, 0x61);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002719 usleep_range(1000, 1000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302720 } else {
2721 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2722 }
2723 sitar->bandgap_type = choice;
2724}
2725
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002726static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
2727 int enable)
2728{
2729 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2730
2731 if (enable) {
2732 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
2733 snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
2734 usleep_range(5, 5);
2735 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
2736 0x80);
2737 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
2738 0x80);
2739 usleep_range(10, 10);
2740 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
2741 usleep_range(20, 20);
2742 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
2743 } else {
2744 snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
2745 0);
2746 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
2747 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2748 }
2749 sitar->config_mode_active = enable ? true : false;
2750
2751 return 0;
2752}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302753
2754static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
2755 int config_mode)
2756{
2757 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2758
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302759 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302760
2761 if (config_mode) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002762 sitar_codec_enable_config_mode(codec, 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302763 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
2764 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2765 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
2766 usleep_range(1000, 1000);
2767 } else
2768 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2769
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002770 if (!config_mode && sitar->mbhc_polling_active) {
2771 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2772 sitar_codec_enable_config_mode(codec, 0);
2773
2774 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302775
2776 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
2777 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
2778 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302779 usleep_range(50, 50);
2780 sitar->clock_active = true;
2781 return 0;
2782}
2783static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
2784{
2785 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302786 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302787 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
2788 ndelay(160);
2789 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
2790 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
2791 sitar->clock_active = false;
2792}
2793
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002794static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
2795{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002796 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002797 return 0;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002798 else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002799 return 1;
2800 else {
2801 BUG_ON(1);
2802 return -EINVAL;
2803 }
2804}
2805
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302806static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2807{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002808 u8 *n_ready, *n_cic;
2809 struct sitar_mbhc_btn_detect_cfg *btn_det;
2810 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302811
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002812 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302813
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002814 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
2815 sitar->mbhc_data.v_ins_hu & 0xFF);
2816 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
2817 (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302818
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002819 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
2820 sitar->mbhc_data.v_b1_hu & 0xFF);
2821 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
2822 (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
2823
2824 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
2825 sitar->mbhc_data.v_b1_h & 0xFF);
2826 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
2827 (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
2828
2829 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
2830 sitar->mbhc_data.v_brh & 0xFF);
2831 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
2832 (sitar->mbhc_data.v_brh >> 8) & 0xFF);
2833
2834 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
2835 sitar->mbhc_data.v_brl & 0xFF);
2836 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
2837 (sitar->mbhc_data.v_brl >> 8) & 0xFF);
2838
2839 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
2840 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
2841 n_ready[sitar_codec_mclk_index(sitar)]);
2842 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
2843 sitar->mbhc_data.npoll);
2844 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
2845 sitar->mbhc_data.nbounce_wait);
2846 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
2847 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
2848 n_cic[sitar_codec_mclk_index(sitar)]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302849}
2850
2851static int sitar_startup(struct snd_pcm_substream *substream,
2852 struct snd_soc_dai *dai)
2853{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08002854 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
2855 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
2856 (wcd9xxx->dev->parent != NULL))
2857 pm_runtime_get_sync(wcd9xxx->dev->parent);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302858 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302859 substream->name, substream->stream);
2860
2861 return 0;
2862}
2863
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07002864static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
2865{
2866 if (sitar->dev != NULL &&
2867 sitar->dev->parent != NULL) {
2868 pm_runtime_mark_last_busy(sitar->dev->parent);
2869 pm_runtime_put(sitar->dev->parent);
2870 }
2871}
2872
2873static void sitar_shutdown(struct snd_pcm_substream *substream,
2874 struct snd_soc_dai *dai)
2875{
2876 struct wcd9xxx *sitar_core = dev_get_drvdata(dai->codec->dev->parent);
2877 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2878 u32 active = 0;
2879
2880 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2881 substream->name, substream->stream);
2882 if (sitar->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2883 return;
2884
2885 if (dai->id <= NUM_CODEC_DAIS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07002886 if (sitar->dai[dai->id].ch_mask) {
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07002887 active = 1;
Joonwoo Park9bbb4d12012-11-09 19:58:11 -08002888 pr_debug("%s(): Codec DAI: chmask[%d] = 0x%lx\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07002889 __func__, dai->id,
2890 sitar->dai[dai->id].ch_mask);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07002891 }
2892 }
2893
2894 if (sitar_core != NULL && active == 0)
2895 sitar_codec_pm_runtime_put(sitar_core);
2896}
2897
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002898int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302899{
2900 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2901
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302902 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302903
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002904 if (dapm)
2905 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302906 if (mclk_enable) {
2907 sitar->mclk_enabled = true;
2908
2909 if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
2910 sitar_codec_pause_hs_polling(codec);
2911 sitar_codec_enable_bandgap(codec,
2912 SITAR_BANDGAP_AUDIO_MODE);
2913 sitar_codec_enable_clock_block(codec, 0);
2914 sitar_codec_calibrate_hs_polling(codec);
2915 sitar_codec_start_hs_polling(codec);
2916 } else {
2917 sitar_codec_enable_bandgap(codec,
2918 SITAR_BANDGAP_AUDIO_MODE);
2919 sitar_codec_enable_clock_block(codec, 0);
2920 }
2921 } else {
2922
2923 if (!sitar->mclk_enabled) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002924 if (dapm)
2925 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302926 pr_err("Error, MCLK already diabled\n");
2927 return -EINVAL;
2928 }
2929 sitar->mclk_enabled = false;
2930
2931 if (sitar->mbhc_polling_active) {
2932 if (!sitar->mclk_enabled) {
2933 sitar_codec_pause_hs_polling(codec);
2934 sitar_codec_enable_bandgap(codec,
2935 SITAR_BANDGAP_MBHC_MODE);
2936 sitar_enable_rx_bias(codec, 1);
2937 sitar_codec_enable_clock_block(codec, 1);
2938 sitar_codec_calibrate_hs_polling(codec);
2939 sitar_codec_start_hs_polling(codec);
2940 }
2941 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
2942 0x05, 0x01);
2943 } else {
2944 sitar_codec_disable_clock_block(codec);
2945 sitar_codec_enable_bandgap(codec,
2946 SITAR_BANDGAP_OFF);
2947 }
2948 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002949 if (dapm)
2950 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302951 return 0;
2952}
2953
2954static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
2955 int clk_id, unsigned int freq, int dir)
2956{
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302957 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302958 return 0;
2959}
2960
2961static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2962{
2963 u8 val = 0;
2964 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2965
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302966 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302967 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2968 case SND_SOC_DAIFMT_CBS_CFS:
2969 /* CPU is master */
2970 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2971 if (dai->id == AIF1_CAP)
2972 snd_soc_update_bits(dai->codec,
2973 SITAR_A_CDC_CLK_TX_I2S_CTL,
2974 SITAR_I2S_MASTER_MODE_MASK, 0);
2975 else if (dai->id == AIF1_PB)
2976 snd_soc_update_bits(dai->codec,
2977 SITAR_A_CDC_CLK_RX_I2S_CTL,
2978 SITAR_I2S_MASTER_MODE_MASK, 0);
2979 }
2980 break;
2981 case SND_SOC_DAIFMT_CBM_CFM:
2982 /* CPU is slave */
2983 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2984 val = SITAR_I2S_MASTER_MODE_MASK;
2985 if (dai->id == AIF1_CAP)
2986 snd_soc_update_bits(dai->codec,
2987 SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
2988 else if (dai->id == AIF1_PB)
2989 snd_soc_update_bits(dai->codec,
2990 SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
2991 }
2992 break;
2993 default:
2994 return -EINVAL;
2995 }
2996 return 0;
2997}
2998static int sitar_set_channel_map(struct snd_soc_dai *dai,
2999 unsigned int tx_num, unsigned int *tx_slot,
3000 unsigned int rx_num, unsigned int *rx_slot)
3001
3002{
3003 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003004 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303005 if (!tx_slot && !rx_slot) {
3006 pr_err("%s: Invalid\n", __func__);
3007 return -EINVAL;
3008 }
3009 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3010
Kuirong Wang906ac472012-07-09 12:54:44 -07003011 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3012 wcd9xxx_init_slimslave(core, core->slim->laddr,
3013 tx_num, tx_slot, rx_num, rx_slot);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303014 return 0;
3015}
3016
3017static int sitar_get_channel_map(struct snd_soc_dai *dai,
3018 unsigned int *tx_num, unsigned int *tx_slot,
3019 unsigned int *rx_num, unsigned int *rx_slot)
3020
3021{
Kuirong Wang906ac472012-07-09 12:54:44 -07003022 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(dai->codec);
3023 u32 i = 0;
3024 struct wcd9xxx_ch *ch;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303025
Kuirong Wang906ac472012-07-09 12:54:44 -07003026 switch (dai->id) {
3027 case AIF1_PB:
3028 if (!rx_slot || !rx_num) {
3029 pr_err("%s: Invalid rx_slot 0x%x or rx_num 0x%x\n",
3030 __func__, (u32) rx_slot, (u32) rx_num);
3031 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303032 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003033 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3034 list) {
3035 rx_slot[i++] = ch->ch_num;
3036 }
3037 *rx_num = i;
3038 break;
3039 case AIF1_CAP:
3040 if (!tx_slot || !tx_num) {
3041 pr_err("%s: Invalid tx_slot 0x%x or tx_num 0x%x\n",
3042 __func__, (u32) tx_slot, (u32) tx_num);
3043 return -EINVAL;
3044 }
3045 list_for_each_entry(ch, &sitar_p->dai[dai->id].wcd9xxx_ch_list,
3046 list) {
3047 tx_slot[i++] = ch->ch_num;
3048 }
3049 *tx_num = i;
3050 break;
3051 default:
3052 pr_err("%s: Invalid dai %d", __func__, dai->id);
3053 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303054 }
3055 return 0;
3056}
3057
3058static int sitar_hw_params(struct snd_pcm_substream *substream,
3059 struct snd_pcm_hw_params *params,
3060 struct snd_soc_dai *dai)
3061{
3062 struct snd_soc_codec *codec = dai->codec;
3063 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
3064 u8 path, shift;
3065 u16 tx_fs_reg, rx_fs_reg;
3066 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
3067
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05303068 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303069
3070 switch (params_rate(params)) {
3071 case 8000:
3072 tx_fs_rate = 0x00;
3073 rx_fs_rate = 0x00;
3074 break;
3075 case 16000:
3076 tx_fs_rate = 0x01;
3077 rx_fs_rate = 0x20;
3078 break;
3079 case 32000:
3080 tx_fs_rate = 0x02;
3081 rx_fs_rate = 0x40;
3082 break;
3083 case 48000:
3084 tx_fs_rate = 0x03;
3085 rx_fs_rate = 0x60;
3086 break;
3087 default:
3088 pr_err("%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07003089 params_rate(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303090 return -EINVAL;
3091 }
3092
3093
3094 /**
3095 * If current dai is a tx dai, set sample rate to
3096 * all the txfe paths that are currently not active
3097 */
3098 if (dai->id == AIF1_CAP) {
3099
3100 tx_state = snd_soc_read(codec,
3101 SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3102
3103 for (path = 1, shift = 0;
3104 path <= NUM_DECIMATORS; path++, shift++) {
3105
3106 if (!(tx_state & (1 << shift))) {
3107 tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
3108 + (BITS_PER_REG*(path-1));
3109 snd_soc_update_bits(codec, tx_fs_reg,
3110 0x03, tx_fs_rate);
3111 }
3112 }
3113 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3114 switch (params_format(params)) {
3115 case SNDRV_PCM_FORMAT_S16_LE:
3116 snd_soc_update_bits(codec,
3117 SITAR_A_CDC_CLK_TX_I2S_CTL,
3118 0x20, 0x20);
3119 break;
3120 case SNDRV_PCM_FORMAT_S32_LE:
3121 snd_soc_update_bits(codec,
3122 SITAR_A_CDC_CLK_TX_I2S_CTL,
3123 0x20, 0x00);
3124 break;
3125 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003126 pr_err("%s: Unsupport format %d\n", __func__,
3127 params_format(params));
3128 return -EINVAL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303129 }
3130 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
3131 0x03, tx_fs_rate);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303132 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003133 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303134 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303135 }
3136
3137 /**
3138 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3139 * with varying sample rates
3140 */
3141
3142 /**
3143 * If current dai is a rx dai, set sample rate to
3144 * all the rx paths that are currently not active
3145 */
3146 if (dai->id == AIF1_PB) {
3147
3148 rx_state = snd_soc_read(codec,
3149 SITAR_A_CDC_CLK_RX_B1_CTL);
3150
3151 for (path = 1, shift = 0;
3152 path <= NUM_INTERPOLATORS; path++, shift++) {
3153
3154 if (!(rx_state & (1 << shift))) {
3155 rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
3156 + (BITS_PER_REG*(path-1));
3157 snd_soc_update_bits(codec, rx_fs_reg,
3158 0xE0, rx_fs_rate);
3159 }
3160 }
3161 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3162 switch (params_format(params)) {
3163 case SNDRV_PCM_FORMAT_S16_LE:
3164 snd_soc_update_bits(codec,
3165 SITAR_A_CDC_CLK_RX_I2S_CTL,
3166 0x20, 0x20);
3167 break;
3168 case SNDRV_PCM_FORMAT_S32_LE:
3169 snd_soc_update_bits(codec,
3170 SITAR_A_CDC_CLK_RX_I2S_CTL,
3171 0x20, 0x00);
3172 break;
3173 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07003174 pr_err("%s: Unsupport format %d\n", __func__,
3175 params_format(params));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303176 break;
3177 }
3178 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
3179 0x03, (rx_fs_rate >> 0x05));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303180 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07003181 sitar->dai[dai->id].rate = params_rate(params);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303182 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303183 }
3184
3185 return 0;
3186}
3187
3188static struct snd_soc_dai_ops sitar_dai_ops = {
3189 .startup = sitar_startup,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003190 .shutdown = sitar_shutdown,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303191 .hw_params = sitar_hw_params,
3192 .set_sysclk = sitar_set_dai_sysclk,
3193 .set_fmt = sitar_set_dai_fmt,
3194 .set_channel_map = sitar_set_channel_map,
3195 .get_channel_map = sitar_get_channel_map,
3196};
3197
3198static struct snd_soc_dai_driver sitar_dai[] = {
3199 {
3200 .name = "sitar_rx1",
3201 .id = AIF1_PB,
3202 .playback = {
3203 .stream_name = "AIF1 Playback",
3204 .rates = WCD9304_RATES,
3205 .formats = SITAR_FORMATS,
3206 .rate_max = 48000,
3207 .rate_min = 8000,
3208 .channels_min = 1,
3209 .channels_max = 2,
3210 },
3211 .ops = &sitar_dai_ops,
3212 },
3213 {
3214 .name = "sitar_tx1",
3215 .id = AIF1_CAP,
3216 .capture = {
3217 .stream_name = "AIF1 Capture",
3218 .rates = WCD9304_RATES,
3219 .formats = SITAR_FORMATS,
3220 .rate_max = 48000,
3221 .rate_min = 8000,
3222 .channels_min = 1,
3223 .channels_max = 2,
3224 },
3225 .ops = &sitar_dai_ops,
3226 },
3227};
3228
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05303229static struct snd_soc_dai_driver sitar_i2s_dai[] = {
3230 {
3231 .name = "sitar_i2s_rx1",
3232 .id = AIF1_PB,
3233 .playback = {
3234 .stream_name = "AIF1 Playback",
3235 .rates = WCD9304_RATES,
3236 .formats = SITAR_FORMATS,
3237 .rate_max = 192000,
3238 .rate_min = 8000,
3239 .channels_min = 1,
3240 .channels_max = 4,
3241 },
3242 .ops = &sitar_dai_ops,
3243 },
3244 {
3245 .name = "sitar_i2s_tx1",
3246 .id = AIF1_CAP,
3247 .capture = {
3248 .stream_name = "AIF1 Capture",
3249 .rates = WCD9304_RATES,
3250 .formats = SITAR_FORMATS,
3251 .rate_max = 192000,
3252 .rate_min = 8000,
3253 .channels_min = 1,
3254 .channels_max = 4,
3255 },
3256 .ops = &sitar_dai_ops,
3257 },
3258};
3259
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003260static int sitar_codec_enable_chmask(struct sitar_priv *sitar,
3261 int event, int index)
3262{
Kuirong Wang906ac472012-07-09 12:54:44 -07003263 int ret = 0;
3264 struct wcd9xxx_ch *ch;
3265
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003266 switch (event) {
3267 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003268 list_for_each_entry(ch,
3269 &sitar->dai[index].wcd9xxx_ch_list, list) {
3270 ret = wcd9xxx_get_slave_port(ch->ch_num);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003271 if (ret < 0) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003272 pr_err("%s: Invalid slave port ID: %d\n",
3273 __func__, ret);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003274 ret = -EINVAL;
3275 break;
3276 }
3277 sitar->dai[index].ch_mask |= 1 << ret;
3278 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003279 break;
3280 case SND_SOC_DAPM_POST_PMD:
3281 ret = wait_event_timeout(sitar->dai[index].dai_wait,
3282 (sitar->dai[index].ch_mask == 0),
Kuirong Wang906ac472012-07-09 12:54:44 -07003283 msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003284 if (!ret) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003285 pr_err("%s: Slim close tx/rx wait timeout\n",
3286 __func__);
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003287 ret = -EINVAL;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003288 } else {
3289 ret = 0;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003290 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003291 break;
3292 }
3293 return ret;
3294}
3295
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303296static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3297 struct snd_kcontrol *kcontrol, int event)
3298{
Kuirong Wang906ac472012-07-09 12:54:44 -07003299 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303300 struct snd_soc_codec *codec = w->codec;
3301 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003302 int ret = 0;
3303 struct wcd9xxx_codec_dai_data *dai;
3304
3305 core = dev_get_drvdata(codec->dev->parent);
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003306
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303307 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003308 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003309 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3310 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303311 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003312 }
3313
Kuirong Wang906ac472012-07-09 12:54:44 -07003314 dai = &sitar_p->dai[w->shift];
3315
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303316 switch (event) {
3317 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003318 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3319 w->shift);
3320 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3321 dai->rate, dai->bit_width,
3322 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303323 break;
3324 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003325 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3326 dai->grph);
3327 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3328 w->shift);
3329 if (ret < 0) {
3330 ret = wcd9xxx_disconnect_port(core,
3331 &dai->wcd9xxx_ch_list,
3332 dai->grph);
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003333 pr_info("%s: Disconnect RX port ret = %d\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07003334 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303335 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003336 if (core != NULL)
3337 sitar_codec_pm_runtime_put(core);
3338 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303339 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003340 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303341}
3342
3343static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3344 struct snd_kcontrol *kcontrol, int event)
3345{
Kuirong Wang906ac472012-07-09 12:54:44 -07003346 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303347 struct snd_soc_codec *codec = w->codec;
3348 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07003349 struct wcd9xxx_codec_dai_data *dai;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07003350 int ret = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303351
Kuirong Wang906ac472012-07-09 12:54:44 -07003352 core = dev_get_drvdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303353
3354 /* Execute the callback only if interface type is slimbus */
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003355 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07003356 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL))
3357 sitar_codec_pm_runtime_put(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303358 return 0;
Bhalchandra Gajareac580a92012-07-10 17:14:33 -07003359 }
3360
Kuirong Wang906ac472012-07-09 12:54:44 -07003361 dai = &sitar_p->dai[w->shift];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303362 switch (event) {
3363 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07003364 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMU,
3365 w->shift);
3366 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3367 dai->rate, dai->bit_width,
3368 &dai->grph);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303369 break;
3370 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07003371 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3372 dai->grph);
3373 ret = sitar_codec_enable_chmask(sitar_p, SND_SOC_DAPM_POST_PMD,
3374 w->shift);
3375 if (ret < 0) {
3376 ret = wcd9xxx_disconnect_port(core,
3377 &dai->wcd9xxx_ch_list,
3378 dai->grph);
3379 pr_info("%s: Disconnect RX port ret = %d\n",
3380 __func__, ret);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303381 }
Kuirong Wang906ac472012-07-09 12:54:44 -07003382 if (core != NULL)
3383 sitar_codec_pm_runtime_put(core);
3384 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303385 }
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07003386 return ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303387}
3388
3389
3390static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
3391{
3392 u8 bias_msb, bias_lsb;
3393 short bias_value;
3394
3395 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
3396 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
3397 bias_value = (bias_msb << 8) | bias_lsb;
3398 return bias_value;
3399}
3400
3401static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
3402{
3403 u8 bias_msb, bias_lsb;
3404 short bias_value;
3405
3406 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
3407 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
3408 bias_value = (bias_msb << 8) | bias_lsb;
3409 return bias_value;
3410}
3411
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003412static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
3413 bool on)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303414{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003415 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
3416}
3417
3418static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3419 bool override_bypass, bool noreldetection)
3420{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303421 short bias_value;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003422 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3423
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003424 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003425 if (noreldetection)
3426 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303427
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003428 /* Turn on the override */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003429 if (!override_bypass)
3430 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303431 if (dce) {
3432 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3433 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
3434 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003435 usleep_range(sitar->mbhc_data.t_sta_dce,
3436 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303437 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003438 usleep_range(sitar->mbhc_data.t_dce,
3439 sitar->mbhc_data.t_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303440 bias_value = sitar_codec_read_dce_result(codec);
3441 } else {
3442 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3443 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
3444 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003445 usleep_range(sitar->mbhc_data.t_sta_dce,
3446 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303447 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003448 usleep_range(sitar->mbhc_data.t_sta,
3449 sitar->mbhc_data.t_sta);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303450 bias_value = sitar_codec_read_sta_result(codec);
3451 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3452 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
3453 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003454 /* Turn off the override after measuring mic voltage */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003455 if (!override_bypass)
3456 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3457
3458 if (noreldetection)
3459 sitar_turn_onoff_rel_detection(codec, true);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003460 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303461
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303462 return bias_value;
3463}
3464
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003465static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
3466 bool norel)
3467{
3468 return __sitar_codec_sta_dce(codec, dce, false, norel);
3469}
3470
3471static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3472{
3473 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3474 const struct sitar_mbhc_general_cfg *generic =
3475 SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3476
3477 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
3478 sitar_codec_enable_config_mode(codec, 1);
3479
3480 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3481 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
3482
3483 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
3484
3485 usleep_range(generic->t_shutdown_plug_rem,
3486 generic->t_shutdown_plug_rem);
3487
3488 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
3489 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
3490 sitar_codec_enable_config_mode(codec, 0);
3491
3492 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
3493}
3494
3495static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
3496{
3497 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3498
3499 sitar_codec_shutdown_hs_removal_detect(codec);
3500
3501 if (!sitar->mclk_enabled) {
3502 sitar_codec_disable_clock_block(codec);
3503 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
3504 }
3505
3506 sitar->mbhc_polling_active = false;
3507 sitar->mbhc_state = MBHC_STATE_NONE;
3508}
3509
3510/* called only from interrupt which is under codec_resource_lock acquisition */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303511static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
3512{
3513 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303514 short bias_value;
3515 u8 cfilt_mode;
3516
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003517 if (!sitar->mbhc_cfg.calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303518 pr_err("Error, no sitar calibration\n");
3519 return -ENODEV;
3520 }
3521
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303522 if (!sitar->mclk_enabled) {
3523 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
3524 sitar_enable_rx_bias(codec, 1);
3525 sitar_codec_enable_clock_block(codec, 1);
3526 }
3527
3528 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
3529
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303530 /* Make sure CFILT is in fast mode, save current mode */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003531 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
3532 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
3533
3534 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303535
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303536 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3537 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
3538
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003539 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
3540 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
3541 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
3542
3543 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303544 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3545 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
3546
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003547 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303548 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3549
3550 sitar_codec_calibrate_hs_polling(codec);
3551
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003552 /* don't flip override */
3553 bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003554 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
3555 cfilt_mode);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303556 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
3557
3558 return bias_value;
3559}
3560
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003561static int sitar_cancel_btn_work(struct sitar_priv *sitar)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303562{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003563 int r = 0;
3564 struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303565
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003566 if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
3567 /* if scheduled mbhc_btn_dwork is canceled from here,
3568 * we have to unlock from here instead btn_work */
3569 wcd9xxx_unlock_sleep(core);
3570 r = 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303571 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003572 return r;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303573}
3574
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003575
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003576static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3577 s16 vin_mv)
3578{
3579 short diff, zero;
3580 struct sitar_priv *sitar;
3581 u32 mb_mv, in;
3582
3583 sitar = snd_soc_codec_get_drvdata(codec);
3584 mb_mv = sitar->mbhc_data.micb_mv;
3585
3586 if (mb_mv == 0) {
3587 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3588 return -EINVAL;
3589 }
3590
3591 if (dce) {
3592 diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
3593 zero = sitar->mbhc_data.dce_z;
3594 } else {
3595 diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
3596 zero = sitar->mbhc_data.sta_z;
3597 }
3598 in = (u32) diff * vin_mv;
3599
3600 return (u16) (in / mb_mv) + zero;
3601}
3602
3603static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3604 u16 bias_value)
3605{
3606 struct sitar_priv *sitar;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003607 s16 value, z, mb;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003608 s32 mv;
3609
3610 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003611 value = bias_value;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003612
3613 if (dce) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003614 z = (sitar->mbhc_data.dce_z);
3615 mb = (sitar->mbhc_data.dce_mb);
3616 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003617 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003618 z = (sitar->mbhc_data.sta_z);
3619 mb = (sitar->mbhc_data.sta_mb);
3620 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003621 }
3622
3623 return mv;
3624}
3625
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003626static void btn_lpress_fn(struct work_struct *work)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303627{
3628 struct delayed_work *delayed_work;
3629 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003630 short bias_value;
3631 int dce_mv, sta_mv;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003632 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303633
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003634 pr_debug("%s:\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303635
3636 delayed_work = to_delayed_work(work);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003637 sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003638 core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303639
3640 if (sitar) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003641 if (sitar->mbhc_cfg.button_jack) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003642 bias_value = sitar_codec_read_sta_result(sitar->codec);
3643 sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003644 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003645 bias_value = sitar_codec_read_dce_result(sitar->codec);
3646 dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003647 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003648 pr_debug("%s: Reporting long button press event"
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003649 " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
3650 sitar_snd_soc_jack_report(sitar,
3651 sitar->mbhc_cfg.button_jack,
3652 sitar->buttons_pressed,
3653 sitar->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303654 }
3655 } else {
3656 pr_err("%s: Bad sitar private data\n", __func__);
3657 }
3658
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003659 pr_debug("%s: leave\n", __func__);
3660 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303661}
3662
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003663
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003664void sitar_mbhc_cal(struct snd_soc_codec *codec)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303665{
3666 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003667 struct sitar_mbhc_btn_detect_cfg *btn_det;
3668 u8 cfilt_mode, bg_mode;
3669 u8 ncic, nmeas, navg;
3670 u32 mclk_rate;
3671 u32 dce_wait, sta_wait;
3672 u8 *n_cic;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003673 void *calibration;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003674
3675 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003676 calibration = sitar->mbhc_cfg.calibration;
3677
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003678 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003679 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003680
3681 /* First compute the DCE / STA wait times
3682 * depending on tunable parameters.
3683 * The value is computed in microseconds
3684 */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003685 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003686 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3687 ncic = n_cic[sitar_codec_mclk_index(sitar)];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003688 nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
3689 navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
3690 mclk_rate = sitar->mbhc_cfg.mclk_rate;
3691 dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003692 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
3693
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003694 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
3695 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003696
3697 /* LDOH and CFILT are already configured during pdata handling.
3698 * Only need to make sure CFILT and bandgap are in Fast mode.
3699 * Need to restore defaults once calculation is done.
3700 */
3701 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
3702 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3703 bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
3704 0x02);
3705
3706 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3707 * to perform ADC calibration
3708 */
3709 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003710 sitar->mbhc_cfg.micbias << 5);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003711 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3712 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003713 snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003714 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3715
3716 /* DCE measurement for 0 volts */
3717 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3718 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3719 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3720 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
3721 usleep_range(100, 100);
3722 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3723 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
3724 sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
3725
3726 /* DCE measurment for MB voltage */
3727 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3728 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3729 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
3730 usleep_range(100, 100);
3731 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
3732 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
3733 sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
3734
3735 /* Sta measuremnt for 0 volts */
3736 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
3737 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3738 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
3739 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
3740 usleep_range(100, 100);
3741 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3742 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
3743 sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
3744
3745 /* STA Measurement for MB Voltage */
3746 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
3747 usleep_range(100, 100);
3748 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
3749 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
3750 sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
3751
3752 /* Restore default settings. */
3753 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3754 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
3755 cfilt_mode);
3756 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3757
3758 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
3759 usleep_range(100, 100);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003760
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003761 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003762 sitar_turn_onoff_rel_detection(codec, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003763}
3764
3765void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
3766 const enum sitar_mbhc_btn_det_mem mem)
3767{
3768 void *ret = &btn_det->_v_btn_low;
3769
3770 switch (mem) {
3771 case SITAR_BTN_DET_GAIN:
3772 ret += sizeof(btn_det->_n_cic);
3773 case SITAR_BTN_DET_N_CIC:
3774 ret += sizeof(btn_det->_n_ready);
3775 case SITAR_BTN_DET_N_READY:
3776 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3777 case SITAR_BTN_DET_V_BTN_HIGH:
3778 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3779 case SITAR_BTN_DET_V_BTN_LOW:
3780 /* do nothing */
3781 break;
3782 default:
3783 ret = NULL;
3784 }
3785
3786 return ret;
3787}
3788
3789static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
3790{
3791 struct sitar_priv *sitar;
3792 s16 btn_mv = 0, btn_delta_mv;
3793 struct sitar_mbhc_btn_detect_cfg *btn_det;
3794 struct sitar_mbhc_plug_type_cfg *plug_type;
3795 u16 *btn_high;
3796 u8 *n_ready;
3797 int i;
3798
3799 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003800 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
3801 plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003802
3803 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003804 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003805 sitar->mbhc_data.npoll = 9;
3806 sitar->mbhc_data.nbounce_wait = 30;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003807 } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003808 sitar->mbhc_data.npoll = 7;
3809 sitar->mbhc_data.nbounce_wait = 23;
3810 }
3811
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003812 sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
3813 (sitar->mbhc_cfg.mclk_rate / 1000) *
3814 n_ready[sitar_codec_mclk_index(sitar)]) +
3815 10;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003816 sitar->mbhc_data.v_ins_hu =
3817 sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3818 sitar->mbhc_data.v_ins_h =
3819 sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3820
3821 btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
3822 for (i = 0; i < btn_det->num_btn; i++)
3823 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3824
3825 sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
3826 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3827
3828 sitar->mbhc_data.v_b1_hu =
3829 sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
3830
3831 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3832
3833 sitar->mbhc_data.v_b1_huc =
3834 sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3835
3836 sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003837 sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003838
3839 sitar->mbhc_data.v_no_mic =
3840 sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3841}
3842
3843void sitar_mbhc_init(struct snd_soc_codec *codec)
3844{
3845 struct sitar_priv *sitar;
3846 struct sitar_mbhc_general_cfg *generic;
3847 struct sitar_mbhc_btn_detect_cfg *btn_det;
3848 int n;
3849 u8 *n_cic, *gain;
3850
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003851 pr_err("%s(): ENTER\n", __func__);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003852 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003853 generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3854 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003855
3856 for (n = 0; n < 8; n++) {
3857 if (n != 7) {
3858 snd_soc_update_bits(codec,
3859 SITAR_A_CDC_MBHC_FIR_B1_CFG,
3860 0x07, n);
3861 snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
3862 btn_det->c[n]);
3863 }
3864 }
3865 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
3866 btn_det->nc);
3867
3868 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3869 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
3870 n_cic[sitar_codec_mclk_index(sitar)]);
3871
3872 gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
3873 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
3874 gain[sitar_codec_mclk_index(sitar)] << 3);
3875
3876 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3877 generic->mbhc_nsa << 4);
3878
3879 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3880 btn_det->n_meas);
3881
3882 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3883
3884 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3885
3886 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
3887 btn_det->mbhc_nsc << 3);
3888
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003889 snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
3890 sitar->mbhc_cfg.micbias);
3891
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003892 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003893
3894 snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
3895
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003896}
3897
3898static bool sitar_mbhc_fw_validate(const struct firmware *fw)
3899{
3900 u32 cfg_offset;
3901 struct sitar_mbhc_imped_detect_cfg *imped_cfg;
3902 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
3903
3904 if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
3905 return false;
3906
3907 /* previous check guarantees that there is enough fw data up
3908 * to num_btn
3909 */
3910 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
3911 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3912 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
3913 return false;
3914
3915 /* previous check guarantees that there is enough fw data up
3916 * to start of impedance detection configuration
3917 */
3918 imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
3919 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3920
3921 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
3922 return false;
3923
3924 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
3925 return false;
3926
3927 return true;
3928}
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003929
3930
3931static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
3932{
3933 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
3934}
3935
3936/* called under codec_resource_lock acquisition */
3937void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
3938{
3939 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3940 u8 wg_time;
3941
3942 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
3943 wg_time += 1;
3944
3945 /* If headphone PA is on, check if userspace receives
3946 * removal event to sync-up PA's state */
3947 if (sitar_is_hph_pa_on(codec)) {
3948 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
3949 set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
3950 set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
3951 } else {
3952 pr_debug("%s PA is off\n", __func__);
3953 }
3954
3955 if (sitar_is_hph_dac_on(codec, 1))
3956 set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
3957 if (sitar_is_hph_dac_on(codec, 0))
3958 set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
3959
3960 snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
3961 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
3962 0xC0, 0x00);
3963 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
3964 0xC0, 0x00);
3965 usleep_range(wg_time * 1000, wg_time * 1000);
3966}
3967
3968static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
3969{
3970 bool pa_turned_on = false;
3971 struct snd_soc_codec *codec = sitar->codec;
3972 u8 wg_time;
3973
3974 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
3975 wg_time += 1;
3976
3977 if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
3978 &sitar->hph_pa_dac_state)) {
3979 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
3980 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
3981 0xC0, 0xC0);
3982 }
3983 if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
3984 &sitar->hph_pa_dac_state)) {
3985 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
3986 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
3987 0xC0, 0xC0);
3988 }
3989
3990 if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
3991 &sitar->hph_pa_dac_state)) {
3992 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
3993 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
3994 1 << 4);
3995 pa_turned_on = true;
3996 }
3997 if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
3998 &sitar->hph_pa_dac_state)) {
3999 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4000 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
4001 1 << 5);
4002 pa_turned_on = true;
4003 }
4004
4005 if (pa_turned_on) {
4006 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4007 __func__);
4008 usleep_range(wg_time * 1000, wg_time * 1000);
4009 }
4010}
4011
4012static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4013 enum snd_jack_types jack_type)
4014{
4015 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4016
4017 if (!insertion) {
4018 /* Report removal */
4019 sitar->hph_status &= ~jack_type;
4020 if (sitar->mbhc_cfg.headset_jack) {
4021 /* cancel possibly scheduled btn work and
4022 * report release if we reported button press */
4023 if (sitar_cancel_btn_work(sitar)) {
4024 pr_debug("%s: button press is canceled\n",
4025 __func__);
4026 } else if (sitar->buttons_pressed) {
4027 pr_debug("%s: Reporting release for reported "
4028 "button press %d\n", __func__,
4029 jack_type);
4030 sitar_snd_soc_jack_report(sitar,
4031 sitar->mbhc_cfg.button_jack, 0,
4032 sitar->buttons_pressed);
4033 sitar->buttons_pressed &=
4034 ~SITAR_JACK_BUTTON_MASK;
4035 }
4036 pr_debug("%s: Reporting removal %d\n", __func__,
4037 jack_type);
4038 sitar_snd_soc_jack_report(sitar,
4039 sitar->mbhc_cfg.headset_jack,
4040 sitar->hph_status,
4041 SITAR_JACK_MASK);
4042 }
4043 sitar_set_and_turnoff_hph_padac(codec);
4044 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004045 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004046 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004047 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004048 sitar->current_plug = PLUG_TYPE_NONE;
4049 sitar->mbhc_polling_active = false;
4050 } else {
4051 /* Report insertion */
4052 sitar->hph_status |= jack_type;
4053
4054 if (jack_type == SND_JACK_HEADPHONE)
4055 sitar->current_plug = PLUG_TYPE_HEADPHONE;
4056 else if (jack_type == SND_JACK_HEADSET) {
4057 sitar->mbhc_polling_active = true;
4058 sitar->current_plug = PLUG_TYPE_HEADSET;
4059 }
4060 if (sitar->mbhc_cfg.headset_jack) {
4061 pr_debug("%s: Reporting insertion %d\n", __func__,
4062 jack_type);
4063 sitar_snd_soc_jack_report(sitar,
4064 sitar->mbhc_cfg.headset_jack,
4065 sitar->hph_status,
4066 SITAR_JACK_MASK);
4067 }
4068 sitar_clr_and_turnon_hph_padac(sitar);
4069 }
4070}
4071
4072
4073static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
4074{
4075 return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
4076 sitar->mbhc_cfg.gpio_level_insert);
4077}
4078
4079static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
4080 int mic_volt, int mic_volt_prev)
4081{
4082 int delta = abs(mic_volt - mic_volt_prev);
4083 if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
4084 pr_debug("%s: volt delta %dmv\n", __func__, delta);
4085 return true;
4086 }
4087 return false;
4088}
4089
4090static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
4091 s32 mic_volt)
4092{
4093 bool invalid = false;
4094
4095 if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
4096 && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
4097 invalid = true;
4098 }
4099
4100 return invalid;
4101}
4102
4103static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
4104 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
4105 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
4106{
4107 int i;
4108 bool r = false;
4109 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4110 struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
4111 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4112
4113 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
4114 if (mic_mv[i] < plug_type_ptr->v_no_mic)
4115 plug_type[i] = PLUG_TYPE_HEADPHONE;
4116 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
4117 plug_type[i] = PLUG_TYPE_HEADSET;
4118 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
4119 plug_type[i] = PLUG_TYPE_HIGH_HPH;
4120
4121 r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
4122 if (!r && i > 0) {
4123 if (plug_type[i-1] != plug_type[i])
4124 r = true;
4125 else
4126 r = sitar_is_invalid_insert_delta(codec,
4127 mic_mv[i],
4128 mic_mv[i - 1]);
4129 }
4130 }
4131
4132 return r;
4133}
4134
4135/* called under codec_resource_lock acquisition */
4136void sitar_find_plug_and_report(struct snd_soc_codec *codec,
4137 enum sitar_mbhc_plug_type plug_type)
4138{
4139 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4140
4141 if (plug_type == PLUG_TYPE_HEADPHONE
4142 && sitar->current_plug == PLUG_TYPE_NONE) {
4143 /* Nothing was reported previously
4144 * reporte a headphone
4145 */
4146 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4147 sitar_codec_cleanup_hs_polling(codec);
4148 } else if (plug_type == PLUG_TYPE_HEADSET) {
4149 /* If Headphone was reported previously, this will
4150 * only report the mic line
4151 */
4152 sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
4153 msleep(100);
4154 sitar_codec_start_hs_polling(codec);
4155 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
4156 if (sitar->current_plug == PLUG_TYPE_NONE)
4157 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4158 sitar_codec_cleanup_hs_polling(codec);
4159 pr_debug("setup mic trigger for further detection\n");
4160 sitar->lpi_enabled = true;
4161 /* TODO ::: sitar_codec_enable_hs_detect */
4162 pr_err("%s(): High impedence hph not supported\n", __func__);
4163 }
4164}
4165
4166/* should be called under interrupt context that hold suspend */
4167static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
4168{
4169 pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
4170 sitar->hs_detect_work_stop = false;
4171 wcd9xxx_lock_sleep(sitar->codec->control_data);
4172 schedule_work(&sitar->hs_correct_plug_work);
4173}
4174
4175/* called under codec_resource_lock acquisition */
4176static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
4177{
4178 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
4179 sitar->hs_detect_work_stop = true;
4180 wmb();
4181 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4182 if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
4183 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
4184 wcd9xxx_unlock_sleep(sitar->codec->control_data);
4185 }
4186 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4187}
4188
4189static void sitar_hs_correct_gpio_plug(struct work_struct *work)
4190{
4191 struct sitar_priv *sitar;
4192 struct snd_soc_codec *codec;
4193 int retry = 0, i;
4194 bool correction = false;
4195 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4196 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4197 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4198 unsigned long timeout;
4199
4200 sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
4201 codec = sitar->codec;
4202
4203 pr_debug("%s: enter\n", __func__);
4204 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4205
4206 /* Keep override on during entire plug type correction work.
4207 *
4208 * This is okay under the assumption that any GPIO irqs which use
4209 * MBHC block cancel and sync this work so override is off again
4210 * prior to GPIO interrupt handler's MBHC block usage.
4211 * Also while this correction work is running, we can guarantee
4212 * DAPM doesn't use any MBHC block as this work only runs with
4213 * headphone detection.
4214 */
4215 sitar_turn_onoff_override(codec, true);
4216
4217 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4218 while (!time_after(jiffies, timeout)) {
4219 ++retry;
4220 rmb();
4221 if (sitar->hs_detect_work_stop) {
4222 pr_debug("%s: stop requested\n", __func__);
4223 break;
4224 }
4225
4226 msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
4227 if (sitar_hs_gpio_level_remove(sitar)) {
4228 pr_debug("%s: GPIO value is low\n", __func__);
4229 break;
4230 }
4231
4232 /* can race with removal interrupt */
4233 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4234 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4235 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4236 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4237 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
4238 __func__, retry, mic_mv[i], mb_v[i]);
4239 }
4240 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4241
4242 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4243 pr_debug("Invalid plug in attempt # %d\n", retry);
4244 if (retry == NUM_ATTEMPTS_TO_REPORT &&
4245 sitar->current_plug == PLUG_TYPE_NONE) {
4246 sitar_codec_report_plug(codec, 1,
4247 SND_JACK_HEADPHONE);
4248 }
4249 } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
4250 plug_type) &&
4251 plug_type[0] == PLUG_TYPE_HEADPHONE) {
4252 pr_debug("Good headphone detected, continue polling mic\n");
4253 if (sitar->current_plug == PLUG_TYPE_NONE) {
4254 sitar_codec_report_plug(codec, 1,
4255 SND_JACK_HEADPHONE);
4256 }
4257 } else {
4258 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
4259 /* Turn off override */
4260 sitar_turn_onoff_override(codec, false);
4261 sitar_find_plug_and_report(codec, plug_type[0]);
4262 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
4263 pr_debug("Attempt %d found correct plug %d\n", retry,
4264 plug_type[0]);
4265 correction = true;
4266 break;
4267 }
4268 }
4269
4270 /* Turn off override */
4271 if (!correction)
4272 sitar_turn_onoff_override(codec, false);
4273
4274 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4275 pr_debug("%s: leave\n", __func__);
4276 /* unlock sleep */
4277 wcd9xxx_unlock_sleep(sitar->codec->control_data);
4278}
4279
4280/* called under codec_resource_lock acquisition */
4281static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
4282{
4283 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4284 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4285 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4286 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
4287 int i;
4288
4289 pr_debug("%s: enter\n", __func__);
4290
4291 sitar_turn_onoff_override(codec, true);
4292 mb_v[0] = sitar_codec_setup_hs_polling(codec);
4293 mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
4294 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
4295
4296 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4297 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4298 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4299 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
4300 mic_mv[i]);
4301 }
4302 sitar_turn_onoff_override(codec, false);
4303
4304 if (sitar_hs_gpio_level_remove(sitar)) {
4305 pr_debug("%s: GPIO value is low when determining plug\n",
4306 __func__);
4307 return;
4308 }
4309
4310 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
4311 sitar_schedule_hs_detect_plug(sitar);
4312 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
4313 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
4314 sitar_schedule_hs_detect_plug(sitar);
4315 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
4316 pr_debug("%s: Valid plug found, determine plug type\n",
4317 __func__);
4318 sitar_find_plug_and_report(codec, plug_type[0]);
4319 }
4320
4321}
4322
4323/* called under codec_resource_lock acquisition */
4324static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
4325{
4326 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4327 const struct sitar_mbhc_plug_detect_cfg *plug_det =
4328 SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
4329
4330 if (plug_det->t_ins_complete > 20)
4331 msleep(plug_det->t_ins_complete);
4332 else
4333 usleep_range(plug_det->t_ins_complete * 1000,
4334 plug_det->t_ins_complete * 1000);
4335
4336 if (sitar_hs_gpio_level_remove(sitar))
4337 pr_debug("%s: GPIO value is low when determining "
4338 "plug\n", __func__);
4339 else
4340 sitar_codec_decide_gpio_plug(codec);
4341
4342 return;
4343}
4344
4345static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
4346{
4347 bool insert;
4348 struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
4349 bool is_removed = false;
4350
4351 pr_debug("%s: enter\n", __func__);
4352
4353 priv->in_gpio_handler = true;
4354 /* Wait here for debounce time */
4355 usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
4356 SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
4357
4358 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4359
4360 /* cancel pending button press */
4361 if (sitar_cancel_btn_work(priv))
4362 pr_debug("%s: button press is canceled\n", __func__);
4363
4364 insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4365 priv->mbhc_cfg.gpio_level_insert);
4366 if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
4367 priv->lpi_enabled = false;
4368 wmb();
4369
4370 /* cancel detect plug */
4371 sitar_cancel_hs_detect_plug(priv);
4372
4373 /* Disable Mic Bias pull down and HPH Switch to GND */
4374 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
4375 0x00);
4376 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
4377 sitar_codec_detect_plug_type(codec);
4378 } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
4379 priv->lpi_enabled = false;
4380 wmb();
4381
4382 /* cancel detect plug */
4383 sitar_cancel_hs_detect_plug(priv);
4384
4385 if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
4386 sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
4387 is_removed = true;
4388 } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
4389 sitar_codec_pause_hs_polling(codec);
4390 sitar_codec_cleanup_hs_polling(codec);
4391 sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
4392 is_removed = true;
4393 }
4394
4395 if (is_removed) {
4396 /* Enable Mic Bias pull down and HPH Switch to GND */
4397 snd_soc_update_bits(codec,
4398 priv->mbhc_bias_regs.ctl_reg, 0x01,
4399 0x01);
4400 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
4401 0x01);
4402 /* Make sure mic trigger is turned off */
4403 snd_soc_update_bits(codec,
4404 priv->mbhc_bias_regs.ctl_reg,
4405 0x01, 0x01);
4406 snd_soc_update_bits(codec,
4407 priv->mbhc_bias_regs.mbhc_reg,
4408 0x90, 0x00);
4409 /* Reset MBHC State Machine */
4410 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4411 0x08, 0x08);
4412 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
4413 0x08, 0x00);
4414 /* Turn off override */
4415 sitar_turn_onoff_override(codec, false);
4416 }
4417 }
4418
4419 priv->in_gpio_handler = false;
4420 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4421 pr_debug("%s: leave\n", __func__);
4422}
4423
4424static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
4425{
4426 int r = IRQ_HANDLED;
4427 struct snd_soc_codec *codec = data;
4428
4429 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
4430 pr_warn("%s(): Failed to hold suspend\n", __func__);
4431 r = IRQ_NONE;
4432 } else {
4433 sitar_hs_gpio_handler(codec);
4434 wcd9xxx_unlock_sleep(codec->control_data);
4435 }
4436 return r;
4437}
4438
4439static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
4440{
4441 int rc = 0;
4442 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4443
4444 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
4445 sitar_mbhc_init(codec);
4446 sitar_mbhc_cal(codec);
4447 sitar_mbhc_calc_thres(codec);
4448 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
4449 sitar_codec_calibrate_hs_polling(codec);
4450
4451 /* Enable Mic Bias pull down and HPH Switch to GND */
4452 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
4453 0x01, 0x01);
4454 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
4455 0x01, 0x01);
4456
4457 rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
4458 NULL,
4459 sitar_mechanical_plug_detect_irq,
4460 (IRQF_TRIGGER_RISING |
4461 IRQF_TRIGGER_FALLING),
4462 "sitar-hs-gpio", codec);
4463
4464 if (!IS_ERR_VALUE(rc)) {
4465 rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
4466 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
4467 0x10, 0x10);
4468 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004469 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004470 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004471 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004472 /* Bootup time detection */
4473 sitar_hs_gpio_handler(codec);
4474 }
4475
4476 return rc;
4477}
4478
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004479static void mbhc_fw_read(struct work_struct *work)
4480{
4481 struct delayed_work *dwork;
4482 struct sitar_priv *sitar;
4483 struct snd_soc_codec *codec;
4484 const struct firmware *fw;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004485 int ret = -1, retry = 0;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004486
4487 dwork = to_delayed_work(work);
4488 sitar = container_of(dwork, struct sitar_priv,
4489 mbhc_firmware_dwork);
4490 codec = sitar->codec;
4491
4492 while (retry < MBHC_FW_READ_ATTEMPTS) {
4493 retry++;
4494 pr_info("%s:Attempt %d to request MBHC firmware\n",
4495 __func__, retry);
4496 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
4497 codec->dev);
4498
4499 if (ret != 0) {
4500 usleep_range(MBHC_FW_READ_TIMEOUT,
4501 MBHC_FW_READ_TIMEOUT);
4502 } else {
4503 pr_info("%s: MBHC Firmware read succesful\n", __func__);
4504 break;
4505 }
4506 }
4507
4508 if (ret != 0) {
4509 pr_err("%s: Cannot load MBHC firmware use default cal\n",
4510 __func__);
4511 } else if (sitar_mbhc_fw_validate(fw) == false) {
4512 pr_err("%s: Invalid MBHC cal data size use default cal\n",
4513 __func__);
4514 release_firmware(fw);
4515 } else {
4516 sitar->calibration = (void *)fw->data;
4517 sitar->mbhc_fw = fw;
4518 }
4519
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004520 sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004521}
4522
4523int sitar_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004524 const struct sitar_mbhc_config *cfg)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004525{
4526 struct sitar_priv *sitar;
4527 int rc = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304528
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004529 if (!codec || !cfg->calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304530 pr_err("Error: no codec or calibration\n");
4531 return -EINVAL;
4532 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004533
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004534 if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
4535 if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004536 pr_err("Error: clock rate %dHz is not yet supported\n",
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004537 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004538 else
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004539 pr_err("Error: unsupported clock rate %d\n",
4540 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004541 return -EINVAL;
4542 }
4543
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304544 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004545 sitar->mbhc_cfg = *cfg;
4546 sitar->in_gpio_handler = false;
4547 sitar->current_plug = PLUG_TYPE_NONE;
4548 sitar->lpi_enabled = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304549 sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
4550
4551 /* Put CFILT in fast mode by default */
4552 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004553 0x40, SITAR_CFILT_FAST_MODE);
4554
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004555 INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004556 INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304557 INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
4558 INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004559 INIT_WORK(&sitar->hs_correct_plug_work,
4560 sitar_hs_correct_gpio_plug);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004561
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004562 if (!sitar->mbhc_cfg.read_fw_bin) {
4563 rc = sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004564 } else {
4565 schedule_delayed_work(&sitar->mbhc_firmware_dwork,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004566 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304567 }
4568
4569 return rc;
4570}
4571EXPORT_SYMBOL_GPL(sitar_hs_detect);
4572
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004573static int sitar_determine_button(const struct sitar_priv *priv,
4574 const s32 bias_mv)
4575{
4576 s16 *v_btn_low, *v_btn_high;
4577 struct sitar_mbhc_btn_detect_cfg *btn_det;
4578 int i, btn = -1;
4579
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004580 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004581 v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
4582 v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
4583 SITAR_BTN_DET_V_BTN_HIGH);
4584 for (i = 0; i < btn_det->num_btn; i++) {
4585 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4586 btn = i;
4587 break;
4588 }
4589 }
4590
4591 if (btn == -1)
4592 pr_debug("%s: couldn't find button number for mic mv %d\n",
4593 __func__, bias_mv);
4594
4595 return btn;
4596}
4597
4598static int sitar_get_button_mask(const int btn)
4599{
4600 int mask = 0;
4601 switch (btn) {
4602 case 0:
4603 mask = SND_JACK_BTN_0;
4604 break;
4605 case 1:
4606 mask = SND_JACK_BTN_1;
4607 break;
4608 case 2:
4609 mask = SND_JACK_BTN_2;
4610 break;
4611 case 3:
4612 mask = SND_JACK_BTN_3;
4613 break;
4614 case 4:
4615 mask = SND_JACK_BTN_4;
4616 break;
4617 case 5:
4618 mask = SND_JACK_BTN_5;
4619 break;
4620 case 6:
4621 mask = SND_JACK_BTN_6;
4622 break;
4623 case 7:
4624 mask = SND_JACK_BTN_7;
4625 break;
4626 }
4627 return mask;
4628}
4629
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004630
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304631static irqreturn_t sitar_dce_handler(int irq, void *data)
4632{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004633 int i, mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004634 short dce, sta, bias_value_dce;
4635 s32 mv, stamv, bias_mv_dce;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004636 int btn = -1, meas = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304637 struct sitar_priv *priv = data;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004638 const struct sitar_mbhc_btn_detect_cfg *d =
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004639 SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004640 short btnmeas[d->n_btn_meas + 1];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304641 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08004642 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004643 int n_btn_meas = d->n_btn_meas;
4644 u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304645
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004646 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304647
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004648 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4649 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
4650 pr_debug("%s: mbhc is being recovered, skip button press\n",
4651 __func__);
4652 goto done;
4653 }
4654
4655 priv->mbhc_state = MBHC_STATE_POTENTIAL;
4656
4657 if (!priv->mbhc_polling_active) {
4658 pr_warn("%s: mbhc polling is not active, skip button press\n",
4659 __func__);
4660 goto done;
4661 }
4662
4663 dce = sitar_codec_read_dce_result(codec);
4664 mv = sitar_codec_sta_dce_v(codec, 1, dce);
4665
4666 /* If GPIO interrupt already kicked in, ignore button press */
4667 if (priv->in_gpio_handler) {
4668 pr_debug("%s: GPIO State Changed, ignore button press\n",
4669 __func__);
4670 btn = -1;
4671 goto done;
4672 }
4673
4674 if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
4675 if (priv->mbhc_last_resume &&
4676 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
4677 pr_debug("%s: Button is already released shortly after "
4678 "resume\n", __func__);
4679 n_btn_meas = 0;
4680 } else {
4681 pr_debug("%s: Button is already released without "
4682 "resume", __func__);
4683 sta = sitar_codec_read_sta_result(codec);
4684 stamv = sitar_codec_sta_dce_v(codec, 0, sta);
4685 btn = sitar_determine_button(priv, mv);
4686 if (btn != sitar_determine_button(priv, stamv))
4687 btn = -1;
4688 goto done;
4689 }
4690 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304691
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004692 /* determine pressed button */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004693 btnmeas[meas++] = sitar_determine_button(priv, mv);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004694 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004695 meas - 1, dce, mv, btnmeas[meas - 1]);
4696 if (n_btn_meas == 0)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004697 btn = btnmeas[0];
4698 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004699 bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004700 bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
4701 btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
4702 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
4703 __func__, meas, bias_value_dce, bias_mv_dce,
4704 btnmeas[meas]);
4705 /* if large enough measurements are collected,
4706 * start to check if last all n_btn_con measurements were
4707 * in same button low/high range */
4708 if (meas + 1 >= d->n_btn_con) {
4709 for (i = 0; i < d->n_btn_con; i++)
4710 if ((btnmeas[meas] < 0) ||
4711 (btnmeas[meas] != btnmeas[meas - i]))
4712 break;
4713 if (i == d->n_btn_con) {
4714 /* button pressed */
4715 btn = btnmeas[meas];
4716 break;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004717 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
4718 /* if left measurements are less than n_btn_con,
4719 * it's impossible to find button number */
4720 break;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004721 }
4722 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004723 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304724
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004725 if (btn >= 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004726 if (priv->in_gpio_handler) {
4727 pr_debug("%s: GPIO already triggered, ignore button "
4728 "press\n", __func__);
4729 goto done;
4730 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004731 mask = sitar_get_button_mask(btn);
4732 priv->buttons_pressed |= mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004733 wcd9xxx_lock_sleep(core);
4734 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
4735 msecs_to_jiffies(400)) == 0) {
4736 WARN(1, "Button pressed twice without release"
4737 "event\n");
4738 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004739 }
4740 } else {
4741 pr_debug("%s: bogus button press, too short press?\n",
4742 __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304743 }
4744
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004745 done:
4746 pr_debug("%s: leave\n", __func__);
4747 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304748 return IRQ_HANDLED;
4749}
4750
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004751static int sitar_is_fake_press(struct sitar_priv *priv)
4752{
4753 int i;
4754 int r = 0;
4755 struct snd_soc_codec *codec = priv->codec;
4756 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
4757 short mb_v;
4758
4759 for (i = 0; i < dces; i++) {
4760 usleep_range(10000, 10000);
4761 if (i == 0) {
4762 mb_v = sitar_codec_sta_dce(codec, 0, true);
4763 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
4764 sitar_codec_sta_dce_v(codec, 0, mb_v));
4765 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4766 mb_v > (short)priv->mbhc_data.v_ins_hu) {
4767 r = 1;
4768 break;
4769 }
4770 } else {
4771 mb_v = sitar_codec_sta_dce(codec, 1, true);
4772 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
4773 sitar_codec_sta_dce_v(codec, 1, mb_v));
4774 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
4775 mb_v > (short)priv->mbhc_data.v_ins_h) {
4776 r = 1;
4777 break;
4778 }
4779 }
4780 }
4781
4782 return r;
4783}
4784
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304785static irqreturn_t sitar_release_handler(int irq, void *data)
4786{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004787 int ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304788 struct sitar_priv *priv = data;
4789 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304790
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004791 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304792
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004793 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4794 priv->mbhc_state = MBHC_STATE_RELEASE;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304795
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004796 if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
4797 ret = sitar_cancel_btn_work(priv);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304798 if (ret == 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004799 pr_debug("%s: Reporting long button release event\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004800 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004801 if (priv->mbhc_cfg.button_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304802 sitar_snd_soc_jack_report(priv,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004803 priv->mbhc_cfg.button_jack, 0,
4804 priv->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304805 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004806 if (sitar_is_fake_press(priv)) {
4807 pr_debug("%s: Fake button press interrupt\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004808 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004809 } else if (priv->mbhc_cfg.button_jack) {
4810 if (priv->in_gpio_handler) {
4811 pr_debug("%s: GPIO kicked in, ignore\n",
4812 __func__);
4813 } else {
4814 pr_debug("%s: Reporting short button 0 "
4815 "press and release\n",
4816 __func__);
4817 sitar_snd_soc_jack_report(priv,
4818 priv->mbhc_cfg.button_jack,
4819 priv->buttons_pressed,
4820 priv->buttons_pressed);
4821 sitar_snd_soc_jack_report(priv,
4822 priv->mbhc_cfg.button_jack, 0,
4823 priv->buttons_pressed);
4824 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304825 }
4826 }
4827
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004828 priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
4829 }
4830
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004831 sitar_codec_calibrate_hs_polling(codec);
4832
4833 if (priv->mbhc_cfg.gpio)
4834 msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
4835
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304836 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004837
4838 pr_debug("%s: leave\n", __func__);
4839 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4840
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304841 return IRQ_HANDLED;
4842}
4843
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304844static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
4845{
4846 struct sitar_priv *sitar = data;
4847 struct snd_soc_codec *codec;
4848
4849 pr_info("%s: received HPHL OCP irq\n", __func__);
4850
4851 if (sitar) {
4852 codec = sitar->codec;
4853 if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
4854 pr_info("%s: retry\n", __func__);
4855 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004856 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304857 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004858 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304859 } else {
4860 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004861 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304862 sitar->hphlocp_cnt = 0;
4863 sitar->hph_status |= SND_JACK_OC_HPHL;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004864 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304865 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004866 sitar->mbhc_cfg.headset_jack,
4867 sitar->hph_status,
4868 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304869 }
4870 } else {
4871 pr_err("%s: Bad sitar private data\n", __func__);
4872 }
4873
4874 return IRQ_HANDLED;
4875}
4876
4877static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
4878{
4879 struct sitar_priv *sitar = data;
4880 struct snd_soc_codec *codec;
4881
4882 pr_info("%s: received HPHR OCP irq\n", __func__);
4883
4884 if (sitar) {
4885 codec = sitar->codec;
4886 if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
4887 pr_info("%s: retry\n", __func__);
4888 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
4889 0x00);
4890 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
4891 0x10);
4892 } else {
4893 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004894 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304895 sitar->hphrocp_cnt = 0;
4896 sitar->hph_status |= SND_JACK_OC_HPHR;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004897 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304898 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004899 sitar->mbhc_cfg.headset_jack,
4900 sitar->hph_status,
4901 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304902 }
4903 } else {
4904 pr_err("%s: Bad sitar private data\n", __func__);
4905 }
4906
4907 return IRQ_HANDLED;
4908}
4909
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304910static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
4911{
4912 struct sitar_priv *priv = data;
4913 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304914
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004915 pr_debug("%s: enter\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004916 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07004917 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304918
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304919 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4920
4921 /* Turn off both HPH and MIC line schmitt triggers */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004922 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304923 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004924 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304925
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004926 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304927
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004928 rmb();
4929 if (priv->lpi_enabled)
4930 msleep(100);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304931
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004932 rmb();
4933 if (!priv->lpi_enabled) {
4934 pr_debug("%s: lpi is disabled\n", __func__);
4935 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4936 priv->mbhc_cfg.gpio_level_insert) {
4937 pr_debug("%s: Valid insertion, "
4938 "detect plug type\n", __func__);
4939 sitar_codec_decide_gpio_plug(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304940 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004941 pr_debug("%s: Invalid insertion, "
4942 "stop plug detection\n", __func__);
4943 }
4944 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4945 return IRQ_HANDLED;
4946}
4947
4948static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
4949{
4950 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4951 struct sitar_mbhc_plug_type_cfg *plug_type =
4952 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4953
4954 return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
4955 && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
4956 && (mic_mv > plug_type->v_no_mic)
4957 && (mic_mv < plug_type->v_hs_max)) ? true : false;
4958}
4959
4960/* called under codec_resource_lock acquisition
4961 * returns true if mic voltage range is back to normal insertion
4962 * returns false either if timedout or removed */
4963static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
4964{
4965 int i;
4966 bool timedout, settled = false;
4967 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4968 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4969 unsigned long retry = 0, timeout;
4970 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4971
4972 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4973 while (!(timedout = time_after(jiffies, timeout))) {
4974 retry++;
4975 if (sitar_hs_gpio_level_remove(sitar)) {
4976 pr_debug("%s: GPIO indicates removal\n", __func__);
4977 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304978 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004979
4980 if (retry > 1)
4981 msleep(250);
4982 else
4983 msleep(50);
4984
4985 if (sitar_hs_gpio_level_remove(sitar)) {
4986 pr_debug("%s: GPIO indicates removal\n", __func__);
4987 break;
4988 }
4989
4990 sitar_turn_onoff_override(codec, true);
4991 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4992 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4993 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4994 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
4995 __func__, retry, mic_mv[i], mb_v[i]);
4996 }
4997 sitar_turn_onoff_override(codec, false);
4998
4999 if (sitar_hs_gpio_level_remove(sitar)) {
5000 pr_debug("%s: GPIO indicates removal\n", __func__);
5001 break;
5002 }
5003
5004 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5005 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5006 break;
5007
5008 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5009 pr_debug("%s: MIC voltage settled\n", __func__);
5010 settled = true;
5011 msleep(200);
5012 break;
5013 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305014 }
5015
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005016 if (timedout)
5017 pr_debug("%s: Microphone did not settle in %d seconds\n",
5018 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
5019 return settled;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305020}
5021
5022static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
5023{
5024 struct sitar_priv *priv = data;
5025 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305026
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005027 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305028
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005029 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
5030 if (sitar_hs_remove_settle(codec))
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305031 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005032 pr_debug("%s: remove settle done\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305033
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005034 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305035 return IRQ_HANDLED;
5036}
5037
5038
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305039
5040static irqreturn_t sitar_slimbus_irq(int irq, void *data)
5041{
5042 struct sitar_priv *priv = data;
5043 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005044 unsigned long slimbus_value;
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005045 int i, j, k, port_id, ch_mask_temp;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305046 u8 val;
5047
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305048
5049 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
5050 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
5051 SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
5052 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005053 port_id = i*8 + j;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305054 val = wcd9xxx_interface_reg_read(codec->control_data,
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005055 SITAR_SLIM_PGD_PORT_INT_SOURCE0 + port_id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305056 if (val & 0x1)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005057 pr_err_ratelimited("overflow error on port %x, value %x\n",
5058 port_id, val);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305059 if (val & 0x2)
Bhalchandra Gajaree66e4bb2012-07-10 15:17:50 -07005060 pr_err_ratelimited("underflow error on port %x,value %x\n",
5061 port_id, val);
5062 if (val & 0x4) {
5063 pr_debug("%s: port %x disconnect value %x\n",
5064 __func__, port_id, val);
5065 for (k = 0; k < ARRAY_SIZE(sitar_dai); k++) {
5066 ch_mask_temp = 1 << port_id;
5067 if (ch_mask_temp &
5068 priv->dai[k].ch_mask) {
5069 priv->dai[k].ch_mask &=
5070 ~ch_mask_temp;
5071 if (!priv->dai[k].ch_mask)
5072 wake_up(
5073 &priv->dai[k].dai_wait);
5074 }
5075 }
5076 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305077 }
5078 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajarec131e9f2012-09-09 15:32:14 -07005079 SITAR_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
5080 val = 0x0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305081 }
5082
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305083 return IRQ_HANDLED;
5084}
5085
5086
5087static int sitar_handle_pdata(struct sitar_priv *sitar)
5088{
5089 struct snd_soc_codec *codec = sitar->codec;
5090 struct wcd9xxx_pdata *pdata = sitar->pdata;
5091 int k1, k2, rc = 0;
5092 u8 leg_mode = pdata->amic_settings.legacy_mode;
5093 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
5094 u8 txfe_buff = pdata->amic_settings.txfe_buff;
5095 u8 flag = pdata->amic_settings.use_pdata;
5096 u8 i = 0, j = 0;
5097 u8 val_txfe = 0, value = 0;
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305098 int amic_reg_count = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305099
5100 if (!pdata) {
5101 rc = -ENODEV;
5102 goto done;
5103 }
5104
5105 /* Make sure settings are correct */
5106 if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
5107 (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
5108 (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
5109 rc = -EINVAL;
5110 goto done;
5111 }
5112
5113 /* figure out k value */
5114 k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
5115 pdata->micbias.cfilt1_mv);
5116 k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
5117 pdata->micbias.cfilt2_mv);
5118
5119 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
5120 rc = -EINVAL;
5121 goto done;
5122 }
5123
5124 /* Set voltage level and always use LDO */
Bhalchandra Gajare03d28d02012-05-18 17:39:32 -07005125 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
5126 (pdata->micbias.ldoh_v << 2));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305127
5128 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
5129 (k1 << 2));
5130 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
5131 (k2 << 2));
5132
5133 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
5134 (pdata->micbias.bias1_cfilt_sel << 5));
5135 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
5136 (pdata->micbias.bias2_cfilt_sel << 5));
5137
Bhalchandra Gajare15dbeaa2012-06-26 12:53:07 -07005138 /* Set micbias capless mode */
5139 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x10,
5140 (pdata->micbias.bias1_cap_mode << 4));
5141 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
5142 (pdata->micbias.bias2_cap_mode << 4));
5143
Asish Bhattacharya34aa1982012-09-20 14:24:05 +05305144 amic_reg_count = (NUM_AMIC % 2) ? NUM_AMIC + 1 : NUM_AMIC;
5145 for (i = 0; i < amic_reg_count; j++, i += 2) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305146 if (flag & (0x01 << i)) {
5147 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
5148 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
5149 val_txfe = val_txfe |
5150 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
5151 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5152 0x10, value);
5153 snd_soc_update_bits(codec,
5154 SITAR_A_TX_1_2_TEST_EN + j * 10,
5155 0x30, val_txfe);
5156 }
5157 if (flag & (0x01 << (i + 1))) {
5158 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
5159 val_txfe = (txfe_bypass &
5160 (0x01 << (i + 1))) ? 0x02 : 0x00;
5161 val_txfe |= (txfe_buff &
5162 (0x01 << (i + 1))) ? 0x01 : 0x00;
5163 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
5164 0x01, value);
5165 snd_soc_update_bits(codec,
5166 SITAR_A_TX_1_2_TEST_EN + j * 10,
5167 0x03, val_txfe);
5168 }
5169 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005170 if (flag & 0x40) {
5171 value = (leg_mode & 0x40) ? 0x10 : 0x00;
5172 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
5173 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
5174 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
5175 0x13, value);
5176 }
5177
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305178
5179 if (pdata->ocp.use_pdata) {
5180 /* not defined in CODEC specification */
5181 if (pdata->ocp.hph_ocp_limit == 1 ||
5182 pdata->ocp.hph_ocp_limit == 5) {
5183 rc = -EINVAL;
5184 goto done;
5185 }
5186 snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
5187 0x0F, pdata->ocp.num_attempts);
5188 snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
5189 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
5190 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
5191 0xE0, (pdata->ocp.hph_ocp_limit << 5));
5192 }
5193done:
5194 return rc;
5195}
5196
5197static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
5198
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305199 SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
5200 SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
5201
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305202 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
5203 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
5204
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305205 SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
5206 SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
5207 SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
5208
Simmi Pateriya6dc02f72012-10-08 13:28:31 +05305209 SITAR_REG_VAL(SITAR_A_RX_LINE_BIAS_PA, 0xA7),
5210
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305211 SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
Asish Bhattacharya2e1d7522012-05-25 15:08:40 +05305212 SITAR_REG_VAL(SITAR_A_CDC_RX2_B5_CTL, 0x78),
5213 SITAR_REG_VAL(SITAR_A_CDC_RX3_B5_CTL, 0x78),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305214
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305215 SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
5216
5217 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
Bhalchandra Gajare8a0bb372012-10-03 18:41:01 -07005218 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x5B),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305219
5220};
5221
5222static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
5223{
5224 u32 i;
5225 for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
5226 snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
5227 sitar_1_1_reg_defaults[i].val);
5228
5229}
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305230
5231static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
5232 {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
5233};
5234
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305235static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
5236 /* Initialize current threshold to 350MA
5237 * number of wait and run cycles to 4096
5238 */
Bhalchandra Gajare33f74302012-06-14 15:12:51 -07005239 {SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305240 {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
5241
5242 {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
5243
5244 /* Initialize gain registers to use register gain */
5245 {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
5246 {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
5247 {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
5248 {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
5249
Kuirong Wangccb29c62012-06-15 11:09:07 -07005250 /* Set the MICBIAS default output as pull down*/
5251 {SITAR_A_MICB_1_CTL, 0x01, 0x01},
5252 {SITAR_A_MICB_2_CTL, 0x01, 0x01},
5253
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305254 /* Initialize mic biases to differential mode */
5255 {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
5256 {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
5257
5258 {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
5259
5260 /* Use 16 bit sample size for TX1 to TX6 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005261 {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305262 {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
5263 {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
5264 {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
5265 {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005266 {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305267
5268 /* Use 16 bit sample size for RX */
5269 {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
5270 {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
5271
5272 /*enable HPF filter for TX paths */
5273 {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005274 {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07005275
5276 /*enable External clock select*/
5277 {SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305278};
5279
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305280static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
5281{
5282 u32 i;
5283 for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
5284 snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
5285 sitar_i2c_codec_reg_init_val[i].mask,
5286 sitar_i2c_codec_reg_init_val[i].val);
5287}
5288
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305289static void sitar_codec_init_reg(struct snd_soc_codec *codec)
5290{
5291 u32 i;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305292 for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
5293 snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
5294 sitar_codec_reg_init_val[i].mask,
5295 sitar_codec_reg_init_val[i].val);
5296}
5297
5298static int sitar_codec_probe(struct snd_soc_codec *codec)
5299{
Kuirong Wang906ac472012-07-09 12:54:44 -07005300 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305301 struct sitar_priv *sitar;
5302 struct snd_soc_dapm_context *dapm = &codec->dapm;
5303 int ret = 0;
5304 int i;
5305 u8 sitar_version;
Kuirong Wang906ac472012-07-09 12:54:44 -07005306 void *ptr = NULL;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305307
5308 codec->control_data = dev_get_drvdata(codec->dev->parent);
Kuirong Wang906ac472012-07-09 12:54:44 -07005309 core = codec->control_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305310
5311 sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
5312 if (!sitar) {
5313 dev_err(codec->dev, "Failed to allocate private data\n");
5314 return -ENOMEM;
5315 }
5316
5317 /* Make sure mbhc micbias register addresses are zeroed out */
5318 memset(&sitar->mbhc_bias_regs, 0,
5319 sizeof(struct mbhc_micbias_regs));
5320 sitar->cfilt_k_value = 0;
5321 sitar->mbhc_micbias_switched = false;
5322
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005323 /* Make sure mbhc intenal calibration data is zeroed out */
5324 memset(&sitar->mbhc_data, 0,
5325 sizeof(struct mbhc_internal_cal_data));
5326 sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
5327 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
5328 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305329 snd_soc_codec_set_drvdata(codec, sitar);
5330
5331 sitar->mclk_enabled = false;
5332 sitar->bandgap_type = SITAR_BANDGAP_OFF;
5333 sitar->clock_active = false;
5334 sitar->config_mode_active = false;
5335 sitar->mbhc_polling_active = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305336 sitar->no_mic_headset_override = false;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005337 mutex_init(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305338 sitar->codec = codec;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005339 sitar->mbhc_state = MBHC_STATE_NONE;
5340 sitar->mbhc_last_resume = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305341 sitar->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305342 sitar_update_reg_defaults(codec);
5343 sitar_codec_init_reg(codec);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305344 sitar->intf_type = wcd9xxx_get_intf_type();
5345 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
5346 sitar_i2c_codec_init_reg(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305347
5348 ret = sitar_handle_pdata(sitar);
5349 if (IS_ERR_VALUE(ret)) {
5350 pr_err("%s: bad pdata\n", __func__);
5351 goto err_pdata;
5352 }
5353
Steve Mucklef132c6c2012-06-06 18:30:57 -07005354 snd_soc_add_codec_controls(codec, sitar_snd_controls,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305355 ARRAY_SIZE(sitar_snd_controls));
5356 snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
5357 ARRAY_SIZE(sitar_dapm_widgets));
Kuirong Wang906ac472012-07-09 12:54:44 -07005358
5359 ptr = kmalloc((sizeof(sitar_rx_chs) +
5360 sizeof(sitar_tx_chs)), GFP_KERNEL);
5361 if (!ptr) {
5362 pr_err("%s: no mem for slim chan ctl data\n", __func__);
5363 ret = -ENOMEM;
5364 goto err_nomem_slimch;
5365 }
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305366 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
5367 snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
5368 ARRAY_SIZE(sitar_dapm_i2s_widgets));
5369 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5370 ARRAY_SIZE(audio_i2s_map));
Kuirong Wang906ac472012-07-09 12:54:44 -07005371 for (i = 0; i < ARRAY_SIZE(sitar_i2s_dai); i++)
5372 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305373 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005374 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
5375 for (i = 0; i < NUM_CODEC_DAIS; i++) {
5376 INIT_LIST_HEAD(&sitar->dai[i].wcd9xxx_ch_list);
5377 init_waitqueue_head(&sitar->dai[i].dai_wait);
5378 }
5379 }
5380 core->num_rx_port = SITAR_RX_MAX;
5381 core->rx_chs = ptr;
5382 memcpy(core->rx_chs, sitar_rx_chs, sizeof(sitar_rx_chs));
5383 core->num_tx_port = SITAR_TX_MAX;
5384 core->tx_chs = ptr + sizeof(sitar_rx_chs);
5385 memcpy(core->tx_chs, sitar_tx_chs, sizeof(sitar_tx_chs));
5386
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305387 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
5388
5389 sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
5390 pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
5391
5392 sitar_version &= 0x1F;
5393 pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
5394
5395 snd_soc_dapm_sync(dapm);
5396
5397
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005398 ret = wcd9xxx_request_irq(codec->control_data,
5399 WCD9XXX_IRQ_MBHC_INSERTION,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305400 sitar_hs_insert_irq, "Headset insert detect", sitar);
5401 if (ret) {
5402 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005403 WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305404 goto err_insert_irq;
5405 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005406 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305407
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005408 ret = wcd9xxx_request_irq(codec->control_data,
5409 WCD9XXX_IRQ_MBHC_REMOVAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305410 sitar_hs_remove_irq, "Headset remove detect", sitar);
5411 if (ret) {
5412 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005413 WCD9XXX_IRQ_MBHC_REMOVAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305414 goto err_remove_irq;
5415 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305416
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005417 ret = wcd9xxx_request_irq(codec->control_data,
5418 WCD9XXX_IRQ_MBHC_POTENTIAL,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305419 sitar_dce_handler, "DC Estimation detect", sitar);
5420 if (ret) {
5421 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005422 WCD9XXX_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305423 goto err_potential_irq;
5424 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305425
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005426 ret = wcd9xxx_request_irq(codec->control_data,
5427 WCD9XXX_IRQ_MBHC_RELEASE,
5428 sitar_release_handler,
5429 "Button Release detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305430 if (ret) {
5431 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005432 WCD9XXX_IRQ_MBHC_RELEASE);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305433 goto err_release_irq;
5434 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305435
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005436 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
5437 sitar_slimbus_irq, "SLIMBUS Slave", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305438 if (ret) {
5439 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005440 WCD9XXX_IRQ_SLIMBUS);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305441 goto err_slimbus_irq;
5442 }
5443
5444 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
5445 wcd9xxx_interface_reg_write(codec->control_data,
5446 SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
5447
5448
5449 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005450 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
5451 sitar_hphl_ocp_irq,
5452 "HPH_L OCP detect", sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305453 if (ret) {
5454 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005455 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305456 goto err_hphl_ocp_irq;
5457 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005458 wcd9xxx_disable_irq(codec->control_data,
5459 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305460
5461 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005462 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
5463 sitar_hphr_ocp_irq, "HPH_R OCP detect",
5464 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305465 if (ret) {
5466 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005467 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305468 goto err_hphr_ocp_irq;
5469 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005470 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305471
Steve Mucklef132c6c2012-06-06 18:30:57 -07005472 codec->ignore_pmdown_time = 1;
5473
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305474#ifdef CONFIG_DEBUG_FS
5475 debug_sitar_priv = sitar;
5476#endif
5477
5478 return ret;
5479
5480err_hphr_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005481 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
5482 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305483err_hphl_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005484 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305485err_slimbus_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005486 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305487err_release_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005488 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
5489 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305490err_potential_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005491 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305492err_remove_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005493 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
5494 sitar);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305495err_insert_irq:
Kuirong Wang906ac472012-07-09 12:54:44 -07005496 kfree(ptr);
5497err_nomem_slimch:
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305498err_pdata:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005499 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305500 kfree(sitar);
5501 return ret;
5502}
5503static int sitar_codec_remove(struct snd_soc_codec *codec)
5504{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305505 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005506 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
5507 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
5508 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
5509 sitar);
5510 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
5511 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
5512 sitar);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005513 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305514 sitar_codec_disable_clock_block(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005515 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305516 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08005517 if (sitar->mbhc_fw)
5518 release_firmware(sitar->mbhc_fw);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005519 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305520 kfree(sitar);
5521 return 0;
5522}
5523static struct snd_soc_codec_driver soc_codec_dev_sitar = {
5524 .probe = sitar_codec_probe,
5525 .remove = sitar_codec_remove,
5526 .read = sitar_read,
5527 .write = sitar_write,
5528
5529 .readable_register = sitar_readable,
5530 .volatile_register = sitar_volatile,
5531
5532 .reg_cache_size = SITAR_CACHE_SIZE,
5533 .reg_cache_default = sitar_reg_defaults,
5534 .reg_word_size = 1,
5535};
5536
5537#ifdef CONFIG_DEBUG_FS
5538static struct dentry *debugfs_poke;
5539
5540static int codec_debug_open(struct inode *inode, struct file *file)
5541{
5542 file->private_data = inode->i_private;
5543 return 0;
5544}
5545
5546static ssize_t codec_debug_write(struct file *filp,
5547 const char __user *ubuf, size_t cnt, loff_t *ppos)
5548{
5549 char lbuf[32];
5550 char *buf;
5551 int rc;
5552
5553 if (cnt > sizeof(lbuf) - 1)
5554 return -EINVAL;
5555
5556 rc = copy_from_user(lbuf, ubuf, cnt);
5557 if (rc)
5558 return -EFAULT;
5559
5560 lbuf[cnt] = '\0';
5561 buf = (char *)lbuf;
5562 debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
5563 ? false : true;
5564
5565 return rc;
5566}
5567
5568static const struct file_operations codec_debug_ops = {
5569 .open = codec_debug_open,
5570 .write = codec_debug_write,
5571};
5572#endif
5573
5574#ifdef CONFIG_PM
5575static int sitar_suspend(struct device *dev)
5576{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005577 dev_dbg(dev, "%s: system suspend\n", __func__);
5578 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305579}
5580
5581static int sitar_resume(struct device *dev)
5582{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005583 struct platform_device *pdev = to_platform_device(dev);
5584 struct sitar_priv *sitar = platform_get_drvdata(pdev);
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005585 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07005586 sitar->mbhc_last_resume = jiffies;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08005587 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305588}
5589
5590static const struct dev_pm_ops sitar_pm_ops = {
5591 .suspend = sitar_suspend,
5592 .resume = sitar_resume,
5593};
5594#endif
5595
5596static int __devinit sitar_probe(struct platform_device *pdev)
5597{
5598 int ret = 0;
5599 pr_err("%s\n", __func__);
5600#ifdef CONFIG_DEBUG_FS
5601 debugfs_poke = debugfs_create_file("TRRS",
5602 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
5603
5604#endif
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305605 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5606 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305607 sitar_dai, ARRAY_SIZE(sitar_dai));
Asish Bhattacharya2b709d42011-11-15 10:39:23 +05305608 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5609 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
5610 sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05305611 return ret;
5612}
5613static int __devexit sitar_remove(struct platform_device *pdev)
5614{
5615 snd_soc_unregister_codec(&pdev->dev);
5616
5617#ifdef CONFIG_DEBUG_FS
5618 debugfs_remove(debugfs_poke);
5619#endif
5620 return 0;
5621}
5622static struct platform_driver sitar_codec_driver = {
5623 .probe = sitar_probe,
5624 .remove = sitar_remove,
5625 .driver = {
5626 .name = "sitar_codec",
5627 .owner = THIS_MODULE,
5628#ifdef CONFIG_PM
5629 .pm = &sitar_pm_ops,
5630#endif
5631 },
5632};
5633
5634static int __init sitar_codec_init(void)
5635{
5636 return platform_driver_register(&sitar_codec_driver);
5637}
5638
5639static void __exit sitar_codec_exit(void)
5640{
5641 platform_driver_unregister(&sitar_codec_driver);
5642}
5643
5644module_init(sitar_codec_init);
5645module_exit(sitar_codec_exit);
5646
5647MODULE_DESCRIPTION("Sitar codec driver");
5648MODULE_VERSION("1.0");
5649MODULE_LICENSE("GPL v2");