blob: 5b54bac82e0e457339a3da0464b310db3336f994 [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"
28#include <../codecs/wcd9310.h>
29
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
Kiran Kandi462acea2011-08-31 23:53:14 -070035#define TOP_SPK_PAMP_GPIO (PM8921_GPIO_PM_TO_SYS(18))
36#define BOTTOM_SPK_PAMP_GPIO (PM8921_GPIO_PM_TO_SYS(19))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037#define MSM8960_SPK_ON 1
38#define MSM8960_SPK_OFF 0
39
40#define msm8960_SLIM_0_RX_MAX_CHANNELS 2
41#define msm8960_SLIM_0_TX_MAX_CHANNELS 4
42
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070043#define BTSCO_RATE_8KHZ 8000
44#define BTSCO_RATE_16KHZ 16000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045
Kiran Kandi462acea2011-08-31 23:53:14 -070046#define BOTTOM_SPK_AMP_POS 0x1
47#define BOTTOM_SPK_AMP_NEG 0x2
48#define TOP_SPK_AMP_POS 0x4
49#define TOP_SPK_AMP_NEG 0x8
50
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070051#define GPIO_AUX_PCM_DOUT 63
52#define GPIO_AUX_PCM_DIN 64
53#define GPIO_AUX_PCM_SYNC 65
54#define GPIO_AUX_PCM_CLK 66
55
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
Kiran Kandi462acea2011-08-31 23:53:14 -070099 if (spk_amp_gpio == BOTTOM_SPK_PAMP_GPIO) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100
Kiran Kandi462acea2011-08-31 23:53:14 -0700101 ret = gpio_request(BOTTOM_SPK_PAMP_GPIO, "BOTTOM_SPK_AMP");
102 if (ret) {
103 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
104 __func__, BOTTOM_SPK_PAMP_GPIO);
105 return;
106 }
107 ret = pm8xxx_gpio_config(BOTTOM_SPK_PAMP_GPIO, &param);
108 if (ret)
109 pr_err("%s: Failed to configure Bottom Spk Ampl"
110 " gpio %u\n", __func__, BOTTOM_SPK_PAMP_GPIO);
111 else {
112 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
113 gpio_direction_output(BOTTOM_SPK_PAMP_GPIO, 1);
114 }
115
116 } else if (spk_amp_gpio == TOP_SPK_PAMP_GPIO) {
117
118 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__,
Kiran Kandi462acea2011-08-31 23:53:14 -0700121 TOP_SPK_PAMP_GPIO);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700122 return;
123 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700124 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"
127 " 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__);
130 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
156 msm8960_enable_ext_spk_amp_gpio(BOTTOM_SPK_PAMP_GPIO);
157 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
177 msm8960_enable_ext_spk_amp_gpio(TOP_SPK_PAMP_GPIO);
178 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
197 gpio_direction_output(BOTTOM_SPK_PAMP_GPIO, 0);
198 gpio_free(BOTTOM_SPK_PAMP_GPIO);
199 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
211 gpio_direction_output(TOP_SPK_PAMP_GPIO, 0);
212 gpio_free(TOP_SPK_PAMP_GPIO);
213 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);
232 if (msm8960_spk_control == MSM8960_SPK_ON)
233 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
234 else
235 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
236
237 snd_soc_dapm_sync(dapm);
238}
239
240static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
241 struct snd_ctl_elem_value *ucontrol)
242{
243 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
244 ucontrol->value.integer.value[0] = msm8960_spk_control;
245 return 0;
246}
247static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
248 struct snd_ctl_elem_value *ucontrol)
249{
250 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
251
252 pr_debug("%s()\n", __func__);
253 if (msm8960_spk_control == ucontrol->value.integer.value[0])
254 return 0;
255
256 msm8960_spk_control = ucontrol->value.integer.value[0];
257 msm8960_ext_control(codec);
258 return 1;
259}
260static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
261 struct snd_kcontrol *k, int event)
262{
263 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700264
265 if (SND_SOC_DAPM_EVENT_ON(event)) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700266 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
267 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
268 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
269 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
270 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
271 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
272 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
273 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
274 else {
275 pr_err("%s() Invalid Speaker Widget = %s\n",
276 __func__, w->name);
277 return -EINVAL;
278 }
279
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700280 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700281 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
282 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
283 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
284 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
285 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
286 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
287 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
288 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
289 else {
290 pr_err("%s() Invalid Speaker Widget = %s\n",
291 __func__, w->name);
292 return -EINVAL;
293 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700294 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 return 0;
296}
297
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700298static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
299 struct snd_kcontrol *kcontrol, int event)
300{
301 pr_debug("%s: event = %d\n", __func__, event);
302
303 switch (event) {
304 case SND_SOC_DAPM_PRE_PMU:
305
306 clk_users++;
307 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
308
309 if (clk_users != 1)
310 return 0;
311
312 codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
313 if (codec_clk) {
314 clk_set_rate(codec_clk, 12288000);
315 clk_enable(codec_clk);
316 tabla_mclk_enable(w->codec, 1);
317
318 } else {
319 pr_err("%s: Error setting Tabla MCLK\n", __func__);
320 clk_users--;
321 return -EINVAL;
322 }
323 break;
324 case SND_SOC_DAPM_POST_PMD:
325
326 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
327
328 if (clk_users == 0)
329 return 0;
330
331 clk_users--;
332
333 if (!clk_users) {
334 pr_debug("%s: disabling MCLK. clk_users = %d\n",
335 __func__, clk_users);
336
337 clk_disable(codec_clk);
338 clk_put(codec_clk);
339 tabla_mclk_enable(w->codec, 0);
340 }
341 break;
342 }
343 return 0;
344}
345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700347
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700348 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
349 msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
350
Kiran Kandi462acea2011-08-31 23:53:14 -0700351 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
352 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
353
354 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
355 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 SND_SOC_DAPM_MIC("Handset Mic", NULL),
358 SND_SOC_DAPM_MIC("Headset Mic", NULL),
359 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700360 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
361 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700362
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700363 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700364 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700365 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700366 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700367 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
368 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370};
371
Bradley Rubin229c6a52011-07-12 16:18:48 -0700372static const struct snd_soc_dapm_route common_audio_map[] = {
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700373
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700374 {"RX_BIAS", NULL, "MCLK"},
375 {"LDO_H", NULL, "MCLK"},
376
377 /* Speaker path */
Kiran Kandi462acea2011-08-31 23:53:14 -0700378 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
379 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700380
Kiran Kandi462acea2011-08-31 23:53:14 -0700381 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
382 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383
384 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700385 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
386 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700387
388 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700390
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700391 {"HEADPHONE", NULL, "LDO_H"},
392
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700393 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700394 * The digital Mic routes are setup considering
395 * fluid as default device.
396 */
397
398 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700399 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700400 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700401 * Conncted to DMIC2 Input on Tabla codec.
402 */
403 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700404 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700405
406 /**
407 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700408 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700409 * Conncted to DMIC1 Input on Tabla codec.
410 */
411 {"DMIC1", NULL, "MIC BIAS1 External"},
412 {"MIC BIAS1 External", NULL, "Digital Mic2"},
413
414 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700415 * Digital Mic3. Back Bottom Digital Mic on Fluid.
416 * Digital Mic GM1 on CDP mainboard.
417 * Conncted to DMIC4 Input on Tabla codec.
418 */
419 {"DMIC4", NULL, "MIC BIAS3 External"},
420 {"MIC BIAS3 External", NULL, "Digital Mic3"},
421
422 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700423 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700424 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700425 * Conncted to DMIC3 Input on Tabla codec.
426 */
427 {"DMIC3", NULL, "MIC BIAS3 External"},
428 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700429
430 /**
431 * Digital Mic5. Front top Digital Mic on Fluid.
432 * Digital Mic GM3 on CDP mainboard.
433 * Conncted to DMIC5 Input on Tabla codec.
434 */
435 {"DMIC5", NULL, "MIC BIAS4 External"},
436 {"MIC BIAS4 External", NULL, "Digital Mic5"},
437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438};
439
Bradley Rubin229c6a52011-07-12 16:18:48 -0700440static const struct snd_soc_dapm_route cdp_audio_map[] = {
441 {"AMIC3", NULL, "MIC BIAS3 External"},
442 {"MIC BIAS3 External", NULL, "ANCRight Headset Mic"},
443
444 {"AMIC4", NULL, "MIC BIAS4 External"},
445 {"MIC BIAS4 External", NULL, "ANCLeft Headset Mic"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700446
447 /** Digital Mic GM4 on CDP mainboard.
448 * Connected to DMIC6 input on Tabla codec.
449 */
450 {"DMIC6", NULL, "MIC BIAS4 External"},
451 {"MIC BIAS4 External", NULL, "Digital Mic6"},
452
Bradley Rubin229c6a52011-07-12 16:18:48 -0700453};
454
455static const struct snd_soc_dapm_route fluid_audio_map[] = {
456 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
457 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
458
459 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
460 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
461};
462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700464static const char *slim0_rx_ch_text[] = {"One", "Two"};
465static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467static const struct soc_enum msm8960_enum[] = {
468 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700469 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
470 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471};
472
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700473static const char *btsco_rate_text[] = {"8000", "16000"};
474static const struct soc_enum msm8960_btsco_enum[] = {
475 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
476};
477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
479 struct snd_ctl_elem_value *ucontrol)
480{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700481 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700483 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 return 0;
485}
486
487static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
488 struct snd_ctl_elem_value *ucontrol)
489{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700490 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491
Patrick Lai9f4b4292011-07-16 22:11:09 -0700492 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 msm8960_slim_0_rx_ch);
494 return 1;
495}
496
497static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
498 struct snd_ctl_elem_value *ucontrol)
499{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700500 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700502 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 return 0;
504}
505
506static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
507 struct snd_ctl_elem_value *ucontrol)
508{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700509 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510
511 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
512 msm8960_slim_0_tx_ch);
513 return 1;
514}
515
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700516static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_value *ucontrol)
518{
519 pr_debug("%s: msm8960_btsco_rate = %d", __func__,
520 msm8960_btsco_rate);
521 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
522 return 0;
523}
524
525static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_value *ucontrol)
527{
528 switch (ucontrol->value.integer.value[0]) {
529 case 0:
530 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
531 break;
532 case 1:
533 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
534 break;
535 default:
536 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
537 break;
538 }
539 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
540 msm8960_btsco_rate);
541 return 0;
542}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543
544static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
545 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
546 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700547 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
548 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
549 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
550 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551};
552
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700553static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
554 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
555 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
556};
557
558static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
559{
560 int err = 0;
561 struct snd_soc_platform *platform = rtd->platform;
562
563 err = snd_soc_add_platform_controls(platform,
564 int_btsco_rate_mixer_controls,
565 ARRAY_SIZE(int_btsco_rate_mixer_controls));
566 if (err < 0)
567 return err;
568 return 0;
569}
570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
572{
573 int err;
574 struct snd_soc_codec *codec = rtd->codec;
575 struct snd_soc_dapm_context *dapm = &codec->dapm;
576
577 pr_debug("%s()\n", __func__);
578
579 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
580 ARRAY_SIZE(tabla_msm8960_controls));
581 if (err < 0)
582 return err;
583
584 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
585 ARRAY_SIZE(msm8960_dapm_widgets));
586
Bradley Rubin229c6a52011-07-12 16:18:48 -0700587 snd_soc_dapm_add_routes(dapm, common_audio_map,
588 ARRAY_SIZE(common_audio_map));
589
590 if (machine_is_msm8960_cdp())
591 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
592 ARRAY_SIZE(cdp_audio_map));
593 else if (machine_is_msm8960_mtp())
594 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
595 ARRAY_SIZE(cdp_audio_map));
596 else if (machine_is_msm8960_fluid())
597 snd_soc_dapm_add_routes(dapm, fluid_audio_map,
598 ARRAY_SIZE(fluid_audio_map));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599
600 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
601
602 snd_soc_dapm_sync(dapm);
603
604 err = snd_soc_jack_new(codec, "Headset Jack",
605 SND_JACK_HEADSET, &hs_jack);
606 if (err) {
607 pr_err("failed to create new jack\n");
608 return err;
609 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700610
611 err = snd_soc_jack_new(codec, "Button Jack",
612 SND_JACK_BTN_0, &button_jack);
613 if (err) {
614 pr_err("failed to create new jack\n");
615 return err;
616 }
617
618 tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619
620 return 0;
621}
622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700624 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 .trigger = {
626 SND_SOC_DSP_TRIGGER_POST,
627 SND_SOC_DSP_TRIGGER_POST
628 },
629};
630
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700632 .playback = true,
633 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 .trigger = {
635 SND_SOC_DSP_TRIGGER_POST,
636 SND_SOC_DSP_TRIGGER_POST
637 },
638};
639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640static struct snd_soc_dsp_link slimbus0_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700641 .playback = true,
642 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643 .trigger = {
644 SND_SOC_DSP_TRIGGER_POST,
645 SND_SOC_DSP_TRIGGER_POST
646 },
647};
648
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649static struct snd_soc_dsp_link int_fm_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700650 .playback = true,
651 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 .trigger = {
653 SND_SOC_DSP_TRIGGER_POST,
654 SND_SOC_DSP_TRIGGER_POST
655 },
656};
657
658static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
659 struct snd_pcm_hw_params *params)
660{
661 struct snd_interval *rate = hw_param_interval(params,
662 SNDRV_PCM_HW_PARAM_RATE);
663
664 struct snd_interval *channels = hw_param_interval(params,
665 SNDRV_PCM_HW_PARAM_CHANNELS);
666
667 pr_debug("%s()\n", __func__);
668 rate->min = rate->max = 48000;
669 channels->min = channels->max = msm8960_slim_0_rx_ch;
670
671 return 0;
672}
673
674static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
675 struct snd_pcm_hw_params *params)
676{
677 struct snd_interval *rate = hw_param_interval(params,
678 SNDRV_PCM_HW_PARAM_RATE);
679
680 struct snd_interval *channels = hw_param_interval(params,
681 SNDRV_PCM_HW_PARAM_CHANNELS);
682
683 pr_debug("%s()\n", __func__);
684 rate->min = rate->max = 48000;
685 channels->min = channels->max = msm8960_slim_0_tx_ch;
686
687 return 0;
688}
689
690static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
691 struct snd_pcm_hw_params *params)
692{
693 struct snd_interval *rate = hw_param_interval(params,
694 SNDRV_PCM_HW_PARAM_RATE);
695
696 pr_debug("%s()\n", __func__);
697 rate->min = rate->max = 48000;
698
699 return 0;
700}
701
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700702static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
703 struct snd_pcm_hw_params *params)
704{
705 struct snd_interval *rate = hw_param_interval(params,
706 SNDRV_PCM_HW_PARAM_RATE);
707
708 struct snd_interval *channels = hw_param_interval(params,
709 SNDRV_PCM_HW_PARAM_CHANNELS);
710
711 rate->min = rate->max = msm8960_btsco_rate;
712 channels->min = channels->max = msm8960_btsco_ch;
713
714 return 0;
715}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700716static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
717 struct snd_pcm_hw_params *params)
718{
719 struct snd_interval *rate = hw_param_interval(params,
720 SNDRV_PCM_HW_PARAM_RATE);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700721
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700722 struct snd_interval *channels = hw_param_interval(params,
723 SNDRV_PCM_HW_PARAM_CHANNELS);
724
725 /* PCM only supports mono output with 8khz sample rate */
726 rate->min = rate->max = 8000;
727 channels->min = channels->max = 1;
728
729 return 0;
730}
731static int msm8960_aux_pcm_get_gpios(void)
732{
733 int ret = 0;
734
735 pr_debug("%s\n", __func__);
736
737 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
738 if (ret < 0) {
739 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
740 __func__, GPIO_AUX_PCM_DOUT);
741 goto fail_dout;
742 }
743
744 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
745 if (ret < 0) {
746 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
747 __func__, GPIO_AUX_PCM_DIN);
748 goto fail_din;
749 }
750
751 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
752 if (ret < 0) {
753 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
754 __func__, GPIO_AUX_PCM_SYNC);
755 goto fail_sync;
756 }
757 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
758 if (ret < 0) {
759 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
760 __func__, GPIO_AUX_PCM_CLK);
761 goto fail_clk;
762 }
763
764 return 0;
765
766fail_clk:
767 gpio_free(GPIO_AUX_PCM_SYNC);
768fail_sync:
769 gpio_free(GPIO_AUX_PCM_DIN);
770fail_din:
771 gpio_free(GPIO_AUX_PCM_DOUT);
772fail_dout:
773
774 return ret;
775}
776
777static int msm8960_aux_pcm_free_gpios(void)
778{
779 gpio_free(GPIO_AUX_PCM_DIN);
780 gpio_free(GPIO_AUX_PCM_DOUT);
781 gpio_free(GPIO_AUX_PCM_SYNC);
782 gpio_free(GPIO_AUX_PCM_CLK);
783
784 return 0;
785}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786static int msm8960_startup(struct snd_pcm_substream *substream)
787{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700788 pr_debug("%s(): substream = %s stream = %d\n", __func__,
789 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790 return 0;
791}
792
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700793static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
794{
795 int ret = 0;
796
797 pr_debug("%s(): substream = %s\n", __func__, substream->name);
798 ret = msm8960_aux_pcm_get_gpios();
799 if (ret < 0) {
800 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
801 return -EINVAL;
802 }
803 return 0;
804}
805
806static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
807{
808
809 pr_debug("%s(): substream = %s\n", __func__, substream->name);
810 msm8960_aux_pcm_free_gpios();
811}
812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813static void msm8960_shutdown(struct snd_pcm_substream *substream)
814{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700815 pr_debug("%s(): substream = %s stream = %d\n", __func__,
816 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700817}
818
819static struct snd_soc_ops msm8960_be_ops = {
820 .startup = msm8960_startup,
821 .shutdown = msm8960_shutdown,
822};
823
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700824static struct snd_soc_ops msm8960_auxpcm_be_ops = {
825 .startup = msm8960_auxpcm_startup,
826 .shutdown = msm8960_auxpcm_shutdown,
827};
828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829/* Digital audio interface glue - connects codec <---> CPU */
830static struct snd_soc_dai_link msm8960_dai[] = {
831 /* FrontEnd DAI Links */
832 {
833 .name = "MSM8960 Media1",
834 .stream_name = "MultiMedia1",
835 .cpu_dai_name = "MultiMedia1",
836 .platform_name = "msm-pcm-dsp",
837 .dynamic = 1,
838 .dsp_link = &fe_media,
839 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
840 },
841 {
842 .name = "MSM8960 Media2",
843 .stream_name = "MultiMedia2",
844 .cpu_dai_name = "MultiMedia2",
845 .platform_name = "msm-pcm-dsp",
846 .dynamic = 1,
847 .dsp_link = &fe_media,
848 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
849 },
850 {
851 .name = "Circuit-Switch Voice",
852 .stream_name = "CS-Voice",
853 .cpu_dai_name = "CS-VOICE",
854 .platform_name = "msm-pcm-voice",
855 .dynamic = 1,
856 .dsp_link = &fe_media,
857 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
858 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700859 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 },
861 {
862 .name = "MSM VoIP",
863 .stream_name = "VoIP",
864 .cpu_dai_name = "VoIP",
865 .platform_name = "msm-voip-dsp",
866 .dynamic = 1,
867 .dsp_link = &fe_media,
868 .be_id = MSM_FRONTEND_DAI_VOIP,
869 },
870 {
871 .name = "MSM8960 LPA",
872 .stream_name = "LPA",
873 .cpu_dai_name = "MultiMedia3",
874 .platform_name = "msm-pcm-lpa",
875 .dynamic = 1,
876 .dsp_link = &lpa_fe_media,
877 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
878 },
879 /* Hostless PMC purpose */
880 {
881 .name = "SLIMBUS_0 Hostless",
882 .stream_name = "SLIMBUS_0 Hostless",
883 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
884 .platform_name = "msm-pcm-hostless",
885 .dynamic = 1,
886 .dsp_link = &slimbus0_hl_media,
887 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700888 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 /* .be_id = do not care */
890 },
891 {
892 .name = "INT_FM Hostless",
893 .stream_name = "INT_FM Hostless",
894 .cpu_dai_name = "INT_FM_HOSTLESS",
895 .platform_name = "msm-pcm-hostless",
896 .dynamic = 1,
897 .dsp_link = &int_fm_hl_media,
898 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700899 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 /* .be_id = do not care */
901 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530902 {
903 .name = "MSM AFE-PCM RX",
904 .stream_name = "AFE-PROXY RX",
905 .cpu_dai_name = "msm-dai-q6.241",
906 .codec_name = "msm-stub-codec.1",
907 .codec_dai_name = "msm-stub-rx",
908 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -0700909 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530910 },
911 {
912 .name = "MSM AFE-PCM TX",
913 .stream_name = "AFE-PROXY TX",
914 .cpu_dai_name = "msm-dai-q6.240",
915 .codec_name = "msm-stub-codec.1",
916 .codec_dai_name = "msm-stub-tx",
917 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -0700918 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530919 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 /* Backend DAI Links */
921 {
922 .name = LPASS_BE_SLIMBUS_0_RX,
923 .stream_name = "Slimbus Playback",
924 .cpu_dai_name = "msm-dai-q6.16384",
925 .platform_name = "msm-pcm-routing",
926 .codec_name = "tabla_codec",
927 .codec_dai_name = "tabla_rx1",
928 .no_pcm = 1,
929 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
930 .init = &msm8960_audrx_init,
931 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
932 .ops = &msm8960_be_ops,
933 },
934 {
935 .name = LPASS_BE_SLIMBUS_0_TX,
936 .stream_name = "Slimbus Capture",
937 .cpu_dai_name = "msm-dai-q6.16385",
938 .platform_name = "msm-pcm-routing",
939 .codec_name = "tabla_codec",
940 .codec_dai_name = "tabla_tx1",
941 .no_pcm = 1,
942 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
943 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
944 .ops = &msm8960_be_ops,
945 },
946 /* Backend BT/FM DAI Links */
947 {
948 .name = LPASS_BE_INT_BT_SCO_RX,
949 .stream_name = "Internal BT-SCO Playback",
950 .cpu_dai_name = "msm-dai-q6.12288",
951 .platform_name = "msm-pcm-routing",
952 .codec_name = "msm-stub-codec.1",
953 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700954 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955 .no_pcm = 1,
956 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700957 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 },
959 {
960 .name = LPASS_BE_INT_BT_SCO_TX,
961 .stream_name = "Internal BT-SCO Capture",
962 .cpu_dai_name = "msm-dai-q6.12289",
963 .platform_name = "msm-pcm-routing",
964 .codec_name = "msm-stub-codec.1",
965 .codec_dai_name = "msm-stub-tx",
966 .no_pcm = 1,
967 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
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_FM_RX,
972 .stream_name = "Internal FM Playback",
973 .cpu_dai_name = "msm-dai-q6.12292",
974 .platform_name = "msm-pcm-routing",
975 .codec_name = "msm-stub-codec.1",
976 .codec_dai_name = "msm-stub-rx",
977 .no_pcm = 1,
978 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
979 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
980 },
981 {
982 .name = LPASS_BE_INT_FM_TX,
983 .stream_name = "Internal FM Capture",
984 .cpu_dai_name = "msm-dai-q6.12293",
985 .platform_name = "msm-pcm-routing",
986 .codec_name = "msm-stub-codec.1",
987 .codec_dai_name = "msm-stub-tx",
988 .no_pcm = 1,
989 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
990 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
991 },
992 /* HDMI BACK END DAI Link */
993 {
994 .name = LPASS_BE_HDMI,
995 .stream_name = "HDMI Playback",
996 .cpu_dai_name = "msm-dai-q6.8",
997 .platform_name = "msm-pcm-routing",
998 .codec_name = "msm-stub-codec.1",
999 .codec_dai_name = "msm-stub-rx",
1000 .no_pcm = 1,
1001 .no_codec = 1,
1002 .be_id = MSM_BACKEND_DAI_HDMI_RX,
1003 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1004 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301005 /* Backend AFE DAI Links */
1006 {
1007 .name = LPASS_BE_AFE_PCM_RX,
1008 .stream_name = "AFE Playback",
1009 .cpu_dai_name = "msm-dai-q6.224",
1010 .platform_name = "msm-pcm-routing",
1011 .codec_name = "msm-stub-codec.1",
1012 .codec_dai_name = "msm-stub-rx",
1013 .no_codec = 1,
1014 .no_pcm = 1,
1015 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1016 },
1017 {
1018 .name = LPASS_BE_AFE_PCM_TX,
1019 .stream_name = "AFE Capture",
1020 .cpu_dai_name = "msm-dai-q6.225",
1021 .platform_name = "msm-pcm-routing",
1022 .codec_name = "msm-stub-codec.1",
1023 .codec_dai_name = "msm-stub-tx",
1024 .no_codec = 1,
1025 .no_pcm = 1,
1026 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1027 },
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001028 /* AUX PCM Backend DAI Links */
1029 {
1030 .name = LPASS_BE_AUXPCM_RX,
1031 .stream_name = "AUX PCM Playback",
1032 .cpu_dai_name = "msm-dai-q6.2",
1033 .platform_name = "msm-pcm-routing",
1034 .codec_name = "msm-stub-codec.1",
1035 .codec_dai_name = "msm-stub-rx",
1036 .no_pcm = 1,
1037 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1038 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1039 .ops = &msm8960_auxpcm_be_ops,
1040 },
1041 {
1042 .name = LPASS_BE_AUXPCM_TX,
1043 .stream_name = "AUX PCM Capture",
1044 .cpu_dai_name = "msm-dai-q6.3",
1045 .platform_name = "msm-pcm-routing",
1046 .codec_name = "msm-stub-codec.1",
1047 .codec_dai_name = "msm-stub-tx",
1048 .no_pcm = 1,
1049 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1050 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1051 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052};
1053
1054struct snd_soc_card snd_soc_card_msm8960 = {
1055 .name = "msm8960-snd-card",
1056 .dai_link = msm8960_dai,
1057 .num_links = ARRAY_SIZE(msm8960_dai),
1058};
1059
1060static struct platform_device *msm8960_snd_device;
1061
1062static int msm8960_configure_headset_mic_gpios(void)
1063{
1064 int ret;
1065 struct pm_gpio param = {
1066 .direction = PM_GPIO_DIR_OUT,
1067 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1068 .output_value = 1,
1069 .pull = PM_GPIO_PULL_NO,
1070 .vin_sel = PM_GPIO_VIN_S4,
1071 .out_strength = PM_GPIO_STRENGTH_MED,
1072 .function = PM_GPIO_FUNC_NORMAL,
1073 };
1074
1075 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1076 if (ret) {
1077 pr_err("%s: Failed to request gpio %d\n", __func__,
1078 PM8921_GPIO_PM_TO_SYS(23));
1079 return ret;
1080 }
1081
1082 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
1083 if (ret)
1084 pr_err("%s: Failed to configure gpio %d\n", __func__,
1085 PM8921_GPIO_PM_TO_SYS(23));
1086 else
1087 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
1088
1089 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1090 if (ret) {
1091 pr_err("%s: Failed to request gpio %d\n", __func__,
1092 PM8921_GPIO_PM_TO_SYS(35));
1093 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1094 return ret;
1095 }
1096 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
1097 if (ret)
1098 pr_err("%s: Failed to configure gpio %d\n", __func__,
1099 PM8921_GPIO_PM_TO_SYS(35));
1100 else
1101 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 1);
1102
1103 return 0;
1104}
1105static void msm8960_free_headset_mic_gpios(void)
1106{
1107 if (msm8960_headset_gpios_configured) {
1108 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1109 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
1110 }
1111}
1112
1113static int __init msm8960_audio_init(void)
1114{
1115 int ret;
1116
1117 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
1118 if (!msm8960_snd_device) {
1119 pr_err("Platform device allocation failed\n");
1120 return -ENOMEM;
1121 }
1122
1123 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
1124 ret = platform_device_add(msm8960_snd_device);
1125 if (ret) {
1126 platform_device_put(msm8960_snd_device);
1127 return ret;
1128 }
1129
1130 if (msm8960_configure_headset_mic_gpios()) {
1131 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1132 msm8960_headset_gpios_configured = 0;
1133 } else
1134 msm8960_headset_gpios_configured = 1;
1135
1136 return ret;
1137
1138}
1139module_init(msm8960_audio_init);
1140
1141static void __exit msm8960_audio_exit(void)
1142{
1143 msm8960_free_headset_mic_gpios();
1144 platform_device_unregister(msm8960_snd_device);
1145}
1146module_exit(msm8960_audio_exit);
1147
1148MODULE_DESCRIPTION("ALSA SoC MSM8960");
1149MODULE_LICENSE("GPL v2");