blob: a2c6f5fe759deaaf3d4c683d431c6c456090c695 [file] [log] [blame]
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/gpio.h>
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080016#include <linux/mfd/pm8xxx/misc.h>
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053017#include <linux/platform_device.h>
18#include <linux/gpio.h>
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053019#include <linux/slab.h>
20#include <sound/core.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <sound/soc-dsp.h>
24#include <sound/pcm.h>
25#include <sound/jack.h>
26#include <asm/mach-types.h>
27#include <mach/socinfo.h>
28#include "msm-pcm-routing.h"
29#include "../codecs/wcd9304.h"
30
31/* 8930 machine driver */
32
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053033#define MSM8930_SPK_ON 1
34#define MSM8930_SPK_OFF 0
35
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053036#define BTSCO_RATE_8KHZ 8000
37#define BTSCO_RATE_16KHZ 16000
38
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053039#define SITAR_EXT_CLK_RATE 12288000
40
41#define SITAR_MBHC_DEF_BUTTONS 3
42#define SITAR_MBHC_DEF_RLOADS 5
43
44static int msm8930_spk_control;
45static int msm8930_slim_0_rx_ch = 1;
46static int msm8930_slim_0_tx_ch = 1;
47
48static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
49static int msm8930_btsco_ch = 1;
50
51static struct clk *codec_clk;
52static int clk_users;
53
54static int msm8930_headset_gpios_configured;
55
56static struct snd_soc_jack hs_jack;
57static struct snd_soc_jack button_jack;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070058
59static int msm8930_enable_codec_ext_clk(
60 struct snd_soc_codec *codec, int enable,
61 bool dapm);
62
63static struct sitar_mbhc_config mbhc_cfg = {
64 .headset_jack = &hs_jack,
65 .button_jack = &button_jack,
66 .read_fw_bin = false,
67 .calibration = NULL,
68 .micbias = SITAR_MICBIAS2,
69 .mclk_cb_fn = msm8930_enable_codec_ext_clk,
70 .mclk_rate = SITAR_EXT_CLK_RATE,
71 .gpio = 0,
72 .gpio_irq = 0,
73 .gpio_level_insert = 1,
74};
75
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053076
77static void msm8930_ext_control(struct snd_soc_codec *codec)
78{
79 struct snd_soc_dapm_context *dapm = &codec->dapm;
80
81 pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
82 if (msm8930_spk_control == MSM8930_SPK_ON) {
83 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080084 snd_soc_dapm_enable_pin(dapm, "Ext Spk left Neg");
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053085 } else {
86 snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080087 snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Neg");
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053088 }
89
90 snd_soc_dapm_sync(dapm);
91}
92
93static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
94 struct snd_ctl_elem_value *ucontrol)
95{
96 pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
97 ucontrol->value.integer.value[0] = msm8930_spk_control;
98 return 0;
99}
100static int msm8930_set_spk(struct snd_kcontrol *kcontrol,
101 struct snd_ctl_elem_value *ucontrol)
102{
103 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
104
105 pr_debug("%s()\n", __func__);
106 if (msm8930_spk_control == ucontrol->value.integer.value[0])
107 return 0;
108
109 msm8930_spk_control = ucontrol->value.integer.value[0];
110 msm8930_ext_control(codec);
111 return 1;
112}
113
114static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
115 struct snd_kcontrol *k, int event)
116{
117 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
118 /* TODO: add external speaker power amps support */
119 return 0;
120}
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800121
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700122static int msm8930_enable_codec_ext_clk(
123 struct snd_soc_codec *codec, int enable,
124 bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530125{
126 pr_debug("%s: enable = %d\n", __func__, enable);
127 if (enable) {
128 clk_users++;
129 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
130 if (clk_users != 1)
131 return 0;
132
133 if (codec_clk) {
134 clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800135 clk_prepare_enable(codec_clk);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700136 sitar_mclk_enable(codec, 1, dapm);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530137 } else {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800138 pr_err("%s: Error setting Sitar MCLK\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530139 clk_users--;
140 return -EINVAL;
141 }
142 } else {
143 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
144 if (clk_users == 0)
145 return 0;
146 clk_users--;
147 if (!clk_users) {
148 pr_debug("%s: disabling MCLK. clk_users = %d\n",
149 __func__, clk_users);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700150 sitar_mclk_enable(codec, 0, dapm);
Bhalchandra Gajare2776af12012-04-27 16:59:39 -0700151 clk_disable_unprepare(codec_clk);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530152 }
153 }
154 return 0;
155}
156
157static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
158 struct snd_kcontrol *kcontrol, int event)
159{
160 pr_debug("%s: event = %d\n", __func__, event);
161
162 switch (event) {
163 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700164 return msm8930_enable_codec_ext_clk(w->codec, 1, true);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530165 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700166 return msm8930_enable_codec_ext_clk(w->codec, 0, true);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530167 }
168 return 0;
169}
170
171static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
172
173 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
174 msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
175
176 SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800177 SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530178
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530179 SND_SOC_DAPM_MIC("Headset Mic", NULL),
180 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
181 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
182 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
183
184 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
185 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
186 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
187 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
188
189};
190
191static const struct snd_soc_dapm_route common_audio_map[] = {
192
193 {"RX_BIAS", NULL, "MCLK"},
194 {"LDO_H", NULL, "MCLK"},
195
196 {"MIC BIAS1 Internal1", NULL, "MCLK"},
197 {"MIC BIAS2 Internal1", NULL, "MCLK"},
198
199 /* Speaker path */
200 {"Ext Spk Left Pos", NULL, "LINEOUT1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800201 {"Ext Spk Left Neg", NULL, "LINEOUT2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530202
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800203 /* Headset Mic */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530204 {"AMIC2", NULL, "MIC BIAS2 Internal1"},
205 {"MIC BIAS2 Internal1", NULL, "Headset Mic"},
206
207 /* Microphone path */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800208 {"AMIC1", NULL, "MIC BIAS2 Internal1"},
209 {"MIC BIAS2 Internal1", NULL, "ANCLeft Headset Mic"},
210
211 {"AMIC3", NULL, "MIC BIAS2 Internal1"},
212 {"MIC BIAS2 Internal1", NULL, "ANCRight Headset Mic"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530213
214 {"HEADPHONE", NULL, "LDO_H"},
215
216 /**
217 * The digital Mic routes are setup considering
218 * fluid as default device.
219 */
220
221 /**
222 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
223 * Digital Mic GM5 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800224 * Conncted to DMIC2 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530225 */
226 {"DMIC1", NULL, "MIC BIAS1 External"},
227 {"MIC BIAS1 External", NULL, "Digital Mic1"},
228
229 /**
230 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
231 * Digital Mic GM6 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800232 * Conncted to DMIC1 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530233 */
234 {"DMIC2", NULL, "MIC BIAS1 External"},
235 {"MIC BIAS1 External", NULL, "Digital Mic2"},
236 /**
237 * Digital Mic3. Back Bottom Digital Mic on Fluid.
238 * Digital Mic GM1 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800239 * Conncted to DMIC4 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530240 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800241 {"DMIC3", NULL, "MIC BIAS1 External"},
242 {"MIC BIAS1 External", NULL, "Digital Mic3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530243
244 /**
245 * Digital Mic4. Back top Digital Mic on Fluid.
246 * Digital Mic GM2 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800247 * Conncted to DMIC3 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530248 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800249 {"DMIC4", NULL, "MIC BIAS1 External"},
250 {"MIC BIAS1 External", NULL, "Digital Mic4"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530251
252
253};
254
255static const char *spk_function[] = {"Off", "On"};
256static const char *slim0_rx_ch_text[] = {"One", "Two"};
257static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
258
259static const struct soc_enum msm8930_enum[] = {
260 SOC_ENUM_SINGLE_EXT(2, spk_function),
261 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
262 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
263};
264
265static const char *btsco_rate_text[] = {"8000", "16000"};
266static const struct soc_enum msm8930_btsco_enum[] = {
267 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
268};
269
270static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
271 struct snd_ctl_elem_value *ucontrol)
272{
273 pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800274 msm8930_slim_0_rx_ch);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530275 ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
276 return 0;
277}
278
279static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
280 struct snd_ctl_elem_value *ucontrol)
281{
282 msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
283
284 pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800285 msm8930_slim_0_rx_ch);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530286 return 1;
287}
288
289static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
290 struct snd_ctl_elem_value *ucontrol)
291{
292 pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
293 msm8930_slim_0_tx_ch);
294 ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
295 return 0;
296}
297
298static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
299 struct snd_ctl_elem_value *ucontrol)
300{
301 msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
302
303 pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
304 msm8930_slim_0_tx_ch);
305 return 1;
306}
307
308static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
309 struct snd_ctl_elem_value *ucontrol)
310{
311 pr_debug("%s: msm8930_btsco_rate = %d", __func__, msm8930_btsco_rate);
312 ucontrol->value.integer.value[0] = msm8930_btsco_rate;
313 return 0;
314}
315
316static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
317 struct snd_ctl_elem_value *ucontrol)
318{
319 switch (ucontrol->value.integer.value[0]) {
320 case 0:
321 msm8930_btsco_rate = BTSCO_RATE_8KHZ;
322 break;
323 case 1:
324 msm8930_btsco_rate = BTSCO_RATE_16KHZ;
325 break;
326 default:
327 msm8930_btsco_rate = BTSCO_RATE_8KHZ;
328 break;
329 }
330 pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
331 return 0;
332}
333
334static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
335 SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
336 msm8930_set_spk),
337 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
338 msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
339 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
340 msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
341};
342
343static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
344 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
345 msm8930_btsco_rate_get, msm8930_btsco_rate_put),
346};
347
348static int msm8930_btsco_init(struct snd_soc_pcm_runtime *rtd)
349{
350 int err = 0;
351 struct snd_soc_platform *platform = rtd->platform;
352
353 err = snd_soc_add_platform_controls(platform,
354 int_btsco_rate_mixer_controls,
355 ARRAY_SIZE(int_btsco_rate_mixer_controls));
356 if (err < 0)
357 return err;
358 return 0;
359}
360
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800361static void *def_sitar_mbhc_cal(void)
362{
363 void *sitar_cal;
364 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
365 u16 *btn_low, *btn_high;
366 u8 *n_ready, *n_cic, *gain;
367
368 sitar_cal = kzalloc(SITAR_MBHC_CAL_SIZE(SITAR_MBHC_DEF_BUTTONS,
369 SITAR_MBHC_DEF_RLOADS),
370 GFP_KERNEL);
371 if (!sitar_cal) {
372 pr_err("%s: out of memory\n", __func__);
373 return NULL;
374 }
375
376#define S(X, Y) ((SITAR_MBHC_CAL_GENERAL_PTR(sitar_cal)->X) = (Y))
377 S(t_ldoh, 100);
378 S(t_bg_fast_settle, 100);
379 S(t_shutdown_plug_rem, 255);
380 S(mbhc_nsa, 4);
381 S(mbhc_navg, 4);
382#undef S
383#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_DET_PTR(sitar_cal)->X) = (Y))
384 S(mic_current, SITAR_PID_MIC_5_UA);
385 S(hph_current, SITAR_PID_MIC_5_UA);
386 S(t_mic_pid, 100);
387 S(t_ins_complete, 250);
388 S(t_ins_retry, 200);
389#undef S
390#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
391 S(v_no_mic, 30);
392 S(v_hs_max, 1550);
393#undef S
394#define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
395 S(c[0], 62);
396 S(c[1], 124);
397 S(nc, 1);
398 S(n_meas, 3);
399 S(mbhc_nsc, 11);
400 S(n_btn_meas, 1);
401 S(n_btn_con, 2);
402 S(num_btn, SITAR_MBHC_DEF_BUTTONS);
403 S(v_btn_press_delta_sta, 100);
404 S(v_btn_press_delta_cic, 50);
405#undef S
406 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal);
407 btn_low = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_LOW);
408 btn_high = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_HIGH);
409 btn_low[0] = -50;
410 btn_high[0] = 10;
411 btn_low[1] = 11;
412 btn_high[1] = 38;
413 btn_low[2] = 39;
414 btn_high[2] = 64;
415 btn_low[3] = 65;
416 btn_high[3] = 91;
417 btn_low[4] = 92;
418 btn_high[4] = 115;
419 btn_low[5] = 116;
420 btn_high[5] = 141;
421 btn_low[6] = 142;
422 btn_high[6] = 163;
423 btn_low[7] = 164;
424 btn_high[7] = 250;
425 n_ready = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_READY);
426 n_ready[0] = 48;
427 n_ready[1] = 38;
428 n_cic = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_CIC);
429 n_cic[0] = 60;
430 n_cic[1] = 47;
431 gain = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_GAIN);
432 gain[0] = 11;
433 gain[1] = 9;
434
435 return sitar_cal;
436}
437
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530438static int msm8930_hw_params(struct snd_pcm_substream *substream,
439 struct snd_pcm_hw_params *params)
440{
441 struct snd_soc_pcm_runtime *rtd = substream->private_data;
442 struct snd_soc_dai *codec_dai = rtd->codec_dai;
443 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
444 int ret = 0;
445 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
446 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
447
448 pr_debug("%s: ch=%d\n", __func__,
449 msm8930_slim_0_rx_ch);
450 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
451 ret = snd_soc_dai_get_channel_map(codec_dai,
452 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
453 if (ret < 0) {
454 pr_err("%s: failed to get codec chan map\n", __func__);
455 goto end;
456 }
457
458 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
459 msm8930_slim_0_rx_ch, rx_ch);
460 if (ret < 0) {
461 pr_err("%s: failed to set cpu chan map\n", __func__);
462 goto end;
463 }
464 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
465 msm8930_slim_0_rx_ch, rx_ch);
466 if (ret < 0) {
467 pr_err("%s: failed to set codec channel map\n",
468 __func__);
469 goto end;
470 }
471 } else {
472 ret = snd_soc_dai_get_channel_map(codec_dai,
473 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
474 if (ret < 0) {
475 pr_err("%s: failed to get codec chan map\n", __func__);
476 goto end;
477 }
478 ret = snd_soc_dai_set_channel_map(cpu_dai,
479 msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
480 if (ret < 0) {
481 pr_err("%s: failed to set cpu chan map\n", __func__);
482 goto end;
483 }
484 ret = snd_soc_dai_set_channel_map(codec_dai,
485 msm8930_slim_0_tx_ch, tx_ch, 0, 0);
486 if (ret < 0) {
487 pr_err("%s: failed to set codec channel map\n",
488 __func__);
489 goto end;
490 }
491
492 }
493end:
494 return ret;
495}
496
497static int msm8930_audrx_init(struct snd_soc_pcm_runtime *rtd)
498{
499 int err;
500 struct snd_soc_codec *codec = rtd->codec;
501 struct snd_soc_dapm_context *dapm = &codec->dapm;
502 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
503
504 pr_debug("%s()\n", __func__);
505
506
507 rtd->pmdown_time = 0;
508
509 err = snd_soc_add_controls(codec, sitar_msm8930_controls,
510 ARRAY_SIZE(sitar_msm8930_controls));
511 if (err < 0)
512 return err;
513
514 snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
515 ARRAY_SIZE(msm8930_dapm_widgets));
516
517 snd_soc_dapm_add_routes(dapm, common_audio_map,
518 ARRAY_SIZE(common_audio_map));
519
520 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800521 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Neg");
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530522
523 snd_soc_dapm_sync(dapm);
524
525 err = snd_soc_jack_new(codec, "Headset Jack",
526 (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
527 &hs_jack);
528 if (err) {
529 pr_err("failed to create new jack\n");
530 return err;
531 }
532
533 err = snd_soc_jack_new(codec, "Button Jack",
534 SND_JACK_BTN_0, &button_jack);
535 if (err) {
536 pr_err("failed to create new jack\n");
537 return err;
538 }
539 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800540
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700541 mbhc_cfg.gpio = 37;
542 mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
543 sitar_hs_detect(codec, &mbhc_cfg);
544
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530545 return 0;
546}
547
548static struct snd_soc_dsp_link lpa_fe_media = {
549 .playback = true,
550 .trigger = {
551 SND_SOC_DSP_TRIGGER_POST,
552 SND_SOC_DSP_TRIGGER_POST
553 },
554};
555
556static struct snd_soc_dsp_link fe_media = {
557 .playback = true,
558 .capture = true,
559 .trigger = {
560 SND_SOC_DSP_TRIGGER_POST,
561 SND_SOC_DSP_TRIGGER_POST
562 },
563};
564
565static struct snd_soc_dsp_link slimbus0_hl_media = {
566 .playback = true,
567 .capture = true,
568 .trigger = {
569 SND_SOC_DSP_TRIGGER_POST,
570 SND_SOC_DSP_TRIGGER_POST
571 },
572};
573
574static struct snd_soc_dsp_link int_fm_hl_media = {
575 .playback = true,
576 .capture = true,
577 .trigger = {
578 SND_SOC_DSP_TRIGGER_POST,
579 SND_SOC_DSP_TRIGGER_POST
580 },
581};
582
583/* bi-directional media definition for hostless PCM device */
584static struct snd_soc_dsp_link bidir_hl_media = {
585 .playback = true,
586 .capture = true,
587 .trigger = {
588 SND_SOC_DSP_TRIGGER_POST,
589 SND_SOC_DSP_TRIGGER_POST
590 },
591};
592
593static struct snd_soc_dsp_link hdmi_rx_hl = {
594 .playback = true,
595 .trigger = {
596 SND_SOC_DSP_TRIGGER_POST,
597 SND_SOC_DSP_TRIGGER_POST
598 },
599};
600
601static int msm8930_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
602 struct snd_pcm_hw_params *params)
603{
604 struct snd_interval *rate = hw_param_interval(params,
605 SNDRV_PCM_HW_PARAM_RATE);
606
607 struct snd_interval *channels = hw_param_interval(params,
608 SNDRV_PCM_HW_PARAM_CHANNELS);
609
610 pr_debug("%s()\n", __func__);
611 rate->min = rate->max = 48000;
612 channels->min = channels->max = msm8930_slim_0_rx_ch;
613
614 return 0;
615}
616
617static int msm8930_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
618 struct snd_pcm_hw_params *params)
619{
620 struct snd_interval *rate = hw_param_interval(params,
621 SNDRV_PCM_HW_PARAM_RATE);
622
623 struct snd_interval *channels = hw_param_interval(params,
624 SNDRV_PCM_HW_PARAM_CHANNELS);
625
626 pr_debug("%s()\n", __func__);
627 rate->min = rate->max = 48000;
628 channels->min = channels->max = msm8930_slim_0_tx_ch;
629
630 return 0;
631}
632
633static int msm8930_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
634 struct snd_pcm_hw_params *params)
635{
636 struct snd_interval *rate = hw_param_interval(params,
637 SNDRV_PCM_HW_PARAM_RATE);
638
639 pr_debug("%s()\n", __func__);
640 rate->min = rate->max = 48000;
641
642 return 0;
643}
644
645static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
646 struct snd_pcm_hw_params *params)
647{
648 struct snd_interval *rate = hw_param_interval(params,
649 SNDRV_PCM_HW_PARAM_RATE);
650
651 struct snd_interval *channels = hw_param_interval(params,
652 SNDRV_PCM_HW_PARAM_CHANNELS);
653
654 rate->min = rate->max = 48000;
655 channels->min = channels->max = 2;
656
657 return 0;
658}
659
660static int msm8930_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
661 struct snd_pcm_hw_params *params)
662{
663 struct snd_interval *rate = hw_param_interval(params,
664 SNDRV_PCM_HW_PARAM_RATE);
665
666 struct snd_interval *channels = hw_param_interval(params,
667 SNDRV_PCM_HW_PARAM_CHANNELS);
668
669 rate->min = rate->max = msm8930_btsco_rate;
670 channels->min = channels->max = msm8930_btsco_ch;
671
672 return 0;
673}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530674
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530675static int msm8930_startup(struct snd_pcm_substream *substream)
676{
677 pr_debug("%s(): substream = %s stream = %d\n", __func__,
678 substream->name, substream->stream);
679 return 0;
680}
681
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530682static void msm8930_shutdown(struct snd_pcm_substream *substream)
683{
684 pr_debug("%s(): substream = %s stream = %d\n", __func__,
685 substream->name, substream->stream);
686}
687
688static struct snd_soc_ops msm8930_be_ops = {
689 .startup = msm8930_startup,
690 .hw_params = msm8930_hw_params,
691 .shutdown = msm8930_shutdown,
692};
693
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530694/* Digital audio interface glue - connects codec <---> CPU */
695static struct snd_soc_dai_link msm8930_dai[] = {
696 /* FrontEnd DAI Links */
697 {
698 .name = "MSM8930 Media1",
699 .stream_name = "MultiMedia1",
700 .cpu_dai_name = "MultiMedia1",
701 .platform_name = "msm-pcm-dsp",
702 .dynamic = 1,
703 .dsp_link = &fe_media,
704 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
705 },
706 {
707 .name = "MSM8930 Media2",
708 .stream_name = "MultiMedia2",
709 .cpu_dai_name = "MultiMedia2",
710 .platform_name = "msm-pcm-dsp",
711 .dynamic = 1,
712 .dsp_link = &fe_media,
713 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
714 },
715 {
716 .name = "Circuit-Switch Voice",
717 .stream_name = "CS-Voice",
718 .cpu_dai_name = "CS-VOICE",
719 .platform_name = "msm-pcm-voice",
720 .dynamic = 1,
721 .dsp_link = &fe_media,
722 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
723 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
724 .ignore_suspend = 1,
725 },
726 {
727 .name = "MSM VoIP",
728 .stream_name = "VoIP",
729 .cpu_dai_name = "VoIP",
730 .platform_name = "msm-voip-dsp",
731 .dynamic = 1,
732 .dsp_link = &fe_media,
733 .be_id = MSM_FRONTEND_DAI_VOIP,
734 },
735 {
736 .name = "MSM8930 LPA",
737 .stream_name = "LPA",
738 .cpu_dai_name = "MultiMedia3",
739 .platform_name = "msm-pcm-lpa",
740 .dynamic = 1,
741 .dsp_link = &lpa_fe_media,
742 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
743 },
744 /* Hostless PMC purpose */
745 {
746 .name = "SLIMBUS_0 Hostless",
747 .stream_name = "SLIMBUS_0 Hostless",
748 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
749 .platform_name = "msm-pcm-hostless",
750 .dynamic = 1,
751 .dsp_link = &slimbus0_hl_media,
752 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
753 .ignore_suspend = 1,
754 /* .be_id = do not care */
755 },
756 {
757 .name = "INT_FM Hostless",
758 .stream_name = "INT_FM Hostless",
759 .cpu_dai_name = "INT_FM_HOSTLESS",
760 .platform_name = "msm-pcm-hostless",
761 .dynamic = 1,
762 .dsp_link = &int_fm_hl_media,
763 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
764 .ignore_suspend = 1,
765 /* .be_id = do not care */
766 },
767 {
768 .name = "MSM AFE-PCM RX",
769 .stream_name = "AFE-PROXY RX",
770 .cpu_dai_name = "msm-dai-q6.241",
771 .codec_name = "msm-stub-codec.1",
772 .codec_dai_name = "msm-stub-rx",
773 .platform_name = "msm-pcm-afe",
774 .ignore_suspend = 1,
775 },
776 {
777 .name = "MSM AFE-PCM TX",
778 .stream_name = "AFE-PROXY TX",
779 .cpu_dai_name = "msm-dai-q6.240",
780 .codec_name = "msm-stub-codec.1",
781 .codec_dai_name = "msm-stub-tx",
782 .platform_name = "msm-pcm-afe",
783 .ignore_suspend = 1,
784 },
785 {
786 .name = "MSM8930 Compr",
787 .stream_name = "COMPR",
788 .cpu_dai_name = "MultiMedia4",
789 .platform_name = "msm-compr-dsp",
790 .dynamic = 1,
791 .dsp_link = &lpa_fe_media,
792 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
793 },
794 {
795 .name = "AUXPCM Hostless",
796 .stream_name = "AUXPCM Hostless",
797 .cpu_dai_name = "AUXPCM_HOSTLESS",
798 .platform_name = "msm-pcm-hostless",
799 .dynamic = 1,
800 .dsp_link = &bidir_hl_media,
801 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
802 .ignore_suspend = 1,
803 },
804 /* HDMI Hostless */
805 {
806 .name = "HDMI_RX_HOSTLESS",
807 .stream_name = "HDMI_RX_HOSTLESS",
808 .cpu_dai_name = "HDMI_HOSTLESS",
809 .platform_name = "msm-pcm-hostless",
810 .dynamic = 1,
811 .dsp_link = &hdmi_rx_hl,
812 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
813 .no_codec = 1,
814 .ignore_suspend = 1,
815 },
816 /* Backend DAI Links */
817 {
818 .name = LPASS_BE_SLIMBUS_0_RX,
819 .stream_name = "Slimbus Playback",
820 .cpu_dai_name = "msm-dai-q6.16384",
821 .platform_name = "msm-pcm-routing",
822 .codec_name = "sitar_codec",
823 .codec_dai_name = "sitar_rx1",
824 .no_pcm = 1,
825 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
826 .init = &msm8930_audrx_init,
827 .be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
828 .ops = &msm8930_be_ops,
829 },
830 {
831 .name = LPASS_BE_SLIMBUS_0_TX,
832 .stream_name = "Slimbus Capture",
833 .cpu_dai_name = "msm-dai-q6.16385",
834 .platform_name = "msm-pcm-routing",
835 .codec_name = "sitar_codec",
836 .codec_dai_name = "sitar_tx1",
837 .no_pcm = 1,
838 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
839 .be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
840 .ops = &msm8930_be_ops,
841 },
842 /* Backend BT/FM DAI Links */
843 {
844 .name = LPASS_BE_INT_BT_SCO_RX,
845 .stream_name = "Internal BT-SCO Playback",
846 .cpu_dai_name = "msm-dai-q6.12288",
847 .platform_name = "msm-pcm-routing",
848 .codec_name = "msm-stub-codec.1",
849 .codec_dai_name = "msm-stub-rx",
850 .init = &msm8930_btsco_init,
851 .no_pcm = 1,
852 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
853 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
854 },
855 {
856 .name = LPASS_BE_INT_BT_SCO_TX,
857 .stream_name = "Internal BT-SCO Capture",
858 .cpu_dai_name = "msm-dai-q6.12289",
859 .platform_name = "msm-pcm-routing",
860 .codec_name = "msm-stub-codec.1",
861 .codec_dai_name = "msm-stub-tx",
862 .no_pcm = 1,
863 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
864 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
865 },
866 {
867 .name = LPASS_BE_INT_FM_RX,
868 .stream_name = "Internal FM Playback",
869 .cpu_dai_name = "msm-dai-q6.12292",
870 .platform_name = "msm-pcm-routing",
871 .codec_name = "msm-stub-codec.1",
872 .codec_dai_name = "msm-stub-rx",
873 .no_pcm = 1,
874 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
875 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
876 },
877 {
878 .name = LPASS_BE_INT_FM_TX,
879 .stream_name = "Internal FM Capture",
880 .cpu_dai_name = "msm-dai-q6.12293",
881 .platform_name = "msm-pcm-routing",
882 .codec_name = "msm-stub-codec.1",
883 .codec_dai_name = "msm-stub-tx",
884 .no_pcm = 1,
885 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
886 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
887 },
888 /* HDMI BACK END DAI Link */
889 {
890 .name = LPASS_BE_HDMI,
891 .stream_name = "HDMI Playback",
892 .cpu_dai_name = "msm-dai-q6-hdmi.8",
893 .platform_name = "msm-pcm-routing",
894 .codec_name = "msm-stub-codec.1",
895 .codec_dai_name = "msm-stub-rx",
896 .no_pcm = 1,
897 .no_codec = 1,
898 .be_id = MSM_BACKEND_DAI_HDMI_RX,
899 .be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
900 },
901 /* Backend AFE DAI Links */
902 {
903 .name = LPASS_BE_AFE_PCM_RX,
904 .stream_name = "AFE Playback",
905 .cpu_dai_name = "msm-dai-q6.224",
906 .platform_name = "msm-pcm-routing",
907 .codec_name = "msm-stub-codec.1",
908 .codec_dai_name = "msm-stub-rx",
909 .no_codec = 1,
910 .no_pcm = 1,
911 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
912 },
913 {
914 .name = LPASS_BE_AFE_PCM_TX,
915 .stream_name = "AFE Capture",
916 .cpu_dai_name = "msm-dai-q6.225",
917 .platform_name = "msm-pcm-routing",
918 .codec_name = "msm-stub-codec.1",
919 .codec_dai_name = "msm-stub-tx",
920 .no_codec = 1,
921 .no_pcm = 1,
922 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
923 },
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530924 /* Incall Music BACK END DAI Link */
925 {
926 .name = LPASS_BE_VOICE_PLAYBACK_TX,
927 .stream_name = "Voice Farend Playback",
928 .cpu_dai_name = "msm-dai-q6.32773",
929 .platform_name = "msm-pcm-routing",
930 .codec_name = "msm-stub-codec.1",
931 .codec_dai_name = "msm-stub-rx",
932 .no_pcm = 1,
933 .no_codec = 1,
934 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
935 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
936 },
937 /* Incall Record Uplink BACK END DAI Link */
938 {
939 .name = LPASS_BE_INCALL_RECORD_TX,
940 .stream_name = "Voice Uplink Capture",
941 .cpu_dai_name = "msm-dai-q6.32772",
942 .platform_name = "msm-pcm-routing",
943 .codec_name = "msm-stub-codec.1",
944 .codec_dai_name = "msm-stub-tx",
945 .no_pcm = 1,
946 .no_codec = 1,
947 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
948 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
949 },
950 /* Incall Record Downlink BACK END DAI Link */
951 {
952 .name = LPASS_BE_INCALL_RECORD_RX,
953 .stream_name = "Voice Downlink Capture",
954 .cpu_dai_name = "msm-dai-q6.32771",
955 .platform_name = "msm-pcm-routing",
956 .codec_name = "msm-stub-codec.1",
957 .codec_dai_name = "msm-stub-tx",
958 .no_pcm = 1,
959 .no_codec = 1,
960 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
961 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
962 },
963};
964
965struct snd_soc_card snd_soc_card_msm8930 = {
966 .name = "msm8930-sitar-snd-card",
967 .dai_link = msm8930_dai,
968 .num_links = ARRAY_SIZE(msm8930_dai),
969};
970
971static struct platform_device *msm8930_snd_device;
972
973static int msm8930_configure_headset_mic_gpios(void)
974{
975 int ret;
976 ret = gpio_request(80, "US_EURO_SWITCH");
977 if (ret) {
978 pr_err("%s: Failed to request gpio 80\n", __func__);
979 return ret;
980 }
981 ret = gpio_direction_output(80, 0);
982 if (ret) {
983 pr_err("%s: Unable to set direction\n", __func__);
984 gpio_free(80);
985 }
986 msm8930_headset_gpios_configured = 0;
987 return 0;
988}
989static void msm8930_free_headset_mic_gpios(void)
990{
991 if (msm8930_headset_gpios_configured)
992 gpio_free(80);
993}
994
995static int __init msm8930_audio_init(void)
996{
997 int ret;
998
999 if (!cpu_is_msm8930()) {
1000 pr_err("%s: Not the right machine type\n", __func__);
1001 return -ENODEV ;
1002 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001003 mbhc_cfg.calibration = def_sitar_mbhc_cal();
1004 if (!mbhc_cfg.calibration) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001005 pr_err("Calibration data allocation failed\n");
1006 return -ENOMEM;
1007 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301008
1009 msm8930_snd_device = platform_device_alloc("soc-audio", 0);
1010 if (!msm8930_snd_device) {
1011 pr_err("Platform device allocation failed\n");
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001012 kfree(mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301013 return -ENOMEM;
1014 }
1015
1016 platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
1017 ret = platform_device_add(msm8930_snd_device);
1018 if (ret) {
1019 platform_device_put(msm8930_snd_device);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001020 kfree(mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301021 return ret;
1022 }
1023
1024 if (msm8930_configure_headset_mic_gpios()) {
1025 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1026 msm8930_headset_gpios_configured = 0;
1027 } else
1028 msm8930_headset_gpios_configured = 1;
1029
1030 return ret;
1031
1032}
1033module_init(msm8930_audio_init);
1034
1035static void __exit msm8930_audio_exit(void)
1036{
1037 if (!cpu_is_msm8930()) {
1038 pr_err("%s: Not the right machine type\n", __func__);
1039 return ;
1040 }
1041 msm8930_free_headset_mic_gpios();
1042 platform_device_unregister(msm8930_snd_device);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001043 kfree(mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301044}
1045module_exit(msm8930_audio_exit);
1046
1047MODULE_DESCRIPTION("ALSA SoC MSM8930");
1048MODULE_LICENSE("GPL v2");