blob: e254cce519d0923eb8643567cf6091e93bad33a8 [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;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080058static void *sitar_mbhc_cal;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053059
60static void msm8930_ext_control(struct snd_soc_codec *codec)
61{
62 struct snd_soc_dapm_context *dapm = &codec->dapm;
63
64 pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
65 if (msm8930_spk_control == MSM8930_SPK_ON) {
66 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080067 snd_soc_dapm_enable_pin(dapm, "Ext Spk left Neg");
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053068 } else {
69 snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080070 snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Neg");
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053071 }
72
73 snd_soc_dapm_sync(dapm);
74}
75
76static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
77 struct snd_ctl_elem_value *ucontrol)
78{
79 pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
80 ucontrol->value.integer.value[0] = msm8930_spk_control;
81 return 0;
82}
83static int msm8930_set_spk(struct snd_kcontrol *kcontrol,
84 struct snd_ctl_elem_value *ucontrol)
85{
86 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
87
88 pr_debug("%s()\n", __func__);
89 if (msm8930_spk_control == ucontrol->value.integer.value[0])
90 return 0;
91
92 msm8930_spk_control = ucontrol->value.integer.value[0];
93 msm8930_ext_control(codec);
94 return 1;
95}
96
97static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
98 struct snd_kcontrol *k, int event)
99{
100 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
101 /* TODO: add external speaker power amps support */
102 return 0;
103}
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800104
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530105int msm8930_enable_codec_ext_clk(
106 struct snd_soc_codec *codec, int enable)
107{
108 pr_debug("%s: enable = %d\n", __func__, enable);
109 if (enable) {
110 clk_users++;
111 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
112 if (clk_users != 1)
113 return 0;
114
115 if (codec_clk) {
116 clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800117 clk_prepare_enable(codec_clk);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530118 sitar_mclk_enable(codec, 1);
119 } else {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800120 pr_err("%s: Error setting Sitar MCLK\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530121 clk_users--;
122 return -EINVAL;
123 }
124 } else {
125 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
126 if (clk_users == 0)
127 return 0;
128 clk_users--;
129 if (!clk_users) {
130 pr_debug("%s: disabling MCLK. clk_users = %d\n",
131 __func__, clk_users);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800132 clk_disable_unprepare(codec_clk);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530133 sitar_mclk_enable(codec, 0);
134 }
135 }
136 return 0;
137}
138
139static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
140 struct snd_kcontrol *kcontrol, int event)
141{
142 pr_debug("%s: event = %d\n", __func__, event);
143
144 switch (event) {
145 case SND_SOC_DAPM_PRE_PMU:
146 return msm8930_enable_codec_ext_clk(w->codec, 1);
147 case SND_SOC_DAPM_POST_PMD:
148 return msm8930_enable_codec_ext_clk(w->codec, 0);
149 }
150 return 0;
151}
152
153static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
154
155 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
156 msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
157
158 SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800159 SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530160
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530161 SND_SOC_DAPM_MIC("Headset Mic", NULL),
162 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
163 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
164 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
165
166 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
167 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
168 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
169 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
170
171};
172
173static const struct snd_soc_dapm_route common_audio_map[] = {
174
175 {"RX_BIAS", NULL, "MCLK"},
176 {"LDO_H", NULL, "MCLK"},
177
178 {"MIC BIAS1 Internal1", NULL, "MCLK"},
179 {"MIC BIAS2 Internal1", NULL, "MCLK"},
180
181 /* Speaker path */
182 {"Ext Spk Left Pos", NULL, "LINEOUT1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800183 {"Ext Spk Left Neg", NULL, "LINEOUT2"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530184
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800185 /* Headset Mic */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530186 {"AMIC2", NULL, "MIC BIAS2 Internal1"},
187 {"MIC BIAS2 Internal1", NULL, "Headset Mic"},
188
189 /* Microphone path */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800190 {"AMIC1", NULL, "MIC BIAS2 Internal1"},
191 {"MIC BIAS2 Internal1", NULL, "ANCLeft Headset Mic"},
192
193 {"AMIC3", NULL, "MIC BIAS2 Internal1"},
194 {"MIC BIAS2 Internal1", NULL, "ANCRight Headset Mic"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530195
196 {"HEADPHONE", NULL, "LDO_H"},
197
198 /**
199 * The digital Mic routes are setup considering
200 * fluid as default device.
201 */
202
203 /**
204 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
205 * Digital Mic GM5 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800206 * Conncted to DMIC2 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530207 */
208 {"DMIC1", NULL, "MIC BIAS1 External"},
209 {"MIC BIAS1 External", NULL, "Digital Mic1"},
210
211 /**
212 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
213 * Digital Mic GM6 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800214 * Conncted to DMIC1 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530215 */
216 {"DMIC2", NULL, "MIC BIAS1 External"},
217 {"MIC BIAS1 External", NULL, "Digital Mic2"},
218 /**
219 * Digital Mic3. Back Bottom Digital Mic on Fluid.
220 * Digital Mic GM1 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800221 * Conncted to DMIC4 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530222 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800223 {"DMIC3", NULL, "MIC BIAS1 External"},
224 {"MIC BIAS1 External", NULL, "Digital Mic3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530225
226 /**
227 * Digital Mic4. Back top Digital Mic on Fluid.
228 * Digital Mic GM2 on CDP mainboard.
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800229 * Conncted to DMIC3 Input on Sitar codec.
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530230 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800231 {"DMIC4", NULL, "MIC BIAS1 External"},
232 {"MIC BIAS1 External", NULL, "Digital Mic4"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530233
234
235};
236
237static const char *spk_function[] = {"Off", "On"};
238static const char *slim0_rx_ch_text[] = {"One", "Two"};
239static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
240
241static const struct soc_enum msm8930_enum[] = {
242 SOC_ENUM_SINGLE_EXT(2, spk_function),
243 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
244 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
245};
246
247static const char *btsco_rate_text[] = {"8000", "16000"};
248static const struct soc_enum msm8930_btsco_enum[] = {
249 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
250};
251
252static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
253 struct snd_ctl_elem_value *ucontrol)
254{
255 pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800256 msm8930_slim_0_rx_ch);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530257 ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
258 return 0;
259}
260
261static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
262 struct snd_ctl_elem_value *ucontrol)
263{
264 msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
265
266 pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800267 msm8930_slim_0_rx_ch);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530268 return 1;
269}
270
271static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
272 struct snd_ctl_elem_value *ucontrol)
273{
274 pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
275 msm8930_slim_0_tx_ch);
276 ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
277 return 0;
278}
279
280static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
281 struct snd_ctl_elem_value *ucontrol)
282{
283 msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
284
285 pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
286 msm8930_slim_0_tx_ch);
287 return 1;
288}
289
290static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
291 struct snd_ctl_elem_value *ucontrol)
292{
293 pr_debug("%s: msm8930_btsco_rate = %d", __func__, msm8930_btsco_rate);
294 ucontrol->value.integer.value[0] = msm8930_btsco_rate;
295 return 0;
296}
297
298static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
299 struct snd_ctl_elem_value *ucontrol)
300{
301 switch (ucontrol->value.integer.value[0]) {
302 case 0:
303 msm8930_btsco_rate = BTSCO_RATE_8KHZ;
304 break;
305 case 1:
306 msm8930_btsco_rate = BTSCO_RATE_16KHZ;
307 break;
308 default:
309 msm8930_btsco_rate = BTSCO_RATE_8KHZ;
310 break;
311 }
312 pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
313 return 0;
314}
315
316static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
317 SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
318 msm8930_set_spk),
319 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
320 msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
321 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
322 msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
323};
324
325static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
326 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
327 msm8930_btsco_rate_get, msm8930_btsco_rate_put),
328};
329
330static int msm8930_btsco_init(struct snd_soc_pcm_runtime *rtd)
331{
332 int err = 0;
333 struct snd_soc_platform *platform = rtd->platform;
334
335 err = snd_soc_add_platform_controls(platform,
336 int_btsco_rate_mixer_controls,
337 ARRAY_SIZE(int_btsco_rate_mixer_controls));
338 if (err < 0)
339 return err;
340 return 0;
341}
342
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800343static void *def_sitar_mbhc_cal(void)
344{
345 void *sitar_cal;
346 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
347 u16 *btn_low, *btn_high;
348 u8 *n_ready, *n_cic, *gain;
349
350 sitar_cal = kzalloc(SITAR_MBHC_CAL_SIZE(SITAR_MBHC_DEF_BUTTONS,
351 SITAR_MBHC_DEF_RLOADS),
352 GFP_KERNEL);
353 if (!sitar_cal) {
354 pr_err("%s: out of memory\n", __func__);
355 return NULL;
356 }
357
358#define S(X, Y) ((SITAR_MBHC_CAL_GENERAL_PTR(sitar_cal)->X) = (Y))
359 S(t_ldoh, 100);
360 S(t_bg_fast_settle, 100);
361 S(t_shutdown_plug_rem, 255);
362 S(mbhc_nsa, 4);
363 S(mbhc_navg, 4);
364#undef S
365#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_DET_PTR(sitar_cal)->X) = (Y))
366 S(mic_current, SITAR_PID_MIC_5_UA);
367 S(hph_current, SITAR_PID_MIC_5_UA);
368 S(t_mic_pid, 100);
369 S(t_ins_complete, 250);
370 S(t_ins_retry, 200);
371#undef S
372#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
373 S(v_no_mic, 30);
374 S(v_hs_max, 1550);
375#undef S
376#define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
377 S(c[0], 62);
378 S(c[1], 124);
379 S(nc, 1);
380 S(n_meas, 3);
381 S(mbhc_nsc, 11);
382 S(n_btn_meas, 1);
383 S(n_btn_con, 2);
384 S(num_btn, SITAR_MBHC_DEF_BUTTONS);
385 S(v_btn_press_delta_sta, 100);
386 S(v_btn_press_delta_cic, 50);
387#undef S
388 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal);
389 btn_low = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_LOW);
390 btn_high = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_V_BTN_HIGH);
391 btn_low[0] = -50;
392 btn_high[0] = 10;
393 btn_low[1] = 11;
394 btn_high[1] = 38;
395 btn_low[2] = 39;
396 btn_high[2] = 64;
397 btn_low[3] = 65;
398 btn_high[3] = 91;
399 btn_low[4] = 92;
400 btn_high[4] = 115;
401 btn_low[5] = 116;
402 btn_high[5] = 141;
403 btn_low[6] = 142;
404 btn_high[6] = 163;
405 btn_low[7] = 164;
406 btn_high[7] = 250;
407 n_ready = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_READY);
408 n_ready[0] = 48;
409 n_ready[1] = 38;
410 n_cic = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_N_CIC);
411 n_cic[0] = 60;
412 n_cic[1] = 47;
413 gain = sitar_mbhc_cal_btn_det_mp(btn_cfg, SITAR_BTN_DET_GAIN);
414 gain[0] = 11;
415 gain[1] = 9;
416
417 return sitar_cal;
418}
419
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530420static int msm8930_hw_params(struct snd_pcm_substream *substream,
421 struct snd_pcm_hw_params *params)
422{
423 struct snd_soc_pcm_runtime *rtd = substream->private_data;
424 struct snd_soc_dai *codec_dai = rtd->codec_dai;
425 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
426 int ret = 0;
427 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
428 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
429
430 pr_debug("%s: ch=%d\n", __func__,
431 msm8930_slim_0_rx_ch);
432 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
433 ret = snd_soc_dai_get_channel_map(codec_dai,
434 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
435 if (ret < 0) {
436 pr_err("%s: failed to get codec chan map\n", __func__);
437 goto end;
438 }
439
440 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
441 msm8930_slim_0_rx_ch, rx_ch);
442 if (ret < 0) {
443 pr_err("%s: failed to set cpu chan map\n", __func__);
444 goto end;
445 }
446 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
447 msm8930_slim_0_rx_ch, rx_ch);
448 if (ret < 0) {
449 pr_err("%s: failed to set codec channel map\n",
450 __func__);
451 goto end;
452 }
453 } else {
454 ret = snd_soc_dai_get_channel_map(codec_dai,
455 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
456 if (ret < 0) {
457 pr_err("%s: failed to get codec chan map\n", __func__);
458 goto end;
459 }
460 ret = snd_soc_dai_set_channel_map(cpu_dai,
461 msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
462 if (ret < 0) {
463 pr_err("%s: failed to set cpu chan map\n", __func__);
464 goto end;
465 }
466 ret = snd_soc_dai_set_channel_map(codec_dai,
467 msm8930_slim_0_tx_ch, tx_ch, 0, 0);
468 if (ret < 0) {
469 pr_err("%s: failed to set codec channel map\n",
470 __func__);
471 goto end;
472 }
473
474 }
475end:
476 return ret;
477}
478
479static int msm8930_audrx_init(struct snd_soc_pcm_runtime *rtd)
480{
481 int err;
482 struct snd_soc_codec *codec = rtd->codec;
483 struct snd_soc_dapm_context *dapm = &codec->dapm;
484 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
485
486 pr_debug("%s()\n", __func__);
487
488
489 rtd->pmdown_time = 0;
490
491 err = snd_soc_add_controls(codec, sitar_msm8930_controls,
492 ARRAY_SIZE(sitar_msm8930_controls));
493 if (err < 0)
494 return err;
495
496 snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
497 ARRAY_SIZE(msm8930_dapm_widgets));
498
499 snd_soc_dapm_add_routes(dapm, common_audio_map,
500 ARRAY_SIZE(common_audio_map));
501
502 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800503 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Neg");
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530504
505 snd_soc_dapm_sync(dapm);
506
507 err = snd_soc_jack_new(codec, "Headset Jack",
508 (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
509 &hs_jack);
510 if (err) {
511 pr_err("failed to create new jack\n");
512 return err;
513 }
514
515 err = snd_soc_jack_new(codec, "Button Jack",
516 SND_JACK_BTN_0, &button_jack);
517 if (err) {
518 pr_err("failed to create new jack\n");
519 return err;
520 }
521 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800522
523 sitar_hs_detect(codec, &hs_jack, &button_jack, sitar_mbhc_cal,
524 SITAR_MICBIAS2, msm8930_enable_codec_ext_clk, 0,
525 SITAR_EXT_CLK_RATE);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530526 return 0;
527}
528
529static struct snd_soc_dsp_link lpa_fe_media = {
530 .playback = true,
531 .trigger = {
532 SND_SOC_DSP_TRIGGER_POST,
533 SND_SOC_DSP_TRIGGER_POST
534 },
535};
536
537static struct snd_soc_dsp_link fe_media = {
538 .playback = true,
539 .capture = true,
540 .trigger = {
541 SND_SOC_DSP_TRIGGER_POST,
542 SND_SOC_DSP_TRIGGER_POST
543 },
544};
545
546static struct snd_soc_dsp_link slimbus0_hl_media = {
547 .playback = true,
548 .capture = true,
549 .trigger = {
550 SND_SOC_DSP_TRIGGER_POST,
551 SND_SOC_DSP_TRIGGER_POST
552 },
553};
554
555static struct snd_soc_dsp_link int_fm_hl_media = {
556 .playback = true,
557 .capture = true,
558 .trigger = {
559 SND_SOC_DSP_TRIGGER_POST,
560 SND_SOC_DSP_TRIGGER_POST
561 },
562};
563
564/* bi-directional media definition for hostless PCM device */
565static struct snd_soc_dsp_link bidir_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 hdmi_rx_hl = {
575 .playback = true,
576 .trigger = {
577 SND_SOC_DSP_TRIGGER_POST,
578 SND_SOC_DSP_TRIGGER_POST
579 },
580};
581
582static int msm8930_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
583 struct snd_pcm_hw_params *params)
584{
585 struct snd_interval *rate = hw_param_interval(params,
586 SNDRV_PCM_HW_PARAM_RATE);
587
588 struct snd_interval *channels = hw_param_interval(params,
589 SNDRV_PCM_HW_PARAM_CHANNELS);
590
591 pr_debug("%s()\n", __func__);
592 rate->min = rate->max = 48000;
593 channels->min = channels->max = msm8930_slim_0_rx_ch;
594
595 return 0;
596}
597
598static int msm8930_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
599 struct snd_pcm_hw_params *params)
600{
601 struct snd_interval *rate = hw_param_interval(params,
602 SNDRV_PCM_HW_PARAM_RATE);
603
604 struct snd_interval *channels = hw_param_interval(params,
605 SNDRV_PCM_HW_PARAM_CHANNELS);
606
607 pr_debug("%s()\n", __func__);
608 rate->min = rate->max = 48000;
609 channels->min = channels->max = msm8930_slim_0_tx_ch;
610
611 return 0;
612}
613
614static int msm8930_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
615 struct snd_pcm_hw_params *params)
616{
617 struct snd_interval *rate = hw_param_interval(params,
618 SNDRV_PCM_HW_PARAM_RATE);
619
620 pr_debug("%s()\n", __func__);
621 rate->min = rate->max = 48000;
622
623 return 0;
624}
625
626static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
627 struct snd_pcm_hw_params *params)
628{
629 struct snd_interval *rate = hw_param_interval(params,
630 SNDRV_PCM_HW_PARAM_RATE);
631
632 struct snd_interval *channels = hw_param_interval(params,
633 SNDRV_PCM_HW_PARAM_CHANNELS);
634
635 rate->min = rate->max = 48000;
636 channels->min = channels->max = 2;
637
638 return 0;
639}
640
641static int msm8930_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
642 struct snd_pcm_hw_params *params)
643{
644 struct snd_interval *rate = hw_param_interval(params,
645 SNDRV_PCM_HW_PARAM_RATE);
646
647 struct snd_interval *channels = hw_param_interval(params,
648 SNDRV_PCM_HW_PARAM_CHANNELS);
649
650 rate->min = rate->max = msm8930_btsco_rate;
651 channels->min = channels->max = msm8930_btsco_ch;
652
653 return 0;
654}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530655
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530656static int msm8930_startup(struct snd_pcm_substream *substream)
657{
658 pr_debug("%s(): substream = %s stream = %d\n", __func__,
659 substream->name, substream->stream);
660 return 0;
661}
662
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530663static void msm8930_shutdown(struct snd_pcm_substream *substream)
664{
665 pr_debug("%s(): substream = %s stream = %d\n", __func__,
666 substream->name, substream->stream);
667}
668
669static struct snd_soc_ops msm8930_be_ops = {
670 .startup = msm8930_startup,
671 .hw_params = msm8930_hw_params,
672 .shutdown = msm8930_shutdown,
673};
674
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530675/* Digital audio interface glue - connects codec <---> CPU */
676static struct snd_soc_dai_link msm8930_dai[] = {
677 /* FrontEnd DAI Links */
678 {
679 .name = "MSM8930 Media1",
680 .stream_name = "MultiMedia1",
681 .cpu_dai_name = "MultiMedia1",
682 .platform_name = "msm-pcm-dsp",
683 .dynamic = 1,
684 .dsp_link = &fe_media,
685 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
686 },
687 {
688 .name = "MSM8930 Media2",
689 .stream_name = "MultiMedia2",
690 .cpu_dai_name = "MultiMedia2",
691 .platform_name = "msm-pcm-dsp",
692 .dynamic = 1,
693 .dsp_link = &fe_media,
694 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
695 },
696 {
697 .name = "Circuit-Switch Voice",
698 .stream_name = "CS-Voice",
699 .cpu_dai_name = "CS-VOICE",
700 .platform_name = "msm-pcm-voice",
701 .dynamic = 1,
702 .dsp_link = &fe_media,
703 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
704 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
705 .ignore_suspend = 1,
706 },
707 {
708 .name = "MSM VoIP",
709 .stream_name = "VoIP",
710 .cpu_dai_name = "VoIP",
711 .platform_name = "msm-voip-dsp",
712 .dynamic = 1,
713 .dsp_link = &fe_media,
714 .be_id = MSM_FRONTEND_DAI_VOIP,
715 },
716 {
717 .name = "MSM8930 LPA",
718 .stream_name = "LPA",
719 .cpu_dai_name = "MultiMedia3",
720 .platform_name = "msm-pcm-lpa",
721 .dynamic = 1,
722 .dsp_link = &lpa_fe_media,
723 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
724 },
725 /* Hostless PMC purpose */
726 {
727 .name = "SLIMBUS_0 Hostless",
728 .stream_name = "SLIMBUS_0 Hostless",
729 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
730 .platform_name = "msm-pcm-hostless",
731 .dynamic = 1,
732 .dsp_link = &slimbus0_hl_media,
733 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
734 .ignore_suspend = 1,
735 /* .be_id = do not care */
736 },
737 {
738 .name = "INT_FM Hostless",
739 .stream_name = "INT_FM Hostless",
740 .cpu_dai_name = "INT_FM_HOSTLESS",
741 .platform_name = "msm-pcm-hostless",
742 .dynamic = 1,
743 .dsp_link = &int_fm_hl_media,
744 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
745 .ignore_suspend = 1,
746 /* .be_id = do not care */
747 },
748 {
749 .name = "MSM AFE-PCM RX",
750 .stream_name = "AFE-PROXY RX",
751 .cpu_dai_name = "msm-dai-q6.241",
752 .codec_name = "msm-stub-codec.1",
753 .codec_dai_name = "msm-stub-rx",
754 .platform_name = "msm-pcm-afe",
755 .ignore_suspend = 1,
756 },
757 {
758 .name = "MSM AFE-PCM TX",
759 .stream_name = "AFE-PROXY TX",
760 .cpu_dai_name = "msm-dai-q6.240",
761 .codec_name = "msm-stub-codec.1",
762 .codec_dai_name = "msm-stub-tx",
763 .platform_name = "msm-pcm-afe",
764 .ignore_suspend = 1,
765 },
766 {
767 .name = "MSM8930 Compr",
768 .stream_name = "COMPR",
769 .cpu_dai_name = "MultiMedia4",
770 .platform_name = "msm-compr-dsp",
771 .dynamic = 1,
772 .dsp_link = &lpa_fe_media,
773 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
774 },
775 {
776 .name = "AUXPCM Hostless",
777 .stream_name = "AUXPCM Hostless",
778 .cpu_dai_name = "AUXPCM_HOSTLESS",
779 .platform_name = "msm-pcm-hostless",
780 .dynamic = 1,
781 .dsp_link = &bidir_hl_media,
782 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
783 .ignore_suspend = 1,
784 },
785 /* HDMI Hostless */
786 {
787 .name = "HDMI_RX_HOSTLESS",
788 .stream_name = "HDMI_RX_HOSTLESS",
789 .cpu_dai_name = "HDMI_HOSTLESS",
790 .platform_name = "msm-pcm-hostless",
791 .dynamic = 1,
792 .dsp_link = &hdmi_rx_hl,
793 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
794 .no_codec = 1,
795 .ignore_suspend = 1,
796 },
797 /* Backend DAI Links */
798 {
799 .name = LPASS_BE_SLIMBUS_0_RX,
800 .stream_name = "Slimbus Playback",
801 .cpu_dai_name = "msm-dai-q6.16384",
802 .platform_name = "msm-pcm-routing",
803 .codec_name = "sitar_codec",
804 .codec_dai_name = "sitar_rx1",
805 .no_pcm = 1,
806 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
807 .init = &msm8930_audrx_init,
808 .be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
809 .ops = &msm8930_be_ops,
810 },
811 {
812 .name = LPASS_BE_SLIMBUS_0_TX,
813 .stream_name = "Slimbus Capture",
814 .cpu_dai_name = "msm-dai-q6.16385",
815 .platform_name = "msm-pcm-routing",
816 .codec_name = "sitar_codec",
817 .codec_dai_name = "sitar_tx1",
818 .no_pcm = 1,
819 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
820 .be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
821 .ops = &msm8930_be_ops,
822 },
823 /* Backend BT/FM DAI Links */
824 {
825 .name = LPASS_BE_INT_BT_SCO_RX,
826 .stream_name = "Internal BT-SCO Playback",
827 .cpu_dai_name = "msm-dai-q6.12288",
828 .platform_name = "msm-pcm-routing",
829 .codec_name = "msm-stub-codec.1",
830 .codec_dai_name = "msm-stub-rx",
831 .init = &msm8930_btsco_init,
832 .no_pcm = 1,
833 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
834 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
835 },
836 {
837 .name = LPASS_BE_INT_BT_SCO_TX,
838 .stream_name = "Internal BT-SCO Capture",
839 .cpu_dai_name = "msm-dai-q6.12289",
840 .platform_name = "msm-pcm-routing",
841 .codec_name = "msm-stub-codec.1",
842 .codec_dai_name = "msm-stub-tx",
843 .no_pcm = 1,
844 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
845 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
846 },
847 {
848 .name = LPASS_BE_INT_FM_RX,
849 .stream_name = "Internal FM Playback",
850 .cpu_dai_name = "msm-dai-q6.12292",
851 .platform_name = "msm-pcm-routing",
852 .codec_name = "msm-stub-codec.1",
853 .codec_dai_name = "msm-stub-rx",
854 .no_pcm = 1,
855 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
856 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
857 },
858 {
859 .name = LPASS_BE_INT_FM_TX,
860 .stream_name = "Internal FM Capture",
861 .cpu_dai_name = "msm-dai-q6.12293",
862 .platform_name = "msm-pcm-routing",
863 .codec_name = "msm-stub-codec.1",
864 .codec_dai_name = "msm-stub-tx",
865 .no_pcm = 1,
866 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
867 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
868 },
869 /* HDMI BACK END DAI Link */
870 {
871 .name = LPASS_BE_HDMI,
872 .stream_name = "HDMI Playback",
873 .cpu_dai_name = "msm-dai-q6-hdmi.8",
874 .platform_name = "msm-pcm-routing",
875 .codec_name = "msm-stub-codec.1",
876 .codec_dai_name = "msm-stub-rx",
877 .no_pcm = 1,
878 .no_codec = 1,
879 .be_id = MSM_BACKEND_DAI_HDMI_RX,
880 .be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
881 },
882 /* Backend AFE DAI Links */
883 {
884 .name = LPASS_BE_AFE_PCM_RX,
885 .stream_name = "AFE Playback",
886 .cpu_dai_name = "msm-dai-q6.224",
887 .platform_name = "msm-pcm-routing",
888 .codec_name = "msm-stub-codec.1",
889 .codec_dai_name = "msm-stub-rx",
890 .no_codec = 1,
891 .no_pcm = 1,
892 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
893 },
894 {
895 .name = LPASS_BE_AFE_PCM_TX,
896 .stream_name = "AFE Capture",
897 .cpu_dai_name = "msm-dai-q6.225",
898 .platform_name = "msm-pcm-routing",
899 .codec_name = "msm-stub-codec.1",
900 .codec_dai_name = "msm-stub-tx",
901 .no_codec = 1,
902 .no_pcm = 1,
903 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
904 },
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530905 /* Incall Music BACK END DAI Link */
906 {
907 .name = LPASS_BE_VOICE_PLAYBACK_TX,
908 .stream_name = "Voice Farend Playback",
909 .cpu_dai_name = "msm-dai-q6.32773",
910 .platform_name = "msm-pcm-routing",
911 .codec_name = "msm-stub-codec.1",
912 .codec_dai_name = "msm-stub-rx",
913 .no_pcm = 1,
914 .no_codec = 1,
915 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
916 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
917 },
918 /* Incall Record Uplink BACK END DAI Link */
919 {
920 .name = LPASS_BE_INCALL_RECORD_TX,
921 .stream_name = "Voice Uplink Capture",
922 .cpu_dai_name = "msm-dai-q6.32772",
923 .platform_name = "msm-pcm-routing",
924 .codec_name = "msm-stub-codec.1",
925 .codec_dai_name = "msm-stub-tx",
926 .no_pcm = 1,
927 .no_codec = 1,
928 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
929 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
930 },
931 /* Incall Record Downlink BACK END DAI Link */
932 {
933 .name = LPASS_BE_INCALL_RECORD_RX,
934 .stream_name = "Voice Downlink Capture",
935 .cpu_dai_name = "msm-dai-q6.32771",
936 .platform_name = "msm-pcm-routing",
937 .codec_name = "msm-stub-codec.1",
938 .codec_dai_name = "msm-stub-tx",
939 .no_pcm = 1,
940 .no_codec = 1,
941 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
942 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
943 },
944};
945
946struct snd_soc_card snd_soc_card_msm8930 = {
947 .name = "msm8930-sitar-snd-card",
948 .dai_link = msm8930_dai,
949 .num_links = ARRAY_SIZE(msm8930_dai),
950};
951
952static struct platform_device *msm8930_snd_device;
953
954static int msm8930_configure_headset_mic_gpios(void)
955{
956 int ret;
957 ret = gpio_request(80, "US_EURO_SWITCH");
958 if (ret) {
959 pr_err("%s: Failed to request gpio 80\n", __func__);
960 return ret;
961 }
962 ret = gpio_direction_output(80, 0);
963 if (ret) {
964 pr_err("%s: Unable to set direction\n", __func__);
965 gpio_free(80);
966 }
967 msm8930_headset_gpios_configured = 0;
968 return 0;
969}
970static void msm8930_free_headset_mic_gpios(void)
971{
972 if (msm8930_headset_gpios_configured)
973 gpio_free(80);
974}
975
976static int __init msm8930_audio_init(void)
977{
978 int ret;
979
980 if (!cpu_is_msm8930()) {
981 pr_err("%s: Not the right machine type\n", __func__);
982 return -ENODEV ;
983 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800984 sitar_mbhc_cal = def_sitar_mbhc_cal();
985 if (!sitar_mbhc_cal) {
986 pr_err("Calibration data allocation failed\n");
987 return -ENOMEM;
988 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530989
990 msm8930_snd_device = platform_device_alloc("soc-audio", 0);
991 if (!msm8930_snd_device) {
992 pr_err("Platform device allocation failed\n");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800993 kfree(sitar_mbhc_cal);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530994 return -ENOMEM;
995 }
996
997 platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
998 ret = platform_device_add(msm8930_snd_device);
999 if (ret) {
1000 platform_device_put(msm8930_snd_device);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001001 kfree(sitar_mbhc_cal);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301002 return ret;
1003 }
1004
1005 if (msm8930_configure_headset_mic_gpios()) {
1006 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1007 msm8930_headset_gpios_configured = 0;
1008 } else
1009 msm8930_headset_gpios_configured = 1;
1010
1011 return ret;
1012
1013}
1014module_init(msm8930_audio_init);
1015
1016static void __exit msm8930_audio_exit(void)
1017{
1018 if (!cpu_is_msm8930()) {
1019 pr_err("%s: Not the right machine type\n", __func__);
1020 return ;
1021 }
1022 msm8930_free_headset_mic_gpios();
1023 platform_device_unregister(msm8930_snd_device);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001024 kfree(sitar_mbhc_cal);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301025}
1026module_exit(msm8930_audio_exit);
1027
1028MODULE_DESCRIPTION("ALSA SoC MSM8930");
1029MODULE_LICENSE("GPL v2");