blob: a61c0e7fd93828f5a8ed92c0a160e9ff7dbe8022 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, 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/gpio.h>
15#include <linux/mfd/pm8xxx/pm8921.h>
16#include <linux/platform_device.h>
17#include <linux/gpio.h>
18#include <linux/mfd/pm8xxx/pm8921.h>
19#include <sound/core.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22#include <sound/soc-dsp.h>
23#include <sound/pcm.h>
24#include <sound/jack.h>
Bradley Rubin229c6a52011-07-12 16:18:48 -070025#include <asm/mach-types.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include "msm-pcm-routing.h"
27#include <../codecs/wcd9310.h>
28
29/* 8960 machine driver */
30
31#define PM8921_GPIO_BASE NR_GPIO_IRQS
32#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
33
34#define MSM_CDC_PAMPL (PM8921_GPIO_PM_TO_SYS(18))
35#define MSM_CDC_PAMPR (PM8921_GPIO_PM_TO_SYS(19))
36#define MSM8960_SPK_ON 1
37#define MSM8960_SPK_OFF 0
38
39#define msm8960_SLIM_0_RX_MAX_CHANNELS 2
40#define msm8960_SLIM_0_TX_MAX_CHANNELS 4
41
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070042#define BTSCO_RATE_8KHZ 8000
43#define BTSCO_RATE_16KHZ 16000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044
45static int msm8960_spk_control;
46static int msm8960_pamp_on;
47static int msm8960_slim_0_rx_ch = 1;
48static int msm8960_slim_0_tx_ch = 1;
49
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070050static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
51static int msm8960_btsco_ch = 1;
52
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053struct tabla_mbhc_calibration tabla_cal = {
54 .bias = TABLA_MICBIAS2,
55 .tldoh = 100,
56 .bg_fast_settle = 100,
57 .mic_current = TABLA_PID_MIC_5_UA,
58 .mic_pid = 100,
59 .hph_current = TABLA_PID_MIC_5_UA,
60 .setup_plug_removal_delay = 1000000,
61 .shutdown_plug_removal = 100000,
62};
63
64static struct clk *codec_clk;
65static int clk_users;
66
67static int msm8960_headset_gpios_configured;
68
69static struct snd_soc_jack hs_jack;
Bradley Rubincb1e2732011-06-23 16:49:20 -070070static struct snd_soc_jack button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72static void codec_poweramp_on(void)
73{
74 int ret = 0;
75
76 struct pm_gpio param = {
77 .direction = PM_GPIO_DIR_OUT,
78 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
79 .output_value = 1,
80 .pull = PM_GPIO_PULL_NO,
81 .vin_sel = PM_GPIO_VIN_S4,
82 .out_strength = PM_GPIO_STRENGTH_MED,
83 .function = PM_GPIO_FUNC_NORMAL,
84 };
85
86 if (msm8960_pamp_on)
87 return;
88
89 pr_debug("%s: enable stereo spkr amp\n", __func__);
90 ret = gpio_request(MSM_CDC_PAMPL, "CDC PAMP1");
91 if (ret) {
92 pr_err("%s: Error requesting GPIO %d\n", __func__,
93 MSM_CDC_PAMPL);
94 return;
95 }
96 ret = pm8xxx_gpio_config(MSM_CDC_PAMPL, &param);
97 if (ret)
98 pr_err("%s: Failed to configure gpio %d\n", __func__,
99 MSM_CDC_PAMPL);
100 else
101 gpio_direction_output(MSM_CDC_PAMPL, 1);
102
103 ret = gpio_request(MSM_CDC_PAMPR, "CDC PAMPL");
104 if (ret) {
105 pr_err("%s: Error requesting GPIO %d\n", __func__,
106 MSM_CDC_PAMPR);
107 gpio_free(MSM_CDC_PAMPL);
108 return;
109 }
110 ret = pm8xxx_gpio_config(MSM_CDC_PAMPR, &param);
111 if (ret)
112 pr_err("%s: Failed to configure gpio %d\n", __func__,
113 MSM_CDC_PAMPR);
114 else
115 gpio_direction_output(MSM_CDC_PAMPR, 1);
116
117 msm8960_pamp_on = 1;
118}
119static void codec_poweramp_off(void)
120{
121 if (!msm8960_pamp_on)
122 return;
123
124 pr_debug("%s: disable stereo spkr amp\n", __func__);
125 gpio_direction_output(MSM_CDC_PAMPL, 0);
126 gpio_free(MSM_CDC_PAMPL);
127 gpio_direction_output(MSM_CDC_PAMPR, 0);
128 gpio_free(MSM_CDC_PAMPR);
129 msm8960_pamp_on = 0;
130}
131static void msm8960_ext_control(struct snd_soc_codec *codec)
132{
133 struct snd_soc_dapm_context *dapm = &codec->dapm;
134
135 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
136 if (msm8960_spk_control == MSM8960_SPK_ON)
137 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
138 else
139 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
140
141 snd_soc_dapm_sync(dapm);
142}
143
144static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
145 struct snd_ctl_elem_value *ucontrol)
146{
147 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
148 ucontrol->value.integer.value[0] = msm8960_spk_control;
149 return 0;
150}
151static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
152 struct snd_ctl_elem_value *ucontrol)
153{
154 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
155
156 pr_debug("%s()\n", __func__);
157 if (msm8960_spk_control == ucontrol->value.integer.value[0])
158 return 0;
159
160 msm8960_spk_control = ucontrol->value.integer.value[0];
161 msm8960_ext_control(codec);
162 return 1;
163}
164static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
165 struct snd_kcontrol *k, int event)
166{
167 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
168 if (SND_SOC_DAPM_EVENT_ON(event))
169 codec_poweramp_on();
170 else
171 codec_poweramp_off();
172 return 0;
173}
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700174static int msm8960_mclk_enable_event(struct snd_soc_dapm_widget *w,
175 struct snd_kcontrol *kcontrol, int event)
176{
177 pr_debug("%s: Event = %d\n", __func__, event);
178
179 switch (event) {
180 case SND_SOC_DAPM_PRE_PMU:
181
182 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
183
184 if (clk_users++)
185 return 0;
186 codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
187 if (codec_clk) {
188 clk_set_rate(codec_clk, 12288000);
189 clk_enable(codec_clk);
190 tabla_mclk_enable(w->codec, 1);
191
192 } else {
193 pr_err("%s: Error setting Tabla MCLK\n", __func__);
194 clk_users--;
195 return -EINVAL;
196 }
197 break;
198 }
199 return 0;
200}
201
202static int msm8960_mclk_disable_event(struct snd_soc_dapm_widget *w,
203 struct snd_kcontrol *kcontrol, int event)
204{
205 pr_debug("%s: Event = %d\n", __func__, event);
206
207 switch (event) {
208 case SND_SOC_DAPM_POST_PMD:
209 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
210
211 if (clk_users == 0)
212 return 0;
213
214 clk_users--;
215 if (!clk_users) {
216 pr_debug("%s: disabling MCLK. clk_users = %d\n",
217 __func__, clk_users);
218
219 clk_disable(codec_clk);
220 clk_put(codec_clk);
221 tabla_mclk_enable(w->codec, 0);
222 }
223 break;
224 }
225 return 0;
226}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227
228static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700229
230 SND_SOC_DAPM_PRE("CODEC MCLK_ON", msm8960_mclk_enable_event),
231 SND_SOC_DAPM_POST("CODEC MCLK_OFF", msm8960_mclk_disable_event),
232
233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 SND_SOC_DAPM_SPK("Ext Spk", msm8960_spkramp_event),
235 SND_SOC_DAPM_MIC("Handset Mic", NULL),
236 SND_SOC_DAPM_MIC("Headset Mic", NULL),
237 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700238 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
239 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700240
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700241 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700242 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700243 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700244 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700245 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
246 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248};
249
Bradley Rubin229c6a52011-07-12 16:18:48 -0700250static const struct snd_soc_dapm_route common_audio_map[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 /* Speaker path */
252 {"Ext Spk", NULL, "LINEOUT"},
253
254 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700255 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
256 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700257
258 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700260
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700261 {"HEADPHONE", NULL, "LDO_H"},
262
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700263 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700264 * The digital Mic routes are setup considering
265 * fluid as default device.
266 */
267
268 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700269 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700270 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700271 * Conncted to DMIC2 Input on Tabla codec.
272 */
273 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700274 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700275
276 /**
277 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700278 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700279 * Conncted to DMIC1 Input on Tabla codec.
280 */
281 {"DMIC1", NULL, "MIC BIAS1 External"},
282 {"MIC BIAS1 External", NULL, "Digital Mic2"},
283
284 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700285 * Digital Mic3. Back Bottom Digital Mic on Fluid.
286 * Digital Mic GM1 on CDP mainboard.
287 * Conncted to DMIC4 Input on Tabla codec.
288 */
289 {"DMIC4", NULL, "MIC BIAS3 External"},
290 {"MIC BIAS3 External", NULL, "Digital Mic3"},
291
292 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700293 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700294 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700295 * Conncted to DMIC3 Input on Tabla codec.
296 */
297 {"DMIC3", NULL, "MIC BIAS3 External"},
298 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700299
300 /**
301 * Digital Mic5. Front top Digital Mic on Fluid.
302 * Digital Mic GM3 on CDP mainboard.
303 * Conncted to DMIC5 Input on Tabla codec.
304 */
305 {"DMIC5", NULL, "MIC BIAS4 External"},
306 {"MIC BIAS4 External", NULL, "Digital Mic5"},
307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308};
309
Bradley Rubin229c6a52011-07-12 16:18:48 -0700310static const struct snd_soc_dapm_route cdp_audio_map[] = {
311 {"AMIC3", NULL, "MIC BIAS3 External"},
312 {"MIC BIAS3 External", NULL, "ANCRight Headset Mic"},
313
314 {"AMIC4", NULL, "MIC BIAS4 External"},
315 {"MIC BIAS4 External", NULL, "ANCLeft Headset Mic"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700316
317 /** Digital Mic GM4 on CDP mainboard.
318 * Connected to DMIC6 input on Tabla codec.
319 */
320 {"DMIC6", NULL, "MIC BIAS4 External"},
321 {"MIC BIAS4 External", NULL, "Digital Mic6"},
322
Bradley Rubin229c6a52011-07-12 16:18:48 -0700323};
324
325static const struct snd_soc_dapm_route fluid_audio_map[] = {
326 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
327 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
328
329 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
330 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
331};
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700334static const char *slim0_rx_ch_text[] = {"One", "Two"};
335static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337static const struct soc_enum msm8960_enum[] = {
338 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700339 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
340 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341};
342
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700343static const char *btsco_rate_text[] = {"8000", "16000"};
344static const struct soc_enum msm8960_btsco_enum[] = {
345 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
346};
347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
349 struct snd_ctl_elem_value *ucontrol)
350{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700351 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700353 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 return 0;
355}
356
357static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
358 struct snd_ctl_elem_value *ucontrol)
359{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700360 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361
Patrick Lai9f4b4292011-07-16 22:11:09 -0700362 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 msm8960_slim_0_rx_ch);
364 return 1;
365}
366
367static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
368 struct snd_ctl_elem_value *ucontrol)
369{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700370 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700372 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 return 0;
374}
375
376static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
378{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700379 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380
381 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
382 msm8960_slim_0_tx_ch);
383 return 1;
384}
385
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700386static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
387 struct snd_ctl_elem_value *ucontrol)
388{
389 pr_debug("%s: msm8960_btsco_rate = %d", __func__,
390 msm8960_btsco_rate);
391 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
392 return 0;
393}
394
395static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
396 struct snd_ctl_elem_value *ucontrol)
397{
398 switch (ucontrol->value.integer.value[0]) {
399 case 0:
400 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
401 break;
402 case 1:
403 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
404 break;
405 default:
406 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
407 break;
408 }
409 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
410 msm8960_btsco_rate);
411 return 0;
412}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413
414static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
415 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
416 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700417 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
418 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
419 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
420 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421};
422
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700423static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
424 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
425 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
426};
427
428static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
429{
430 int err = 0;
431 struct snd_soc_platform *platform = rtd->platform;
432
433 err = snd_soc_add_platform_controls(platform,
434 int_btsco_rate_mixer_controls,
435 ARRAY_SIZE(int_btsco_rate_mixer_controls));
436 if (err < 0)
437 return err;
438 return 0;
439}
440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
442{
443 int err;
444 struct snd_soc_codec *codec = rtd->codec;
445 struct snd_soc_dapm_context *dapm = &codec->dapm;
446
447 pr_debug("%s()\n", __func__);
448
449 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
450 ARRAY_SIZE(tabla_msm8960_controls));
451 if (err < 0)
452 return err;
453
454 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
455 ARRAY_SIZE(msm8960_dapm_widgets));
456
Bradley Rubin229c6a52011-07-12 16:18:48 -0700457 snd_soc_dapm_add_routes(dapm, common_audio_map,
458 ARRAY_SIZE(common_audio_map));
459
460 if (machine_is_msm8960_cdp())
461 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
462 ARRAY_SIZE(cdp_audio_map));
463 else if (machine_is_msm8960_mtp())
464 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
465 ARRAY_SIZE(cdp_audio_map));
466 else if (machine_is_msm8960_fluid())
467 snd_soc_dapm_add_routes(dapm, fluid_audio_map,
468 ARRAY_SIZE(fluid_audio_map));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469
470 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
471
472 snd_soc_dapm_sync(dapm);
473
474 err = snd_soc_jack_new(codec, "Headset Jack",
475 SND_JACK_HEADSET, &hs_jack);
476 if (err) {
477 pr_err("failed to create new jack\n");
478 return err;
479 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700480
481 err = snd_soc_jack_new(codec, "Button Jack",
482 SND_JACK_BTN_0, &button_jack);
483 if (err) {
484 pr_err("failed to create new jack\n");
485 return err;
486 }
487
488 tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489
490 return 0;
491}
492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700494 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 .trigger = {
496 SND_SOC_DSP_TRIGGER_POST,
497 SND_SOC_DSP_TRIGGER_POST
498 },
499};
500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700502 .playback = true,
503 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 .trigger = {
505 SND_SOC_DSP_TRIGGER_POST,
506 SND_SOC_DSP_TRIGGER_POST
507 },
508};
509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510static struct snd_soc_dsp_link slimbus0_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700511 .playback = true,
512 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 .trigger = {
514 SND_SOC_DSP_TRIGGER_POST,
515 SND_SOC_DSP_TRIGGER_POST
516 },
517};
518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519static struct snd_soc_dsp_link int_fm_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700520 .playback = true,
521 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 .trigger = {
523 SND_SOC_DSP_TRIGGER_POST,
524 SND_SOC_DSP_TRIGGER_POST
525 },
526};
527
528static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
529 struct snd_pcm_hw_params *params)
530{
531 struct snd_interval *rate = hw_param_interval(params,
532 SNDRV_PCM_HW_PARAM_RATE);
533
534 struct snd_interval *channels = hw_param_interval(params,
535 SNDRV_PCM_HW_PARAM_CHANNELS);
536
537 pr_debug("%s()\n", __func__);
538 rate->min = rate->max = 48000;
539 channels->min = channels->max = msm8960_slim_0_rx_ch;
540
541 return 0;
542}
543
544static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
545 struct snd_pcm_hw_params *params)
546{
547 struct snd_interval *rate = hw_param_interval(params,
548 SNDRV_PCM_HW_PARAM_RATE);
549
550 struct snd_interval *channels = hw_param_interval(params,
551 SNDRV_PCM_HW_PARAM_CHANNELS);
552
553 pr_debug("%s()\n", __func__);
554 rate->min = rate->max = 48000;
555 channels->min = channels->max = msm8960_slim_0_tx_ch;
556
557 return 0;
558}
559
560static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
561 struct snd_pcm_hw_params *params)
562{
563 struct snd_interval *rate = hw_param_interval(params,
564 SNDRV_PCM_HW_PARAM_RATE);
565
566 pr_debug("%s()\n", __func__);
567 rate->min = rate->max = 48000;
568
569 return 0;
570}
571
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700572static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
573 struct snd_pcm_hw_params *params)
574{
575 struct snd_interval *rate = hw_param_interval(params,
576 SNDRV_PCM_HW_PARAM_RATE);
577
578 struct snd_interval *channels = hw_param_interval(params,
579 SNDRV_PCM_HW_PARAM_CHANNELS);
580
581 rate->min = rate->max = msm8960_btsco_rate;
582 channels->min = channels->max = msm8960_btsco_ch;
583
584 return 0;
585}
586
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588static int msm8960_startup(struct snd_pcm_substream *substream)
589{
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700590 pr_debug("%s(): substream = %s\n", __func__, substream->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 return 0;
592}
593
594static void msm8960_shutdown(struct snd_pcm_substream *substream)
595{
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700596 pr_debug("%s(): substream = %s\n", __func__, substream->name);
597 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598}
599
600static struct snd_soc_ops msm8960_be_ops = {
601 .startup = msm8960_startup,
602 .shutdown = msm8960_shutdown,
603};
604
605/* Digital audio interface glue - connects codec <---> CPU */
606static struct snd_soc_dai_link msm8960_dai[] = {
607 /* FrontEnd DAI Links */
608 {
609 .name = "MSM8960 Media1",
610 .stream_name = "MultiMedia1",
611 .cpu_dai_name = "MultiMedia1",
612 .platform_name = "msm-pcm-dsp",
613 .dynamic = 1,
614 .dsp_link = &fe_media,
615 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
616 },
617 {
618 .name = "MSM8960 Media2",
619 .stream_name = "MultiMedia2",
620 .cpu_dai_name = "MultiMedia2",
621 .platform_name = "msm-pcm-dsp",
622 .dynamic = 1,
623 .dsp_link = &fe_media,
624 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
625 },
626 {
627 .name = "Circuit-Switch Voice",
628 .stream_name = "CS-Voice",
629 .cpu_dai_name = "CS-VOICE",
630 .platform_name = "msm-pcm-voice",
631 .dynamic = 1,
632 .dsp_link = &fe_media,
633 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
634 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
635 },
636 {
637 .name = "MSM VoIP",
638 .stream_name = "VoIP",
639 .cpu_dai_name = "VoIP",
640 .platform_name = "msm-voip-dsp",
641 .dynamic = 1,
642 .dsp_link = &fe_media,
643 .be_id = MSM_FRONTEND_DAI_VOIP,
644 },
645 {
646 .name = "MSM8960 LPA",
647 .stream_name = "LPA",
648 .cpu_dai_name = "MultiMedia3",
649 .platform_name = "msm-pcm-lpa",
650 .dynamic = 1,
651 .dsp_link = &lpa_fe_media,
652 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
653 },
654 /* Hostless PMC purpose */
655 {
656 .name = "SLIMBUS_0 Hostless",
657 .stream_name = "SLIMBUS_0 Hostless",
658 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
659 .platform_name = "msm-pcm-hostless",
660 .dynamic = 1,
661 .dsp_link = &slimbus0_hl_media,
662 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
663 /* .be_id = do not care */
664 },
665 {
666 .name = "INT_FM Hostless",
667 .stream_name = "INT_FM Hostless",
668 .cpu_dai_name = "INT_FM_HOSTLESS",
669 .platform_name = "msm-pcm-hostless",
670 .dynamic = 1,
671 .dsp_link = &int_fm_hl_media,
672 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
673 /* .be_id = do not care */
674 },
675 /* Backend DAI Links */
676 {
677 .name = LPASS_BE_SLIMBUS_0_RX,
678 .stream_name = "Slimbus Playback",
679 .cpu_dai_name = "msm-dai-q6.16384",
680 .platform_name = "msm-pcm-routing",
681 .codec_name = "tabla_codec",
682 .codec_dai_name = "tabla_rx1",
683 .no_pcm = 1,
684 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
685 .init = &msm8960_audrx_init,
686 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
687 .ops = &msm8960_be_ops,
688 },
689 {
690 .name = LPASS_BE_SLIMBUS_0_TX,
691 .stream_name = "Slimbus Capture",
692 .cpu_dai_name = "msm-dai-q6.16385",
693 .platform_name = "msm-pcm-routing",
694 .codec_name = "tabla_codec",
695 .codec_dai_name = "tabla_tx1",
696 .no_pcm = 1,
697 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
698 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
699 .ops = &msm8960_be_ops,
700 },
701 /* Backend BT/FM DAI Links */
702 {
703 .name = LPASS_BE_INT_BT_SCO_RX,
704 .stream_name = "Internal BT-SCO Playback",
705 .cpu_dai_name = "msm-dai-q6.12288",
706 .platform_name = "msm-pcm-routing",
707 .codec_name = "msm-stub-codec.1",
708 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700709 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 .no_pcm = 1,
711 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700712 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 },
714 {
715 .name = LPASS_BE_INT_BT_SCO_TX,
716 .stream_name = "Internal BT-SCO Capture",
717 .cpu_dai_name = "msm-dai-q6.12289",
718 .platform_name = "msm-pcm-routing",
719 .codec_name = "msm-stub-codec.1",
720 .codec_dai_name = "msm-stub-tx",
721 .no_pcm = 1,
722 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700723 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 },
725 {
726 .name = LPASS_BE_INT_FM_RX,
727 .stream_name = "Internal FM Playback",
728 .cpu_dai_name = "msm-dai-q6.12292",
729 .platform_name = "msm-pcm-routing",
730 .codec_name = "msm-stub-codec.1",
731 .codec_dai_name = "msm-stub-rx",
732 .no_pcm = 1,
733 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
734 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
735 },
736 {
737 .name = LPASS_BE_INT_FM_TX,
738 .stream_name = "Internal FM Capture",
739 .cpu_dai_name = "msm-dai-q6.12293",
740 .platform_name = "msm-pcm-routing",
741 .codec_name = "msm-stub-codec.1",
742 .codec_dai_name = "msm-stub-tx",
743 .no_pcm = 1,
744 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
745 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
746 },
747 /* HDMI BACK END DAI Link */
748 {
749 .name = LPASS_BE_HDMI,
750 .stream_name = "HDMI Playback",
751 .cpu_dai_name = "msm-dai-q6.8",
752 .platform_name = "msm-pcm-routing",
753 .codec_name = "msm-stub-codec.1",
754 .codec_dai_name = "msm-stub-rx",
755 .no_pcm = 1,
756 .no_codec = 1,
757 .be_id = MSM_BACKEND_DAI_HDMI_RX,
758 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
759 },
760};
761
762struct snd_soc_card snd_soc_card_msm8960 = {
763 .name = "msm8960-snd-card",
764 .dai_link = msm8960_dai,
765 .num_links = ARRAY_SIZE(msm8960_dai),
766};
767
768static struct platform_device *msm8960_snd_device;
769
770static int msm8960_configure_headset_mic_gpios(void)
771{
772 int ret;
773 struct pm_gpio param = {
774 .direction = PM_GPIO_DIR_OUT,
775 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
776 .output_value = 1,
777 .pull = PM_GPIO_PULL_NO,
778 .vin_sel = PM_GPIO_VIN_S4,
779 .out_strength = PM_GPIO_STRENGTH_MED,
780 .function = PM_GPIO_FUNC_NORMAL,
781 };
782
783 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
784 if (ret) {
785 pr_err("%s: Failed to request gpio %d\n", __func__,
786 PM8921_GPIO_PM_TO_SYS(23));
787 return ret;
788 }
789
790 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
791 if (ret)
792 pr_err("%s: Failed to configure gpio %d\n", __func__,
793 PM8921_GPIO_PM_TO_SYS(23));
794 else
795 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
796
797 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
798 if (ret) {
799 pr_err("%s: Failed to request gpio %d\n", __func__,
800 PM8921_GPIO_PM_TO_SYS(35));
801 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
802 return ret;
803 }
804 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
805 if (ret)
806 pr_err("%s: Failed to configure gpio %d\n", __func__,
807 PM8921_GPIO_PM_TO_SYS(35));
808 else
809 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 1);
810
811 return 0;
812}
813static void msm8960_free_headset_mic_gpios(void)
814{
815 if (msm8960_headset_gpios_configured) {
816 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
817 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
818 }
819}
820
821static int __init msm8960_audio_init(void)
822{
823 int ret;
824
825 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
826 if (!msm8960_snd_device) {
827 pr_err("Platform device allocation failed\n");
828 return -ENOMEM;
829 }
830
831 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
832 ret = platform_device_add(msm8960_snd_device);
833 if (ret) {
834 platform_device_put(msm8960_snd_device);
835 return ret;
836 }
837
838 if (msm8960_configure_headset_mic_gpios()) {
839 pr_err("%s Fail to configure headset mic gpios\n", __func__);
840 msm8960_headset_gpios_configured = 0;
841 } else
842 msm8960_headset_gpios_configured = 1;
843
844 return ret;
845
846}
847module_init(msm8960_audio_init);
848
849static void __exit msm8960_audio_exit(void)
850{
851 msm8960_free_headset_mic_gpios();
852 platform_device_unregister(msm8960_snd_device);
853}
854module_exit(msm8960_audio_exit);
855
856MODULE_DESCRIPTION("ALSA SoC MSM8960");
857MODULE_LICENSE("GPL v2");