blob: 04b0fb0c2efbc4345c2120c401434820f3adddf1 [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 Bhattacharyab86c3472012-02-15 08:31:52 +0530132 sitar_mclk_enable(codec, 0);
Bhalchandra Gajare2776af12012-04-27 16:59:39 -0700133 clk_disable_unprepare(codec_clk);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530134 }
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
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530523 return 0;
524}
525
526static struct snd_soc_dsp_link lpa_fe_media = {
527 .playback = true,
528 .trigger = {
529 SND_SOC_DSP_TRIGGER_POST,
530 SND_SOC_DSP_TRIGGER_POST
531 },
532};
533
534static struct snd_soc_dsp_link fe_media = {
535 .playback = true,
536 .capture = true,
537 .trigger = {
538 SND_SOC_DSP_TRIGGER_POST,
539 SND_SOC_DSP_TRIGGER_POST
540 },
541};
542
543static struct snd_soc_dsp_link slimbus0_hl_media = {
544 .playback = true,
545 .capture = true,
546 .trigger = {
547 SND_SOC_DSP_TRIGGER_POST,
548 SND_SOC_DSP_TRIGGER_POST
549 },
550};
551
552static struct snd_soc_dsp_link int_fm_hl_media = {
553 .playback = true,
554 .capture = true,
555 .trigger = {
556 SND_SOC_DSP_TRIGGER_POST,
557 SND_SOC_DSP_TRIGGER_POST
558 },
559};
560
561/* bi-directional media definition for hostless PCM device */
562static struct snd_soc_dsp_link bidir_hl_media = {
563 .playback = true,
564 .capture = true,
565 .trigger = {
566 SND_SOC_DSP_TRIGGER_POST,
567 SND_SOC_DSP_TRIGGER_POST
568 },
569};
570
571static struct snd_soc_dsp_link hdmi_rx_hl = {
572 .playback = true,
573 .trigger = {
574 SND_SOC_DSP_TRIGGER_POST,
575 SND_SOC_DSP_TRIGGER_POST
576 },
577};
578
579static int msm8930_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
580 struct snd_pcm_hw_params *params)
581{
582 struct snd_interval *rate = hw_param_interval(params,
583 SNDRV_PCM_HW_PARAM_RATE);
584
585 struct snd_interval *channels = hw_param_interval(params,
586 SNDRV_PCM_HW_PARAM_CHANNELS);
587
588 pr_debug("%s()\n", __func__);
589 rate->min = rate->max = 48000;
590 channels->min = channels->max = msm8930_slim_0_rx_ch;
591
592 return 0;
593}
594
595static int msm8930_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
596 struct snd_pcm_hw_params *params)
597{
598 struct snd_interval *rate = hw_param_interval(params,
599 SNDRV_PCM_HW_PARAM_RATE);
600
601 struct snd_interval *channels = hw_param_interval(params,
602 SNDRV_PCM_HW_PARAM_CHANNELS);
603
604 pr_debug("%s()\n", __func__);
605 rate->min = rate->max = 48000;
606 channels->min = channels->max = msm8930_slim_0_tx_ch;
607
608 return 0;
609}
610
611static int msm8930_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
612 struct snd_pcm_hw_params *params)
613{
614 struct snd_interval *rate = hw_param_interval(params,
615 SNDRV_PCM_HW_PARAM_RATE);
616
617 pr_debug("%s()\n", __func__);
618 rate->min = rate->max = 48000;
619
620 return 0;
621}
622
623static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
624 struct snd_pcm_hw_params *params)
625{
626 struct snd_interval *rate = hw_param_interval(params,
627 SNDRV_PCM_HW_PARAM_RATE);
628
629 struct snd_interval *channels = hw_param_interval(params,
630 SNDRV_PCM_HW_PARAM_CHANNELS);
631
632 rate->min = rate->max = 48000;
633 channels->min = channels->max = 2;
634
635 return 0;
636}
637
638static int msm8930_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
639 struct snd_pcm_hw_params *params)
640{
641 struct snd_interval *rate = hw_param_interval(params,
642 SNDRV_PCM_HW_PARAM_RATE);
643
644 struct snd_interval *channels = hw_param_interval(params,
645 SNDRV_PCM_HW_PARAM_CHANNELS);
646
647 rate->min = rate->max = msm8930_btsco_rate;
648 channels->min = channels->max = msm8930_btsco_ch;
649
650 return 0;
651}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530652
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530653static int msm8930_startup(struct snd_pcm_substream *substream)
654{
655 pr_debug("%s(): substream = %s stream = %d\n", __func__,
656 substream->name, substream->stream);
657 return 0;
658}
659
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530660static void msm8930_shutdown(struct snd_pcm_substream *substream)
661{
662 pr_debug("%s(): substream = %s stream = %d\n", __func__,
663 substream->name, substream->stream);
664}
665
666static struct snd_soc_ops msm8930_be_ops = {
667 .startup = msm8930_startup,
668 .hw_params = msm8930_hw_params,
669 .shutdown = msm8930_shutdown,
670};
671
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530672/* Digital audio interface glue - connects codec <---> CPU */
673static struct snd_soc_dai_link msm8930_dai[] = {
674 /* FrontEnd DAI Links */
675 {
676 .name = "MSM8930 Media1",
677 .stream_name = "MultiMedia1",
678 .cpu_dai_name = "MultiMedia1",
679 .platform_name = "msm-pcm-dsp",
680 .dynamic = 1,
681 .dsp_link = &fe_media,
682 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
683 },
684 {
685 .name = "MSM8930 Media2",
686 .stream_name = "MultiMedia2",
687 .cpu_dai_name = "MultiMedia2",
688 .platform_name = "msm-pcm-dsp",
689 .dynamic = 1,
690 .dsp_link = &fe_media,
691 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
692 },
693 {
694 .name = "Circuit-Switch Voice",
695 .stream_name = "CS-Voice",
696 .cpu_dai_name = "CS-VOICE",
697 .platform_name = "msm-pcm-voice",
698 .dynamic = 1,
699 .dsp_link = &fe_media,
700 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
701 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
702 .ignore_suspend = 1,
703 },
704 {
705 .name = "MSM VoIP",
706 .stream_name = "VoIP",
707 .cpu_dai_name = "VoIP",
708 .platform_name = "msm-voip-dsp",
709 .dynamic = 1,
710 .dsp_link = &fe_media,
711 .be_id = MSM_FRONTEND_DAI_VOIP,
712 },
713 {
714 .name = "MSM8930 LPA",
715 .stream_name = "LPA",
716 .cpu_dai_name = "MultiMedia3",
717 .platform_name = "msm-pcm-lpa",
718 .dynamic = 1,
719 .dsp_link = &lpa_fe_media,
720 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
721 },
722 /* Hostless PMC purpose */
723 {
724 .name = "SLIMBUS_0 Hostless",
725 .stream_name = "SLIMBUS_0 Hostless",
726 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
727 .platform_name = "msm-pcm-hostless",
728 .dynamic = 1,
729 .dsp_link = &slimbus0_hl_media,
730 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
731 .ignore_suspend = 1,
732 /* .be_id = do not care */
733 },
734 {
735 .name = "INT_FM Hostless",
736 .stream_name = "INT_FM Hostless",
737 .cpu_dai_name = "INT_FM_HOSTLESS",
738 .platform_name = "msm-pcm-hostless",
739 .dynamic = 1,
740 .dsp_link = &int_fm_hl_media,
741 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
742 .ignore_suspend = 1,
743 /* .be_id = do not care */
744 },
745 {
746 .name = "MSM AFE-PCM RX",
747 .stream_name = "AFE-PROXY RX",
748 .cpu_dai_name = "msm-dai-q6.241",
749 .codec_name = "msm-stub-codec.1",
750 .codec_dai_name = "msm-stub-rx",
751 .platform_name = "msm-pcm-afe",
752 .ignore_suspend = 1,
753 },
754 {
755 .name = "MSM AFE-PCM TX",
756 .stream_name = "AFE-PROXY TX",
757 .cpu_dai_name = "msm-dai-q6.240",
758 .codec_name = "msm-stub-codec.1",
759 .codec_dai_name = "msm-stub-tx",
760 .platform_name = "msm-pcm-afe",
761 .ignore_suspend = 1,
762 },
763 {
764 .name = "MSM8930 Compr",
765 .stream_name = "COMPR",
766 .cpu_dai_name = "MultiMedia4",
767 .platform_name = "msm-compr-dsp",
768 .dynamic = 1,
769 .dsp_link = &lpa_fe_media,
770 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
771 },
772 {
773 .name = "AUXPCM Hostless",
774 .stream_name = "AUXPCM Hostless",
775 .cpu_dai_name = "AUXPCM_HOSTLESS",
776 .platform_name = "msm-pcm-hostless",
777 .dynamic = 1,
778 .dsp_link = &bidir_hl_media,
779 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
780 .ignore_suspend = 1,
781 },
782 /* HDMI Hostless */
783 {
784 .name = "HDMI_RX_HOSTLESS",
785 .stream_name = "HDMI_RX_HOSTLESS",
786 .cpu_dai_name = "HDMI_HOSTLESS",
787 .platform_name = "msm-pcm-hostless",
788 .dynamic = 1,
789 .dsp_link = &hdmi_rx_hl,
790 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
791 .no_codec = 1,
792 .ignore_suspend = 1,
793 },
794 /* Backend DAI Links */
795 {
796 .name = LPASS_BE_SLIMBUS_0_RX,
797 .stream_name = "Slimbus Playback",
798 .cpu_dai_name = "msm-dai-q6.16384",
799 .platform_name = "msm-pcm-routing",
800 .codec_name = "sitar_codec",
801 .codec_dai_name = "sitar_rx1",
802 .no_pcm = 1,
803 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
804 .init = &msm8930_audrx_init,
805 .be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
806 .ops = &msm8930_be_ops,
807 },
808 {
809 .name = LPASS_BE_SLIMBUS_0_TX,
810 .stream_name = "Slimbus Capture",
811 .cpu_dai_name = "msm-dai-q6.16385",
812 .platform_name = "msm-pcm-routing",
813 .codec_name = "sitar_codec",
814 .codec_dai_name = "sitar_tx1",
815 .no_pcm = 1,
816 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
817 .be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
818 .ops = &msm8930_be_ops,
819 },
820 /* Backend BT/FM DAI Links */
821 {
822 .name = LPASS_BE_INT_BT_SCO_RX,
823 .stream_name = "Internal BT-SCO Playback",
824 .cpu_dai_name = "msm-dai-q6.12288",
825 .platform_name = "msm-pcm-routing",
826 .codec_name = "msm-stub-codec.1",
827 .codec_dai_name = "msm-stub-rx",
828 .init = &msm8930_btsco_init,
829 .no_pcm = 1,
830 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
831 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
832 },
833 {
834 .name = LPASS_BE_INT_BT_SCO_TX,
835 .stream_name = "Internal BT-SCO Capture",
836 .cpu_dai_name = "msm-dai-q6.12289",
837 .platform_name = "msm-pcm-routing",
838 .codec_name = "msm-stub-codec.1",
839 .codec_dai_name = "msm-stub-tx",
840 .no_pcm = 1,
841 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
842 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
843 },
844 {
845 .name = LPASS_BE_INT_FM_RX,
846 .stream_name = "Internal FM Playback",
847 .cpu_dai_name = "msm-dai-q6.12292",
848 .platform_name = "msm-pcm-routing",
849 .codec_name = "msm-stub-codec.1",
850 .codec_dai_name = "msm-stub-rx",
851 .no_pcm = 1,
852 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
853 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
854 },
855 {
856 .name = LPASS_BE_INT_FM_TX,
857 .stream_name = "Internal FM Capture",
858 .cpu_dai_name = "msm-dai-q6.12293",
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_FM_TX,
864 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
865 },
866 /* HDMI BACK END DAI Link */
867 {
868 .name = LPASS_BE_HDMI,
869 .stream_name = "HDMI Playback",
870 .cpu_dai_name = "msm-dai-q6-hdmi.8",
871 .platform_name = "msm-pcm-routing",
872 .codec_name = "msm-stub-codec.1",
873 .codec_dai_name = "msm-stub-rx",
874 .no_pcm = 1,
875 .no_codec = 1,
876 .be_id = MSM_BACKEND_DAI_HDMI_RX,
877 .be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
878 },
879 /* Backend AFE DAI Links */
880 {
881 .name = LPASS_BE_AFE_PCM_RX,
882 .stream_name = "AFE Playback",
883 .cpu_dai_name = "msm-dai-q6.224",
884 .platform_name = "msm-pcm-routing",
885 .codec_name = "msm-stub-codec.1",
886 .codec_dai_name = "msm-stub-rx",
887 .no_codec = 1,
888 .no_pcm = 1,
889 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
890 },
891 {
892 .name = LPASS_BE_AFE_PCM_TX,
893 .stream_name = "AFE Capture",
894 .cpu_dai_name = "msm-dai-q6.225",
895 .platform_name = "msm-pcm-routing",
896 .codec_name = "msm-stub-codec.1",
897 .codec_dai_name = "msm-stub-tx",
898 .no_codec = 1,
899 .no_pcm = 1,
900 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
901 },
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530902 /* Incall Music BACK END DAI Link */
903 {
904 .name = LPASS_BE_VOICE_PLAYBACK_TX,
905 .stream_name = "Voice Farend Playback",
906 .cpu_dai_name = "msm-dai-q6.32773",
907 .platform_name = "msm-pcm-routing",
908 .codec_name = "msm-stub-codec.1",
909 .codec_dai_name = "msm-stub-rx",
910 .no_pcm = 1,
911 .no_codec = 1,
912 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
913 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
914 },
915 /* Incall Record Uplink BACK END DAI Link */
916 {
917 .name = LPASS_BE_INCALL_RECORD_TX,
918 .stream_name = "Voice Uplink Capture",
919 .cpu_dai_name = "msm-dai-q6.32772",
920 .platform_name = "msm-pcm-routing",
921 .codec_name = "msm-stub-codec.1",
922 .codec_dai_name = "msm-stub-tx",
923 .no_pcm = 1,
924 .no_codec = 1,
925 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
926 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
927 },
928 /* Incall Record Downlink BACK END DAI Link */
929 {
930 .name = LPASS_BE_INCALL_RECORD_RX,
931 .stream_name = "Voice Downlink Capture",
932 .cpu_dai_name = "msm-dai-q6.32771",
933 .platform_name = "msm-pcm-routing",
934 .codec_name = "msm-stub-codec.1",
935 .codec_dai_name = "msm-stub-tx",
936 .no_pcm = 1,
937 .no_codec = 1,
938 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
939 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
940 },
941};
942
943struct snd_soc_card snd_soc_card_msm8930 = {
944 .name = "msm8930-sitar-snd-card",
945 .dai_link = msm8930_dai,
946 .num_links = ARRAY_SIZE(msm8930_dai),
947};
948
949static struct platform_device *msm8930_snd_device;
950
951static int msm8930_configure_headset_mic_gpios(void)
952{
953 int ret;
954 ret = gpio_request(80, "US_EURO_SWITCH");
955 if (ret) {
956 pr_err("%s: Failed to request gpio 80\n", __func__);
957 return ret;
958 }
959 ret = gpio_direction_output(80, 0);
960 if (ret) {
961 pr_err("%s: Unable to set direction\n", __func__);
962 gpio_free(80);
963 }
964 msm8930_headset_gpios_configured = 0;
965 return 0;
966}
967static void msm8930_free_headset_mic_gpios(void)
968{
969 if (msm8930_headset_gpios_configured)
970 gpio_free(80);
971}
972
973static int __init msm8930_audio_init(void)
974{
975 int ret;
976
977 if (!cpu_is_msm8930()) {
978 pr_err("%s: Not the right machine type\n", __func__);
979 return -ENODEV ;
980 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800981 sitar_mbhc_cal = def_sitar_mbhc_cal();
982 if (!sitar_mbhc_cal) {
983 pr_err("Calibration data allocation failed\n");
984 return -ENOMEM;
985 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530986
987 msm8930_snd_device = platform_device_alloc("soc-audio", 0);
988 if (!msm8930_snd_device) {
989 pr_err("Platform device allocation failed\n");
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800990 kfree(sitar_mbhc_cal);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530991 return -ENOMEM;
992 }
993
994 platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
995 ret = platform_device_add(msm8930_snd_device);
996 if (ret) {
997 platform_device_put(msm8930_snd_device);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800998 kfree(sitar_mbhc_cal);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530999 return ret;
1000 }
1001
1002 if (msm8930_configure_headset_mic_gpios()) {
1003 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1004 msm8930_headset_gpios_configured = 0;
1005 } else
1006 msm8930_headset_gpios_configured = 1;
1007
1008 return ret;
1009
1010}
1011module_init(msm8930_audio_init);
1012
1013static void __exit msm8930_audio_exit(void)
1014{
1015 if (!cpu_is_msm8930()) {
1016 pr_err("%s: Not the right machine type\n", __func__);
1017 return ;
1018 }
1019 msm8930_free_headset_mic_gpios();
1020 platform_device_unregister(msm8930_snd_device);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001021 kfree(sitar_mbhc_cal);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301022}
1023module_exit(msm8930_audio_exit);
1024
1025MODULE_DESCRIPTION("ALSA SoC MSM8930");
1026MODULE_LICENSE("GPL v2");