blob: bfc004e79790c8d641ec9a0a4c140d127e475f85 [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>
Kiran Kandidb0a4b02011-08-23 09:32:09 -070014#include <linux/delay.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/gpio.h>
16#include <linux/mfd/pm8xxx/pm8921.h>
17#include <linux/platform_device.h>
18#include <linux/gpio.h>
19#include <linux/mfd/pm8xxx/pm8921.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>
Bradley Rubin229c6a52011-07-12 16:18:48 -070026#include <asm/mach-types.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include "msm-pcm-routing.h"
Bhalchandra Gajare0b9d4d52011-10-21 16:17:47 -070028#include "../codecs/wcd9310.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
30/* 8960 machine driver */
31
32#define PM8921_GPIO_BASE NR_GPIO_IRQS
33#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
34
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#define MSM8960_SPK_ON 1
36#define MSM8960_SPK_OFF 0
37
38#define msm8960_SLIM_0_RX_MAX_CHANNELS 2
39#define msm8960_SLIM_0_TX_MAX_CHANNELS 4
40
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070041#define BTSCO_RATE_8KHZ 8000
42#define BTSCO_RATE_16KHZ 16000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043
Kiran Kandi462acea2011-08-31 23:53:14 -070044#define BOTTOM_SPK_AMP_POS 0x1
45#define BOTTOM_SPK_AMP_NEG 0x2
46#define TOP_SPK_AMP_POS 0x4
47#define TOP_SPK_AMP_NEG 0x8
48
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070049#define GPIO_AUX_PCM_DOUT 63
50#define GPIO_AUX_PCM_DIN 64
51#define GPIO_AUX_PCM_SYNC 65
52#define GPIO_AUX_PCM_CLK 66
53
Harmandeep Singh0dd82412011-11-11 09:46:17 -080054static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
55static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056static int msm8960_spk_control;
Kiran Kandi462acea2011-08-31 23:53:14 -070057static int msm8960_ext_bottom_spk_pamp;
58static int msm8960_ext_top_spk_pamp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059static int msm8960_slim_0_rx_ch = 1;
60static int msm8960_slim_0_tx_ch = 1;
61
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070062static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
63static int msm8960_btsco_ch = 1;
64
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065struct tabla_mbhc_calibration tabla_cal = {
66 .bias = TABLA_MICBIAS2,
67 .tldoh = 100,
68 .bg_fast_settle = 100,
69 .mic_current = TABLA_PID_MIC_5_UA,
70 .mic_pid = 100,
71 .hph_current = TABLA_PID_MIC_5_UA,
72 .setup_plug_removal_delay = 1000000,
73 .shutdown_plug_removal = 100000,
74};
75
76static struct clk *codec_clk;
77static int clk_users;
78
79static int msm8960_headset_gpios_configured;
80
81static struct snd_soc_jack hs_jack;
Bradley Rubincb1e2732011-06-23 16:49:20 -070082static struct snd_soc_jack button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083
Kiran Kandi462acea2011-08-31 23:53:14 -070084static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085{
86 int ret = 0;
87
88 struct pm_gpio param = {
89 .direction = PM_GPIO_DIR_OUT,
90 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
91 .output_value = 1,
92 .pull = PM_GPIO_PULL_NO,
93 .vin_sel = PM_GPIO_VIN_S4,
94 .out_strength = PM_GPIO_STRENGTH_MED,
Kiran Kandi462acea2011-08-31 23:53:14 -070095 .
96 function = PM_GPIO_FUNC_NORMAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 };
98
Harmandeep Singh0dd82412011-11-11 09:46:17 -080099 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800101 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
Kiran Kandi462acea2011-08-31 23:53:14 -0700102 if (ret) {
103 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800104 __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700105 return;
106 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800107 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
Kiran Kandi462acea2011-08-31 23:53:14 -0700108 if (ret)
109 pr_err("%s: Failed to configure Bottom Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800110 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700111 else {
112 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800113 gpio_direction_output(bottom_spk_pamp_gpio, 1);
Kiran Kandi462acea2011-08-31 23:53:14 -0700114 }
115
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800116 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700117
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800118 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700119 if (ret) {
120 pr_err("%s: Error requesting GPIO %d\n", __func__,
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800121 top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700122 return;
123 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800124 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700125 if (ret)
Kiran Kandi462acea2011-08-31 23:53:14 -0700126 pr_err("%s: Failed to configure Top Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800127 " gpio %u\n", __func__, top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700128 else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700129 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800130 gpio_direction_output(top_spk_pamp_gpio, 1);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700131 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700132 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700133 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
134 " gpio = %u\n", __func__, spk_amp_gpio);
135 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700138
Kiran Kandi462acea2011-08-31 23:53:14 -0700139static void msm8960_ext_spk_power_amp_on(u32 spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140{
Kiran Kandi462acea2011-08-31 23:53:14 -0700141 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
142
143 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
144 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
145
146 pr_debug("%s() External Bottom Speaker Ampl already "
147 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700148 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700149 }
150
151 msm8960_ext_bottom_spk_pamp |= spk;
152
153 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
154 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
155
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800156 msm8960_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700157 pr_debug("%s: slepping 4 ms after turning on external "
158 " Bottom Speaker Ampl\n", __func__);
159 usleep_range(4000, 4000);
160 }
161
162 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
163
164 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
165 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
166
167 pr_debug("%s() External Top Speaker Ampl already"
168 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700169 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700170 }
171
172 msm8960_ext_top_spk_pamp |= spk;
173
174 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
175 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
176
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800177 msm8960_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700178 pr_debug("%s: sleeping 4 ms after turning on "
179 " external Top Speaker Ampl\n", __func__);
180 usleep_range(4000, 4000);
181 }
182 } else {
183
184 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
185 __func__, spk);
186 return;
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700187 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700188}
189
190static void msm8960_ext_spk_power_amp_off(u32 spk)
191{
192 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
193
194 if (!msm8960_ext_bottom_spk_pamp)
195 return;
196
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800197 gpio_direction_output(bottom_spk_pamp_gpio, 0);
198 gpio_free(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700199 msm8960_ext_bottom_spk_pamp = 0;
200
201 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
202 " Speaker Ampl\n", __func__);
203
204 usleep_range(4000, 4000);
205
206 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
207
208 if (!msm8960_ext_top_spk_pamp)
209 return;
210
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800211 gpio_direction_output(top_spk_pamp_gpio, 0);
212 gpio_free(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700213 msm8960_ext_top_spk_pamp = 0;
214
215 pr_debug("%s: sleeping 4 ms after turning off external Top"
216 " Spkaker Ampl\n", __func__);
217
218 usleep_range(4000, 4000);
219 } else {
220
221 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
222 __func__, spk);
223 return;
224 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227static void msm8960_ext_control(struct snd_soc_codec *codec)
228{
229 struct snd_soc_dapm_context *dapm = &codec->dapm;
230
231 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700232 if (msm8960_spk_control == MSM8960_SPK_ON) {
233 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
234 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
235 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
236 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
237 } else {
238 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
239 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
240 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
241 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
242 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243
244 snd_soc_dapm_sync(dapm);
245}
246
247static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
248 struct snd_ctl_elem_value *ucontrol)
249{
250 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
251 ucontrol->value.integer.value[0] = msm8960_spk_control;
252 return 0;
253}
254static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
255 struct snd_ctl_elem_value *ucontrol)
256{
257 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
258
259 pr_debug("%s()\n", __func__);
260 if (msm8960_spk_control == ucontrol->value.integer.value[0])
261 return 0;
262
263 msm8960_spk_control = ucontrol->value.integer.value[0];
264 msm8960_ext_control(codec);
265 return 1;
266}
267static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
268 struct snd_kcontrol *k, int event)
269{
270 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700271
272 if (SND_SOC_DAPM_EVENT_ON(event)) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700273 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
274 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
275 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
276 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
277 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
278 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
279 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
280 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
281 else {
282 pr_err("%s() Invalid Speaker Widget = %s\n",
283 __func__, w->name);
284 return -EINVAL;
285 }
286
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700287 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700288 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
289 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
290 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
291 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
292 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
293 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
294 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
295 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
296 else {
297 pr_err("%s() Invalid Speaker Widget = %s\n",
298 __func__, w->name);
299 return -EINVAL;
300 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700301 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 return 0;
303}
304
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700305static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
306 struct snd_kcontrol *kcontrol, int event)
307{
308 pr_debug("%s: event = %d\n", __func__, event);
309
310 switch (event) {
311 case SND_SOC_DAPM_PRE_PMU:
312
313 clk_users++;
314 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
315
316 if (clk_users != 1)
317 return 0;
318
319 codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
320 if (codec_clk) {
321 clk_set_rate(codec_clk, 12288000);
322 clk_enable(codec_clk);
323 tabla_mclk_enable(w->codec, 1);
324
325 } else {
326 pr_err("%s: Error setting Tabla MCLK\n", __func__);
327 clk_users--;
328 return -EINVAL;
329 }
330 break;
331 case SND_SOC_DAPM_POST_PMD:
332
333 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
334
335 if (clk_users == 0)
336 return 0;
337
338 clk_users--;
339
340 if (!clk_users) {
341 pr_debug("%s: disabling MCLK. clk_users = %d\n",
342 __func__, clk_users);
343
344 clk_disable(codec_clk);
345 clk_put(codec_clk);
346 tabla_mclk_enable(w->codec, 0);
347 }
348 break;
349 }
350 return 0;
351}
352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700354
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700355 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
356 msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
357
Kiran Kandi462acea2011-08-31 23:53:14 -0700358 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
359 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
360
361 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
362 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 SND_SOC_DAPM_MIC("Handset Mic", NULL),
365 SND_SOC_DAPM_MIC("Headset Mic", NULL),
366 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700367 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
368 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700369
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700370 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700371 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700372 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700373 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700374 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
375 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377};
378
Bradley Rubin229c6a52011-07-12 16:18:48 -0700379static const struct snd_soc_dapm_route common_audio_map[] = {
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700380
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700381 {"RX_BIAS", NULL, "MCLK"},
382 {"LDO_H", NULL, "MCLK"},
383
384 /* Speaker path */
Kiran Kandi462acea2011-08-31 23:53:14 -0700385 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
386 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700387
Kiran Kandi462acea2011-08-31 23:53:14 -0700388 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
389 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390
391 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700392 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
393 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700394
395 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700397
Patrick Laie519dd62011-09-28 12:37:11 -0700398 /**
399 * AMIC3 and AMIC4 inputs are connected to ANC microphones
400 * These mics are biased differently on CDP and FLUID
401 * routing entries below are based on bias arrangement
402 * on FLUID.
403 */
404 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
405 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
406
407 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
408 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
409
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700410 {"HEADPHONE", NULL, "LDO_H"},
411
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700412 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700413 * The digital Mic routes are setup considering
414 * fluid as default device.
415 */
416
417 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700418 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700419 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700420 * Conncted to DMIC2 Input on Tabla codec.
421 */
422 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700423 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700424
425 /**
426 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700427 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700428 * Conncted to DMIC1 Input on Tabla codec.
429 */
430 {"DMIC1", NULL, "MIC BIAS1 External"},
431 {"MIC BIAS1 External", NULL, "Digital Mic2"},
432
433 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700434 * Digital Mic3. Back Bottom Digital Mic on Fluid.
435 * Digital Mic GM1 on CDP mainboard.
436 * Conncted to DMIC4 Input on Tabla codec.
437 */
438 {"DMIC4", NULL, "MIC BIAS3 External"},
439 {"MIC BIAS3 External", NULL, "Digital Mic3"},
440
441 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700442 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700443 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700444 * Conncted to DMIC3 Input on Tabla codec.
445 */
446 {"DMIC3", NULL, "MIC BIAS3 External"},
447 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700448
449 /**
450 * Digital Mic5. Front top Digital Mic on Fluid.
451 * Digital Mic GM3 on CDP mainboard.
452 * Conncted to DMIC5 Input on Tabla codec.
453 */
454 {"DMIC5", NULL, "MIC BIAS4 External"},
455 {"MIC BIAS4 External", NULL, "Digital Mic5"},
456
Patrick Laicb7802b2011-10-04 12:39:18 -0700457 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
458 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700459 */
460 {"DMIC6", NULL, "MIC BIAS4 External"},
461 {"MIC BIAS4 External", NULL, "Digital Mic6"},
Bradley Rubin229c6a52011-07-12 16:18:48 -0700462};
463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700465static const char *slim0_rx_ch_text[] = {"One", "Two"};
466static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
467
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468static const struct soc_enum msm8960_enum[] = {
469 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700470 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
471 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472};
473
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700474static const char *btsco_rate_text[] = {"8000", "16000"};
475static const struct soc_enum msm8960_btsco_enum[] = {
476 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
477};
478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
480 struct snd_ctl_elem_value *ucontrol)
481{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700482 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700484 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 return 0;
486}
487
488static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
489 struct snd_ctl_elem_value *ucontrol)
490{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700491 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492
Patrick Lai9f4b4292011-07-16 22:11:09 -0700493 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 msm8960_slim_0_rx_ch);
495 return 1;
496}
497
498static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_value *ucontrol)
500{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700501 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700503 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 return 0;
505}
506
507static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
508 struct snd_ctl_elem_value *ucontrol)
509{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700510 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511
512 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
513 msm8960_slim_0_tx_ch);
514 return 1;
515}
516
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700517static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
518 struct snd_ctl_elem_value *ucontrol)
519{
520 pr_debug("%s: msm8960_btsco_rate = %d", __func__,
521 msm8960_btsco_rate);
522 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
523 return 0;
524}
525
526static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
527 struct snd_ctl_elem_value *ucontrol)
528{
529 switch (ucontrol->value.integer.value[0]) {
530 case 0:
531 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
532 break;
533 case 1:
534 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
535 break;
536 default:
537 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
538 break;
539 }
540 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
541 msm8960_btsco_rate);
542 return 0;
543}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544
545static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
546 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
547 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700548 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
549 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
550 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
551 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552};
553
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700554static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
555 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
556 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
557};
558
559static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
560{
561 int err = 0;
562 struct snd_soc_platform *platform = rtd->platform;
563
564 err = snd_soc_add_platform_controls(platform,
565 int_btsco_rate_mixer_controls,
566 ARRAY_SIZE(int_btsco_rate_mixer_controls));
567 if (err < 0)
568 return err;
569 return 0;
570}
571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
573{
574 int err;
575 struct snd_soc_codec *codec = rtd->codec;
576 struct snd_soc_dapm_context *dapm = &codec->dapm;
577
578 pr_debug("%s()\n", __func__);
579
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800580 if (machine_is_msm8960_liquid()) {
581 top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
582 bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
583 }
584
Kiran Kandi28ef14e2011-09-16 15:45:47 -0700585 rtd->pmdown_time = 0;
586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
588 ARRAY_SIZE(tabla_msm8960_controls));
589 if (err < 0)
590 return err;
591
592 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
593 ARRAY_SIZE(msm8960_dapm_widgets));
594
Bradley Rubin229c6a52011-07-12 16:18:48 -0700595 snd_soc_dapm_add_routes(dapm, common_audio_map,
596 ARRAY_SIZE(common_audio_map));
597
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700598 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
599 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
600 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
601 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602
603 snd_soc_dapm_sync(dapm);
604
605 err = snd_soc_jack_new(codec, "Headset Jack",
Patrick Lai456c4ea2011-11-03 16:16:10 -0700606 (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
607 &hs_jack);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 if (err) {
609 pr_err("failed to create new jack\n");
610 return err;
611 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700612
613 err = snd_soc_jack_new(codec, "Button Jack",
614 SND_JACK_BTN_0, &button_jack);
615 if (err) {
616 pr_err("failed to create new jack\n");
617 return err;
618 }
619
620 tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621
622 return 0;
623}
624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700626 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 .trigger = {
628 SND_SOC_DSP_TRIGGER_POST,
629 SND_SOC_DSP_TRIGGER_POST
630 },
631};
632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700634 .playback = true,
635 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 .trigger = {
637 SND_SOC_DSP_TRIGGER_POST,
638 SND_SOC_DSP_TRIGGER_POST
639 },
640};
641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642static struct snd_soc_dsp_link slimbus0_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700643 .playback = true,
644 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 .trigger = {
646 SND_SOC_DSP_TRIGGER_POST,
647 SND_SOC_DSP_TRIGGER_POST
648 },
649};
650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651static struct snd_soc_dsp_link int_fm_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700652 .playback = true,
653 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 .trigger = {
655 SND_SOC_DSP_TRIGGER_POST,
656 SND_SOC_DSP_TRIGGER_POST
657 },
658};
659
660static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
661 struct snd_pcm_hw_params *params)
662{
663 struct snd_interval *rate = hw_param_interval(params,
664 SNDRV_PCM_HW_PARAM_RATE);
665
666 struct snd_interval *channels = hw_param_interval(params,
667 SNDRV_PCM_HW_PARAM_CHANNELS);
668
669 pr_debug("%s()\n", __func__);
670 rate->min = rate->max = 48000;
671 channels->min = channels->max = msm8960_slim_0_rx_ch;
672
673 return 0;
674}
675
676static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
677 struct snd_pcm_hw_params *params)
678{
679 struct snd_interval *rate = hw_param_interval(params,
680 SNDRV_PCM_HW_PARAM_RATE);
681
682 struct snd_interval *channels = hw_param_interval(params,
683 SNDRV_PCM_HW_PARAM_CHANNELS);
684
685 pr_debug("%s()\n", __func__);
686 rate->min = rate->max = 48000;
687 channels->min = channels->max = msm8960_slim_0_tx_ch;
688
689 return 0;
690}
691
692static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
693 struct snd_pcm_hw_params *params)
694{
695 struct snd_interval *rate = hw_param_interval(params,
696 SNDRV_PCM_HW_PARAM_RATE);
697
698 pr_debug("%s()\n", __func__);
699 rate->min = rate->max = 48000;
700
701 return 0;
702}
703
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700704static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
705 struct snd_pcm_hw_params *params)
706{
707 struct snd_interval *rate = hw_param_interval(params,
708 SNDRV_PCM_HW_PARAM_RATE);
709
710 struct snd_interval *channels = hw_param_interval(params,
711 SNDRV_PCM_HW_PARAM_CHANNELS);
712
713 rate->min = rate->max = msm8960_btsco_rate;
714 channels->min = channels->max = msm8960_btsco_ch;
715
716 return 0;
717}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700718static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
719 struct snd_pcm_hw_params *params)
720{
721 struct snd_interval *rate = hw_param_interval(params,
722 SNDRV_PCM_HW_PARAM_RATE);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700723
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700724 struct snd_interval *channels = hw_param_interval(params,
725 SNDRV_PCM_HW_PARAM_CHANNELS);
726
727 /* PCM only supports mono output with 8khz sample rate */
728 rate->min = rate->max = 8000;
729 channels->min = channels->max = 1;
730
731 return 0;
732}
733static int msm8960_aux_pcm_get_gpios(void)
734{
735 int ret = 0;
736
737 pr_debug("%s\n", __func__);
738
739 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
740 if (ret < 0) {
741 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
742 __func__, GPIO_AUX_PCM_DOUT);
743 goto fail_dout;
744 }
745
746 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
747 if (ret < 0) {
748 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
749 __func__, GPIO_AUX_PCM_DIN);
750 goto fail_din;
751 }
752
753 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
754 if (ret < 0) {
755 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
756 __func__, GPIO_AUX_PCM_SYNC);
757 goto fail_sync;
758 }
759 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
760 if (ret < 0) {
761 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
762 __func__, GPIO_AUX_PCM_CLK);
763 goto fail_clk;
764 }
765
766 return 0;
767
768fail_clk:
769 gpio_free(GPIO_AUX_PCM_SYNC);
770fail_sync:
771 gpio_free(GPIO_AUX_PCM_DIN);
772fail_din:
773 gpio_free(GPIO_AUX_PCM_DOUT);
774fail_dout:
775
776 return ret;
777}
778
779static int msm8960_aux_pcm_free_gpios(void)
780{
781 gpio_free(GPIO_AUX_PCM_DIN);
782 gpio_free(GPIO_AUX_PCM_DOUT);
783 gpio_free(GPIO_AUX_PCM_SYNC);
784 gpio_free(GPIO_AUX_PCM_CLK);
785
786 return 0;
787}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788static int msm8960_startup(struct snd_pcm_substream *substream)
789{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700790 pr_debug("%s(): substream = %s stream = %d\n", __func__,
791 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 return 0;
793}
794
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700795static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
796{
797 int ret = 0;
798
799 pr_debug("%s(): substream = %s\n", __func__, substream->name);
800 ret = msm8960_aux_pcm_get_gpios();
801 if (ret < 0) {
802 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
803 return -EINVAL;
804 }
805 return 0;
806}
807
808static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
809{
810
811 pr_debug("%s(): substream = %s\n", __func__, substream->name);
812 msm8960_aux_pcm_free_gpios();
813}
814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815static void msm8960_shutdown(struct snd_pcm_substream *substream)
816{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700817 pr_debug("%s(): substream = %s stream = %d\n", __func__,
818 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819}
820
821static struct snd_soc_ops msm8960_be_ops = {
822 .startup = msm8960_startup,
823 .shutdown = msm8960_shutdown,
824};
825
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700826static struct snd_soc_ops msm8960_auxpcm_be_ops = {
827 .startup = msm8960_auxpcm_startup,
828 .shutdown = msm8960_auxpcm_shutdown,
829};
830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831/* Digital audio interface glue - connects codec <---> CPU */
832static struct snd_soc_dai_link msm8960_dai[] = {
833 /* FrontEnd DAI Links */
834 {
835 .name = "MSM8960 Media1",
836 .stream_name = "MultiMedia1",
837 .cpu_dai_name = "MultiMedia1",
838 .platform_name = "msm-pcm-dsp",
839 .dynamic = 1,
840 .dsp_link = &fe_media,
841 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
842 },
843 {
844 .name = "MSM8960 Media2",
845 .stream_name = "MultiMedia2",
846 .cpu_dai_name = "MultiMedia2",
847 .platform_name = "msm-pcm-dsp",
848 .dynamic = 1,
849 .dsp_link = &fe_media,
850 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
851 },
852 {
853 .name = "Circuit-Switch Voice",
854 .stream_name = "CS-Voice",
855 .cpu_dai_name = "CS-VOICE",
856 .platform_name = "msm-pcm-voice",
857 .dynamic = 1,
858 .dsp_link = &fe_media,
859 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
860 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700861 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 },
863 {
864 .name = "MSM VoIP",
865 .stream_name = "VoIP",
866 .cpu_dai_name = "VoIP",
867 .platform_name = "msm-voip-dsp",
868 .dynamic = 1,
869 .dsp_link = &fe_media,
870 .be_id = MSM_FRONTEND_DAI_VOIP,
871 },
872 {
873 .name = "MSM8960 LPA",
874 .stream_name = "LPA",
875 .cpu_dai_name = "MultiMedia3",
876 .platform_name = "msm-pcm-lpa",
877 .dynamic = 1,
878 .dsp_link = &lpa_fe_media,
879 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
880 },
881 /* Hostless PMC purpose */
882 {
883 .name = "SLIMBUS_0 Hostless",
884 .stream_name = "SLIMBUS_0 Hostless",
885 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
886 .platform_name = "msm-pcm-hostless",
887 .dynamic = 1,
888 .dsp_link = &slimbus0_hl_media,
889 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700890 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891 /* .be_id = do not care */
892 },
893 {
894 .name = "INT_FM Hostless",
895 .stream_name = "INT_FM Hostless",
896 .cpu_dai_name = "INT_FM_HOSTLESS",
897 .platform_name = "msm-pcm-hostless",
898 .dynamic = 1,
899 .dsp_link = &int_fm_hl_media,
900 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700901 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 /* .be_id = do not care */
903 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530904 {
905 .name = "MSM AFE-PCM RX",
906 .stream_name = "AFE-PROXY RX",
907 .cpu_dai_name = "msm-dai-q6.241",
908 .codec_name = "msm-stub-codec.1",
909 .codec_dai_name = "msm-stub-rx",
910 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -0700911 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530912 },
913 {
914 .name = "MSM AFE-PCM TX",
915 .stream_name = "AFE-PROXY TX",
916 .cpu_dai_name = "msm-dai-q6.240",
917 .codec_name = "msm-stub-codec.1",
918 .codec_dai_name = "msm-stub-tx",
919 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -0700920 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530921 },
Asish Bhattacharya09f9e0a2011-11-11 13:22:47 +0530922 {
923 .name = "MSM8960 Compr",
924 .stream_name = "COMPR",
925 .cpu_dai_name = "MultiMedia4",
926 .platform_name = "msm-compr-dsp",
927 .dynamic = 1,
928 .dsp_link = &lpa_fe_media,
929 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
930 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931 /* Backend DAI Links */
932 {
933 .name = LPASS_BE_SLIMBUS_0_RX,
934 .stream_name = "Slimbus Playback",
935 .cpu_dai_name = "msm-dai-q6.16384",
936 .platform_name = "msm-pcm-routing",
937 .codec_name = "tabla_codec",
938 .codec_dai_name = "tabla_rx1",
939 .no_pcm = 1,
940 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
941 .init = &msm8960_audrx_init,
942 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
943 .ops = &msm8960_be_ops,
944 },
945 {
946 .name = LPASS_BE_SLIMBUS_0_TX,
947 .stream_name = "Slimbus Capture",
948 .cpu_dai_name = "msm-dai-q6.16385",
949 .platform_name = "msm-pcm-routing",
950 .codec_name = "tabla_codec",
951 .codec_dai_name = "tabla_tx1",
952 .no_pcm = 1,
953 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
954 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
955 .ops = &msm8960_be_ops,
956 },
957 /* Backend BT/FM DAI Links */
958 {
959 .name = LPASS_BE_INT_BT_SCO_RX,
960 .stream_name = "Internal BT-SCO Playback",
961 .cpu_dai_name = "msm-dai-q6.12288",
962 .platform_name = "msm-pcm-routing",
963 .codec_name = "msm-stub-codec.1",
964 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700965 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 .no_pcm = 1,
967 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700968 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969 },
970 {
971 .name = LPASS_BE_INT_BT_SCO_TX,
972 .stream_name = "Internal BT-SCO Capture",
973 .cpu_dai_name = "msm-dai-q6.12289",
974 .platform_name = "msm-pcm-routing",
975 .codec_name = "msm-stub-codec.1",
976 .codec_dai_name = "msm-stub-tx",
977 .no_pcm = 1,
978 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700979 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 },
981 {
982 .name = LPASS_BE_INT_FM_RX,
983 .stream_name = "Internal FM Playback",
984 .cpu_dai_name = "msm-dai-q6.12292",
985 .platform_name = "msm-pcm-routing",
986 .codec_name = "msm-stub-codec.1",
987 .codec_dai_name = "msm-stub-rx",
988 .no_pcm = 1,
989 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
990 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
991 },
992 {
993 .name = LPASS_BE_INT_FM_TX,
994 .stream_name = "Internal FM Capture",
995 .cpu_dai_name = "msm-dai-q6.12293",
996 .platform_name = "msm-pcm-routing",
997 .codec_name = "msm-stub-codec.1",
998 .codec_dai_name = "msm-stub-tx",
999 .no_pcm = 1,
1000 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
1001 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1002 },
1003 /* HDMI BACK END DAI Link */
1004 {
1005 .name = LPASS_BE_HDMI,
1006 .stream_name = "HDMI Playback",
1007 .cpu_dai_name = "msm-dai-q6.8",
1008 .platform_name = "msm-pcm-routing",
1009 .codec_name = "msm-stub-codec.1",
1010 .codec_dai_name = "msm-stub-rx",
1011 .no_pcm = 1,
1012 .no_codec = 1,
1013 .be_id = MSM_BACKEND_DAI_HDMI_RX,
1014 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1015 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301016 /* Backend AFE DAI Links */
1017 {
1018 .name = LPASS_BE_AFE_PCM_RX,
1019 .stream_name = "AFE Playback",
1020 .cpu_dai_name = "msm-dai-q6.224",
1021 .platform_name = "msm-pcm-routing",
1022 .codec_name = "msm-stub-codec.1",
1023 .codec_dai_name = "msm-stub-rx",
1024 .no_codec = 1,
1025 .no_pcm = 1,
1026 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1027 },
1028 {
1029 .name = LPASS_BE_AFE_PCM_TX,
1030 .stream_name = "AFE Capture",
1031 .cpu_dai_name = "msm-dai-q6.225",
1032 .platform_name = "msm-pcm-routing",
1033 .codec_name = "msm-stub-codec.1",
1034 .codec_dai_name = "msm-stub-tx",
1035 .no_codec = 1,
1036 .no_pcm = 1,
1037 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1038 },
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001039 /* AUX PCM Backend DAI Links */
1040 {
1041 .name = LPASS_BE_AUXPCM_RX,
1042 .stream_name = "AUX PCM Playback",
1043 .cpu_dai_name = "msm-dai-q6.2",
1044 .platform_name = "msm-pcm-routing",
1045 .codec_name = "msm-stub-codec.1",
1046 .codec_dai_name = "msm-stub-rx",
1047 .no_pcm = 1,
1048 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1049 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1050 .ops = &msm8960_auxpcm_be_ops,
1051 },
1052 {
1053 .name = LPASS_BE_AUXPCM_TX,
1054 .stream_name = "AUX PCM Capture",
1055 .cpu_dai_name = "msm-dai-q6.3",
1056 .platform_name = "msm-pcm-routing",
1057 .codec_name = "msm-stub-codec.1",
1058 .codec_dai_name = "msm-stub-tx",
1059 .no_pcm = 1,
1060 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1061 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1062 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063};
1064
1065struct snd_soc_card snd_soc_card_msm8960 = {
1066 .name = "msm8960-snd-card",
1067 .dai_link = msm8960_dai,
1068 .num_links = ARRAY_SIZE(msm8960_dai),
1069};
1070
1071static struct platform_device *msm8960_snd_device;
1072
1073static int msm8960_configure_headset_mic_gpios(void)
1074{
1075 int ret;
1076 struct pm_gpio param = {
1077 .direction = PM_GPIO_DIR_OUT,
1078 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1079 .output_value = 1,
1080 .pull = PM_GPIO_PULL_NO,
1081 .vin_sel = PM_GPIO_VIN_S4,
1082 .out_strength = PM_GPIO_STRENGTH_MED,
1083 .function = PM_GPIO_FUNC_NORMAL,
1084 };
1085
1086 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1087 if (ret) {
1088 pr_err("%s: Failed to request gpio %d\n", __func__,
1089 PM8921_GPIO_PM_TO_SYS(23));
1090 return ret;
1091 }
1092
1093 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
1094 if (ret)
1095 pr_err("%s: Failed to configure gpio %d\n", __func__,
1096 PM8921_GPIO_PM_TO_SYS(23));
1097 else
1098 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
1099
1100 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1101 if (ret) {
1102 pr_err("%s: Failed to request gpio %d\n", __func__,
1103 PM8921_GPIO_PM_TO_SYS(35));
1104 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1105 return ret;
1106 }
1107 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
1108 if (ret)
1109 pr_err("%s: Failed to configure gpio %d\n", __func__,
1110 PM8921_GPIO_PM_TO_SYS(35));
1111 else
Patrick Lai2ae0a002011-09-26 14:51:09 -07001112 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113
1114 return 0;
1115}
1116static void msm8960_free_headset_mic_gpios(void)
1117{
1118 if (msm8960_headset_gpios_configured) {
1119 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1120 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
1121 }
1122}
1123
1124static int __init msm8960_audio_init(void)
1125{
1126 int ret;
1127
1128 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
1129 if (!msm8960_snd_device) {
1130 pr_err("Platform device allocation failed\n");
1131 return -ENOMEM;
1132 }
1133
1134 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
1135 ret = platform_device_add(msm8960_snd_device);
1136 if (ret) {
1137 platform_device_put(msm8960_snd_device);
1138 return ret;
1139 }
1140
1141 if (msm8960_configure_headset_mic_gpios()) {
1142 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1143 msm8960_headset_gpios_configured = 0;
1144 } else
1145 msm8960_headset_gpios_configured = 1;
1146
1147 return ret;
1148
1149}
1150module_init(msm8960_audio_init);
1151
1152static void __exit msm8960_audio_exit(void)
1153{
1154 msm8960_free_headset_mic_gpios();
1155 platform_device_unregister(msm8960_snd_device);
1156}
1157module_exit(msm8960_audio_exit);
1158
1159MODULE_DESCRIPTION("ALSA SoC MSM8960");
1160MODULE_LICENSE("GPL v2");