blob: 2e9862732ab881a9bd3c0be9c67d4ef71c0429da [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>
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -080027#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include "msm-pcm-routing.h"
Bhalchandra Gajare0b9d4d52011-10-21 16:17:47 -070029#include "../codecs/wcd9310.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030
31/* 8960 machine driver */
32
33#define PM8921_GPIO_BASE NR_GPIO_IRQS
34#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
35
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036#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
Kiran Kandi462acea2011-08-31 23:53:14 -070045#define BOTTOM_SPK_AMP_POS 0x1
46#define BOTTOM_SPK_AMP_NEG 0x2
47#define TOP_SPK_AMP_POS 0x4
48#define TOP_SPK_AMP_NEG 0x8
49
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070050#define GPIO_AUX_PCM_DOUT 63
51#define GPIO_AUX_PCM_DIN 64
52#define GPIO_AUX_PCM_SYNC 65
53#define GPIO_AUX_PCM_CLK 66
54
Harmandeep Singh0dd82412011-11-11 09:46:17 -080055static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
56static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057static int msm8960_spk_control;
Kiran Kandi462acea2011-08-31 23:53:14 -070058static int msm8960_ext_bottom_spk_pamp;
59static int msm8960_ext_top_spk_pamp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060static int msm8960_slim_0_rx_ch = 1;
61static int msm8960_slim_0_tx_ch = 1;
62
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070063static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
64static int msm8960_btsco_ch = 1;
65
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066struct tabla_mbhc_calibration tabla_cal = {
67 .bias = TABLA_MICBIAS2,
68 .tldoh = 100,
69 .bg_fast_settle = 100,
70 .mic_current = TABLA_PID_MIC_5_UA,
71 .mic_pid = 100,
72 .hph_current = TABLA_PID_MIC_5_UA,
73 .setup_plug_removal_delay = 1000000,
74 .shutdown_plug_removal = 100000,
75};
76
77static struct clk *codec_clk;
78static int clk_users;
79
80static int msm8960_headset_gpios_configured;
81
82static struct snd_soc_jack hs_jack;
Bradley Rubincb1e2732011-06-23 16:49:20 -070083static struct snd_soc_jack button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070084
Kiran Kandi462acea2011-08-31 23:53:14 -070085static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086{
87 int ret = 0;
88
89 struct pm_gpio param = {
90 .direction = PM_GPIO_DIR_OUT,
91 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
92 .output_value = 1,
93 .pull = PM_GPIO_PULL_NO,
94 .vin_sel = PM_GPIO_VIN_S4,
95 .out_strength = PM_GPIO_STRENGTH_MED,
Kiran Kandi462acea2011-08-31 23:53:14 -070096 .
97 function = PM_GPIO_FUNC_NORMAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098 };
99
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800100 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800102 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
Kiran Kandi462acea2011-08-31 23:53:14 -0700103 if (ret) {
104 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800105 __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700106 return;
107 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800108 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
Kiran Kandi462acea2011-08-31 23:53:14 -0700109 if (ret)
110 pr_err("%s: Failed to configure Bottom Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800111 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700112 else {
113 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800114 gpio_direction_output(bottom_spk_pamp_gpio, 1);
Kiran Kandi462acea2011-08-31 23:53:14 -0700115 }
116
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800117 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700118
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800119 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700120 if (ret) {
121 pr_err("%s: Error requesting GPIO %d\n", __func__,
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800122 top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700123 return;
124 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800125 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700126 if (ret)
Kiran Kandi462acea2011-08-31 23:53:14 -0700127 pr_err("%s: Failed to configure Top Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800128 " gpio %u\n", __func__, top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700129 else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700130 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800131 gpio_direction_output(top_spk_pamp_gpio, 1);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700132 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700133 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700134 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
135 " gpio = %u\n", __func__, spk_amp_gpio);
136 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700139
Kiran Kandi462acea2011-08-31 23:53:14 -0700140static void msm8960_ext_spk_power_amp_on(u32 spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141{
Kiran Kandi462acea2011-08-31 23:53:14 -0700142 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
143
144 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
145 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
146
147 pr_debug("%s() External Bottom Speaker Ampl already "
148 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700149 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700150 }
151
152 msm8960_ext_bottom_spk_pamp |= spk;
153
154 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
155 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
156
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800157 msm8960_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700158 pr_debug("%s: slepping 4 ms after turning on external "
159 " Bottom Speaker Ampl\n", __func__);
160 usleep_range(4000, 4000);
161 }
162
163 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
164
165 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
166 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
167
168 pr_debug("%s() External Top Speaker Ampl already"
169 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700170 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700171 }
172
173 msm8960_ext_top_spk_pamp |= spk;
174
175 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
176 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
177
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800178 msm8960_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700179 pr_debug("%s: sleeping 4 ms after turning on "
180 " external Top Speaker Ampl\n", __func__);
181 usleep_range(4000, 4000);
182 }
183 } else {
184
185 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
186 __func__, spk);
187 return;
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700188 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700189}
190
191static void msm8960_ext_spk_power_amp_off(u32 spk)
192{
193 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
194
195 if (!msm8960_ext_bottom_spk_pamp)
196 return;
197
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800198 gpio_direction_output(bottom_spk_pamp_gpio, 0);
199 gpio_free(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700200 msm8960_ext_bottom_spk_pamp = 0;
201
202 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
203 " Speaker Ampl\n", __func__);
204
205 usleep_range(4000, 4000);
206
207 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
208
209 if (!msm8960_ext_top_spk_pamp)
210 return;
211
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800212 gpio_direction_output(top_spk_pamp_gpio, 0);
213 gpio_free(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700214 msm8960_ext_top_spk_pamp = 0;
215
216 pr_debug("%s: sleeping 4 ms after turning off external Top"
217 " Spkaker Ampl\n", __func__);
218
219 usleep_range(4000, 4000);
220 } else {
221
222 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
223 __func__, spk);
224 return;
225 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228static void msm8960_ext_control(struct snd_soc_codec *codec)
229{
230 struct snd_soc_dapm_context *dapm = &codec->dapm;
231
232 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700233 if (msm8960_spk_control == MSM8960_SPK_ON) {
234 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
235 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
236 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
237 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
238 } else {
239 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
240 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
241 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
242 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244
245 snd_soc_dapm_sync(dapm);
246}
247
248static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
249 struct snd_ctl_elem_value *ucontrol)
250{
251 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
252 ucontrol->value.integer.value[0] = msm8960_spk_control;
253 return 0;
254}
255static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_value *ucontrol)
257{
258 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
259
260 pr_debug("%s()\n", __func__);
261 if (msm8960_spk_control == ucontrol->value.integer.value[0])
262 return 0;
263
264 msm8960_spk_control = ucontrol->value.integer.value[0];
265 msm8960_ext_control(codec);
266 return 1;
267}
268static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
269 struct snd_kcontrol *k, int event)
270{
271 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700272
273 if (SND_SOC_DAPM_EVENT_ON(event)) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700274 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
275 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
276 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
277 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
278 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
279 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
280 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
281 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
282 else {
283 pr_err("%s() Invalid Speaker Widget = %s\n",
284 __func__, w->name);
285 return -EINVAL;
286 }
287
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700288 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700289 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
290 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
291 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
292 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
293 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
294 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
295 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
296 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
297 else {
298 pr_err("%s() Invalid Speaker Widget = %s\n",
299 __func__, w->name);
300 return -EINVAL;
301 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700302 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 return 0;
304}
305
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700306static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
307 struct snd_kcontrol *kcontrol, int event)
308{
309 pr_debug("%s: event = %d\n", __func__, event);
310
311 switch (event) {
312 case SND_SOC_DAPM_PRE_PMU:
313
314 clk_users++;
315 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
316
317 if (clk_users != 1)
318 return 0;
319
320 codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
321 if (codec_clk) {
322 clk_set_rate(codec_clk, 12288000);
323 clk_enable(codec_clk);
324 tabla_mclk_enable(w->codec, 1);
325
326 } else {
327 pr_err("%s: Error setting Tabla MCLK\n", __func__);
328 clk_users--;
329 return -EINVAL;
330 }
331 break;
332 case SND_SOC_DAPM_POST_PMD:
333
334 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
335
336 if (clk_users == 0)
337 return 0;
338
339 clk_users--;
340
341 if (!clk_users) {
342 pr_debug("%s: disabling MCLK. clk_users = %d\n",
343 __func__, clk_users);
344
345 clk_disable(codec_clk);
346 clk_put(codec_clk);
347 tabla_mclk_enable(w->codec, 0);
348 }
349 break;
350 }
351 return 0;
352}
353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700355
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700356 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
357 msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
358
Kiran Kandi462acea2011-08-31 23:53:14 -0700359 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
360 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
361
362 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
363 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 SND_SOC_DAPM_MIC("Handset Mic", NULL),
366 SND_SOC_DAPM_MIC("Headset Mic", NULL),
367 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700368 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
369 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700370
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700371 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700372 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700373 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700374 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700375 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
376 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378};
379
Bradley Rubin229c6a52011-07-12 16:18:48 -0700380static const struct snd_soc_dapm_route common_audio_map[] = {
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700381
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700382 {"RX_BIAS", NULL, "MCLK"},
383 {"LDO_H", NULL, "MCLK"},
384
385 /* Speaker path */
Kiran Kandi462acea2011-08-31 23:53:14 -0700386 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
387 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700388
Kiran Kandi462acea2011-08-31 23:53:14 -0700389 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
390 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391
392 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700393 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
394 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700395
396 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700398
Patrick Laie519dd62011-09-28 12:37:11 -0700399 /**
400 * AMIC3 and AMIC4 inputs are connected to ANC microphones
401 * These mics are biased differently on CDP and FLUID
402 * routing entries below are based on bias arrangement
403 * on FLUID.
404 */
405 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
406 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
407
408 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
409 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
410
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700411 {"HEADPHONE", NULL, "LDO_H"},
412
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700413 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700414 * The digital Mic routes are setup considering
415 * fluid as default device.
416 */
417
418 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700419 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700420 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700421 * Conncted to DMIC2 Input on Tabla codec.
422 */
423 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700424 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700425
426 /**
427 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700428 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700429 * Conncted to DMIC1 Input on Tabla codec.
430 */
431 {"DMIC1", NULL, "MIC BIAS1 External"},
432 {"MIC BIAS1 External", NULL, "Digital Mic2"},
433
434 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700435 * Digital Mic3. Back Bottom Digital Mic on Fluid.
436 * Digital Mic GM1 on CDP mainboard.
437 * Conncted to DMIC4 Input on Tabla codec.
438 */
439 {"DMIC4", NULL, "MIC BIAS3 External"},
440 {"MIC BIAS3 External", NULL, "Digital Mic3"},
441
442 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700443 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700444 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700445 * Conncted to DMIC3 Input on Tabla codec.
446 */
447 {"DMIC3", NULL, "MIC BIAS3 External"},
448 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700449
450 /**
451 * Digital Mic5. Front top Digital Mic on Fluid.
452 * Digital Mic GM3 on CDP mainboard.
453 * Conncted to DMIC5 Input on Tabla codec.
454 */
455 {"DMIC5", NULL, "MIC BIAS4 External"},
456 {"MIC BIAS4 External", NULL, "Digital Mic5"},
457
Patrick Laicb7802b2011-10-04 12:39:18 -0700458 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
459 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700460 */
461 {"DMIC6", NULL, "MIC BIAS4 External"},
462 {"MIC BIAS4 External", NULL, "Digital Mic6"},
Bradley Rubin229c6a52011-07-12 16:18:48 -0700463};
464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700466static const char *slim0_rx_ch_text[] = {"One", "Two"};
467static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469static const struct soc_enum msm8960_enum[] = {
470 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700471 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
472 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473};
474
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700475static const char *btsco_rate_text[] = {"8000", "16000"};
476static const struct soc_enum msm8960_btsco_enum[] = {
477 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
478};
479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_value *ucontrol)
482{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700483 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700485 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 return 0;
487}
488
489static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_value *ucontrol)
491{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700492 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493
Patrick Lai9f4b4292011-07-16 22:11:09 -0700494 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 msm8960_slim_0_rx_ch);
496 return 1;
497}
498
499static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
500 struct snd_ctl_elem_value *ucontrol)
501{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700502 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700504 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505 return 0;
506}
507
508static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
509 struct snd_ctl_elem_value *ucontrol)
510{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700511 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512
513 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
514 msm8960_slim_0_tx_ch);
515 return 1;
516}
517
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700518static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
519 struct snd_ctl_elem_value *ucontrol)
520{
521 pr_debug("%s: msm8960_btsco_rate = %d", __func__,
522 msm8960_btsco_rate);
523 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
524 return 0;
525}
526
527static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
528 struct snd_ctl_elem_value *ucontrol)
529{
530 switch (ucontrol->value.integer.value[0]) {
531 case 0:
532 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
533 break;
534 case 1:
535 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
536 break;
537 default:
538 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
539 break;
540 }
541 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
542 msm8960_btsco_rate);
543 return 0;
544}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545
546static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
547 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
548 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700549 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
550 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
551 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
552 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553};
554
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700555static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
556 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
557 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
558};
559
560static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
561{
562 int err = 0;
563 struct snd_soc_platform *platform = rtd->platform;
564
565 err = snd_soc_add_platform_controls(platform,
566 int_btsco_rate_mixer_controls,
567 ARRAY_SIZE(int_btsco_rate_mixer_controls));
568 if (err < 0)
569 return err;
570 return 0;
571}
572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
574{
575 int err;
576 struct snd_soc_codec *codec = rtd->codec;
577 struct snd_soc_dapm_context *dapm = &codec->dapm;
578
579 pr_debug("%s()\n", __func__);
580
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800581 if (machine_is_msm8960_liquid()) {
582 top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
583 bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
584 }
585
Kiran Kandi28ef14e2011-09-16 15:45:47 -0700586 rtd->pmdown_time = 0;
587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
589 ARRAY_SIZE(tabla_msm8960_controls));
590 if (err < 0)
591 return err;
592
593 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
594 ARRAY_SIZE(msm8960_dapm_widgets));
595
Bradley Rubin229c6a52011-07-12 16:18:48 -0700596 snd_soc_dapm_add_routes(dapm, common_audio_map,
597 ARRAY_SIZE(common_audio_map));
598
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700599 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
600 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
601 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
602 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603
604 snd_soc_dapm_sync(dapm);
605
606 err = snd_soc_jack_new(codec, "Headset Jack",
Patrick Lai456c4ea2011-11-03 16:16:10 -0700607 (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
608 &hs_jack);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 if (err) {
610 pr_err("failed to create new jack\n");
611 return err;
612 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700613
614 err = snd_soc_jack_new(codec, "Button Jack",
615 SND_JACK_BTN_0, &button_jack);
616 if (err) {
617 pr_err("failed to create new jack\n");
618 return err;
619 }
620
621 tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622
623 return 0;
624}
625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700627 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 .trigger = {
629 SND_SOC_DSP_TRIGGER_POST,
630 SND_SOC_DSP_TRIGGER_POST
631 },
632};
633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700635 .playback = true,
636 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 .trigger = {
638 SND_SOC_DSP_TRIGGER_POST,
639 SND_SOC_DSP_TRIGGER_POST
640 },
641};
642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643static struct snd_soc_dsp_link slimbus0_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700644 .playback = true,
645 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 .trigger = {
647 SND_SOC_DSP_TRIGGER_POST,
648 SND_SOC_DSP_TRIGGER_POST
649 },
650};
651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652static struct snd_soc_dsp_link int_fm_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700653 .playback = true,
654 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 .trigger = {
656 SND_SOC_DSP_TRIGGER_POST,
657 SND_SOC_DSP_TRIGGER_POST
658 },
659};
660
661static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
662 struct snd_pcm_hw_params *params)
663{
664 struct snd_interval *rate = hw_param_interval(params,
665 SNDRV_PCM_HW_PARAM_RATE);
666
667 struct snd_interval *channels = hw_param_interval(params,
668 SNDRV_PCM_HW_PARAM_CHANNELS);
669
670 pr_debug("%s()\n", __func__);
671 rate->min = rate->max = 48000;
672 channels->min = channels->max = msm8960_slim_0_rx_ch;
673
674 return 0;
675}
676
677static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
678 struct snd_pcm_hw_params *params)
679{
680 struct snd_interval *rate = hw_param_interval(params,
681 SNDRV_PCM_HW_PARAM_RATE);
682
683 struct snd_interval *channels = hw_param_interval(params,
684 SNDRV_PCM_HW_PARAM_CHANNELS);
685
686 pr_debug("%s()\n", __func__);
687 rate->min = rate->max = 48000;
688 channels->min = channels->max = msm8960_slim_0_tx_ch;
689
690 return 0;
691}
692
693static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
694 struct snd_pcm_hw_params *params)
695{
696 struct snd_interval *rate = hw_param_interval(params,
697 SNDRV_PCM_HW_PARAM_RATE);
698
699 pr_debug("%s()\n", __func__);
700 rate->min = rate->max = 48000;
701
702 return 0;
703}
704
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700705static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
706 struct snd_pcm_hw_params *params)
707{
708 struct snd_interval *rate = hw_param_interval(params,
709 SNDRV_PCM_HW_PARAM_RATE);
710
711 struct snd_interval *channels = hw_param_interval(params,
712 SNDRV_PCM_HW_PARAM_CHANNELS);
713
714 rate->min = rate->max = msm8960_btsco_rate;
715 channels->min = channels->max = msm8960_btsco_ch;
716
717 return 0;
718}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700719static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
720 struct snd_pcm_hw_params *params)
721{
722 struct snd_interval *rate = hw_param_interval(params,
723 SNDRV_PCM_HW_PARAM_RATE);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700724
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700725 struct snd_interval *channels = hw_param_interval(params,
726 SNDRV_PCM_HW_PARAM_CHANNELS);
727
728 /* PCM only supports mono output with 8khz sample rate */
729 rate->min = rate->max = 8000;
730 channels->min = channels->max = 1;
731
732 return 0;
733}
734static int msm8960_aux_pcm_get_gpios(void)
735{
736 int ret = 0;
737
738 pr_debug("%s\n", __func__);
739
740 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
741 if (ret < 0) {
742 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
743 __func__, GPIO_AUX_PCM_DOUT);
744 goto fail_dout;
745 }
746
747 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
748 if (ret < 0) {
749 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
750 __func__, GPIO_AUX_PCM_DIN);
751 goto fail_din;
752 }
753
754 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
755 if (ret < 0) {
756 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
757 __func__, GPIO_AUX_PCM_SYNC);
758 goto fail_sync;
759 }
760 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
761 if (ret < 0) {
762 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
763 __func__, GPIO_AUX_PCM_CLK);
764 goto fail_clk;
765 }
766
767 return 0;
768
769fail_clk:
770 gpio_free(GPIO_AUX_PCM_SYNC);
771fail_sync:
772 gpio_free(GPIO_AUX_PCM_DIN);
773fail_din:
774 gpio_free(GPIO_AUX_PCM_DOUT);
775fail_dout:
776
777 return ret;
778}
779
780static int msm8960_aux_pcm_free_gpios(void)
781{
782 gpio_free(GPIO_AUX_PCM_DIN);
783 gpio_free(GPIO_AUX_PCM_DOUT);
784 gpio_free(GPIO_AUX_PCM_SYNC);
785 gpio_free(GPIO_AUX_PCM_CLK);
786
787 return 0;
788}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789static int msm8960_startup(struct snd_pcm_substream *substream)
790{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700791 pr_debug("%s(): substream = %s stream = %d\n", __func__,
792 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 return 0;
794}
795
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700796static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
797{
798 int ret = 0;
799
800 pr_debug("%s(): substream = %s\n", __func__, substream->name);
801 ret = msm8960_aux_pcm_get_gpios();
802 if (ret < 0) {
803 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
804 return -EINVAL;
805 }
806 return 0;
807}
808
809static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
810{
811
812 pr_debug("%s(): substream = %s\n", __func__, substream->name);
813 msm8960_aux_pcm_free_gpios();
814}
815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816static void msm8960_shutdown(struct snd_pcm_substream *substream)
817{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700818 pr_debug("%s(): substream = %s stream = %d\n", __func__,
819 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820}
821
822static struct snd_soc_ops msm8960_be_ops = {
823 .startup = msm8960_startup,
824 .shutdown = msm8960_shutdown,
825};
826
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700827static struct snd_soc_ops msm8960_auxpcm_be_ops = {
828 .startup = msm8960_auxpcm_startup,
829 .shutdown = msm8960_auxpcm_shutdown,
830};
831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832/* Digital audio interface glue - connects codec <---> CPU */
833static struct snd_soc_dai_link msm8960_dai[] = {
834 /* FrontEnd DAI Links */
835 {
836 .name = "MSM8960 Media1",
837 .stream_name = "MultiMedia1",
838 .cpu_dai_name = "MultiMedia1",
839 .platform_name = "msm-pcm-dsp",
840 .dynamic = 1,
841 .dsp_link = &fe_media,
842 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
843 },
844 {
845 .name = "MSM8960 Media2",
846 .stream_name = "MultiMedia2",
847 .cpu_dai_name = "MultiMedia2",
848 .platform_name = "msm-pcm-dsp",
849 .dynamic = 1,
850 .dsp_link = &fe_media,
851 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
852 },
853 {
854 .name = "Circuit-Switch Voice",
855 .stream_name = "CS-Voice",
856 .cpu_dai_name = "CS-VOICE",
857 .platform_name = "msm-pcm-voice",
858 .dynamic = 1,
859 .dsp_link = &fe_media,
860 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
861 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700862 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863 },
864 {
865 .name = "MSM VoIP",
866 .stream_name = "VoIP",
867 .cpu_dai_name = "VoIP",
868 .platform_name = "msm-voip-dsp",
869 .dynamic = 1,
870 .dsp_link = &fe_media,
871 .be_id = MSM_FRONTEND_DAI_VOIP,
872 },
873 {
874 .name = "MSM8960 LPA",
875 .stream_name = "LPA",
876 .cpu_dai_name = "MultiMedia3",
877 .platform_name = "msm-pcm-lpa",
878 .dynamic = 1,
879 .dsp_link = &lpa_fe_media,
880 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
881 },
882 /* Hostless PMC purpose */
883 {
884 .name = "SLIMBUS_0 Hostless",
885 .stream_name = "SLIMBUS_0 Hostless",
886 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
887 .platform_name = "msm-pcm-hostless",
888 .dynamic = 1,
889 .dsp_link = &slimbus0_hl_media,
890 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700891 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 /* .be_id = do not care */
893 },
894 {
895 .name = "INT_FM Hostless",
896 .stream_name = "INT_FM Hostless",
897 .cpu_dai_name = "INT_FM_HOSTLESS",
898 .platform_name = "msm-pcm-hostless",
899 .dynamic = 1,
900 .dsp_link = &int_fm_hl_media,
901 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -0700902 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 /* .be_id = do not care */
904 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530905 {
906 .name = "MSM AFE-PCM RX",
907 .stream_name = "AFE-PROXY RX",
908 .cpu_dai_name = "msm-dai-q6.241",
909 .codec_name = "msm-stub-codec.1",
910 .codec_dai_name = "msm-stub-rx",
911 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -0700912 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530913 },
914 {
915 .name = "MSM AFE-PCM TX",
916 .stream_name = "AFE-PROXY TX",
917 .cpu_dai_name = "msm-dai-q6.240",
918 .codec_name = "msm-stub-codec.1",
919 .codec_dai_name = "msm-stub-tx",
920 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -0700921 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530922 },
Asish Bhattacharya09f9e0a2011-11-11 13:22:47 +0530923 {
924 .name = "MSM8960 Compr",
925 .stream_name = "COMPR",
926 .cpu_dai_name = "MultiMedia4",
927 .platform_name = "msm-compr-dsp",
928 .dynamic = 1,
929 .dsp_link = &lpa_fe_media,
930 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
931 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 /* Backend DAI Links */
933 {
934 .name = LPASS_BE_SLIMBUS_0_RX,
935 .stream_name = "Slimbus Playback",
936 .cpu_dai_name = "msm-dai-q6.16384",
937 .platform_name = "msm-pcm-routing",
938 .codec_name = "tabla_codec",
939 .codec_dai_name = "tabla_rx1",
940 .no_pcm = 1,
941 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
942 .init = &msm8960_audrx_init,
943 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
944 .ops = &msm8960_be_ops,
945 },
946 {
947 .name = LPASS_BE_SLIMBUS_0_TX,
948 .stream_name = "Slimbus Capture",
949 .cpu_dai_name = "msm-dai-q6.16385",
950 .platform_name = "msm-pcm-routing",
951 .codec_name = "tabla_codec",
952 .codec_dai_name = "tabla_tx1",
953 .no_pcm = 1,
954 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
955 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
956 .ops = &msm8960_be_ops,
957 },
958 /* Backend BT/FM DAI Links */
959 {
960 .name = LPASS_BE_INT_BT_SCO_RX,
961 .stream_name = "Internal BT-SCO Playback",
962 .cpu_dai_name = "msm-dai-q6.12288",
963 .platform_name = "msm-pcm-routing",
964 .codec_name = "msm-stub-codec.1",
965 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700966 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 .no_pcm = 1,
968 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700969 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 },
971 {
972 .name = LPASS_BE_INT_BT_SCO_TX,
973 .stream_name = "Internal BT-SCO Capture",
974 .cpu_dai_name = "msm-dai-q6.12289",
975 .platform_name = "msm-pcm-routing",
976 .codec_name = "msm-stub-codec.1",
977 .codec_dai_name = "msm-stub-tx",
978 .no_pcm = 1,
979 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700980 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700981 },
982 {
983 .name = LPASS_BE_INT_FM_RX,
984 .stream_name = "Internal FM Playback",
985 .cpu_dai_name = "msm-dai-q6.12292",
986 .platform_name = "msm-pcm-routing",
987 .codec_name = "msm-stub-codec.1",
988 .codec_dai_name = "msm-stub-rx",
989 .no_pcm = 1,
990 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
991 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
992 },
993 {
994 .name = LPASS_BE_INT_FM_TX,
995 .stream_name = "Internal FM Capture",
996 .cpu_dai_name = "msm-dai-q6.12293",
997 .platform_name = "msm-pcm-routing",
998 .codec_name = "msm-stub-codec.1",
999 .codec_dai_name = "msm-stub-tx",
1000 .no_pcm = 1,
1001 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
1002 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1003 },
1004 /* HDMI BACK END DAI Link */
1005 {
1006 .name = LPASS_BE_HDMI,
1007 .stream_name = "HDMI Playback",
1008 .cpu_dai_name = "msm-dai-q6.8",
1009 .platform_name = "msm-pcm-routing",
1010 .codec_name = "msm-stub-codec.1",
1011 .codec_dai_name = "msm-stub-rx",
1012 .no_pcm = 1,
1013 .no_codec = 1,
1014 .be_id = MSM_BACKEND_DAI_HDMI_RX,
1015 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1016 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301017 /* Backend AFE DAI Links */
1018 {
1019 .name = LPASS_BE_AFE_PCM_RX,
1020 .stream_name = "AFE Playback",
1021 .cpu_dai_name = "msm-dai-q6.224",
1022 .platform_name = "msm-pcm-routing",
1023 .codec_name = "msm-stub-codec.1",
1024 .codec_dai_name = "msm-stub-rx",
1025 .no_codec = 1,
1026 .no_pcm = 1,
1027 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1028 },
1029 {
1030 .name = LPASS_BE_AFE_PCM_TX,
1031 .stream_name = "AFE Capture",
1032 .cpu_dai_name = "msm-dai-q6.225",
1033 .platform_name = "msm-pcm-routing",
1034 .codec_name = "msm-stub-codec.1",
1035 .codec_dai_name = "msm-stub-tx",
1036 .no_codec = 1,
1037 .no_pcm = 1,
1038 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1039 },
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001040 /* AUX PCM Backend DAI Links */
1041 {
1042 .name = LPASS_BE_AUXPCM_RX,
1043 .stream_name = "AUX PCM Playback",
1044 .cpu_dai_name = "msm-dai-q6.2",
1045 .platform_name = "msm-pcm-routing",
1046 .codec_name = "msm-stub-codec.1",
1047 .codec_dai_name = "msm-stub-rx",
1048 .no_pcm = 1,
1049 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1050 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1051 .ops = &msm8960_auxpcm_be_ops,
1052 },
1053 {
1054 .name = LPASS_BE_AUXPCM_TX,
1055 .stream_name = "AUX PCM Capture",
1056 .cpu_dai_name = "msm-dai-q6.3",
1057 .platform_name = "msm-pcm-routing",
1058 .codec_name = "msm-stub-codec.1",
1059 .codec_dai_name = "msm-stub-tx",
1060 .no_pcm = 1,
1061 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1062 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1063 },
Helen Zeng0705a5f2011-10-14 15:29:52 -07001064 /* Incall Music BACK END DAI Link */
1065 {
1066 .name = LPASS_BE_VOICE_PLAYBACK_TX,
1067 .stream_name = "Voice Farend Playback",
1068 .cpu_dai_name = "msm-dai-q6.32773",
1069 .platform_name = "msm-pcm-routing",
1070 .codec_name = "msm-stub-codec.1",
1071 .codec_dai_name = "msm-stub-rx",
1072 .no_pcm = 1,
1073 .no_codec = 1,
1074 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
1075 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1076 },
Helen Zenge3d716a2011-10-14 16:32:16 -07001077 /* Incall Record Uplink BACK END DAI Link */
1078 {
1079 .name = LPASS_BE_INCALL_RECORD_TX,
1080 .stream_name = "Voice Uplink Capture",
1081 .cpu_dai_name = "msm-dai-q6.32772",
1082 .platform_name = "msm-pcm-routing",
1083 .codec_name = "msm-stub-codec.1",
1084 .codec_dai_name = "msm-stub-tx",
1085 .no_pcm = 1,
1086 .no_codec = 1,
1087 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
1088 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1089 },
1090 /* Incall Record Downlink BACK END DAI Link */
1091 {
1092 .name = LPASS_BE_INCALL_RECORD_RX,
1093 .stream_name = "Voice Downlink Capture",
1094 .cpu_dai_name = "msm-dai-q6.32771",
1095 .platform_name = "msm-pcm-routing",
1096 .codec_name = "msm-stub-codec.1",
1097 .codec_dai_name = "msm-stub-tx",
1098 .no_pcm = 1,
1099 .no_codec = 1,
1100 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
1101 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1102 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103};
1104
1105struct snd_soc_card snd_soc_card_msm8960 = {
1106 .name = "msm8960-snd-card",
1107 .dai_link = msm8960_dai,
1108 .num_links = ARRAY_SIZE(msm8960_dai),
1109};
1110
1111static struct platform_device *msm8960_snd_device;
1112
1113static int msm8960_configure_headset_mic_gpios(void)
1114{
1115 int ret;
1116 struct pm_gpio param = {
1117 .direction = PM_GPIO_DIR_OUT,
1118 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1119 .output_value = 1,
1120 .pull = PM_GPIO_PULL_NO,
1121 .vin_sel = PM_GPIO_VIN_S4,
1122 .out_strength = PM_GPIO_STRENGTH_MED,
1123 .function = PM_GPIO_FUNC_NORMAL,
1124 };
1125
1126 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1127 if (ret) {
1128 pr_err("%s: Failed to request gpio %d\n", __func__,
1129 PM8921_GPIO_PM_TO_SYS(23));
1130 return ret;
1131 }
1132
1133 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
1134 if (ret)
1135 pr_err("%s: Failed to configure gpio %d\n", __func__,
1136 PM8921_GPIO_PM_TO_SYS(23));
1137 else
1138 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
1139
1140 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1141 if (ret) {
1142 pr_err("%s: Failed to request gpio %d\n", __func__,
1143 PM8921_GPIO_PM_TO_SYS(35));
1144 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1145 return ret;
1146 }
1147 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
1148 if (ret)
1149 pr_err("%s: Failed to configure gpio %d\n", __func__,
1150 PM8921_GPIO_PM_TO_SYS(35));
1151 else
Patrick Lai2ae0a002011-09-26 14:51:09 -07001152 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153
1154 return 0;
1155}
1156static void msm8960_free_headset_mic_gpios(void)
1157{
1158 if (msm8960_headset_gpios_configured) {
1159 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1160 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
1161 }
1162}
1163
1164static int __init msm8960_audio_init(void)
1165{
1166 int ret;
1167
Ajay Dudani79e268c2011-12-28 13:14:44 -08001168 if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001169 pr_err("%s: Not the right machine type\n", __func__);
1170 return -ENODEV ;
1171 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
1173 if (!msm8960_snd_device) {
1174 pr_err("Platform device allocation failed\n");
1175 return -ENOMEM;
1176 }
1177
1178 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
1179 ret = platform_device_add(msm8960_snd_device);
1180 if (ret) {
1181 platform_device_put(msm8960_snd_device);
1182 return ret;
1183 }
1184
1185 if (msm8960_configure_headset_mic_gpios()) {
1186 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1187 msm8960_headset_gpios_configured = 0;
1188 } else
1189 msm8960_headset_gpios_configured = 1;
1190
1191 return ret;
1192
1193}
1194module_init(msm8960_audio_init);
1195
1196static void __exit msm8960_audio_exit(void)
1197{
Ajay Dudani79e268c2011-12-28 13:14:44 -08001198 if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001199 pr_err("%s: Not the right machine type\n", __func__);
1200 return ;
1201 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 msm8960_free_headset_mic_gpios();
1203 platform_device_unregister(msm8960_snd_device);
1204}
1205module_exit(msm8960_audio_exit);
1206
1207MODULE_DESCRIPTION("ALSA SoC MSM8960");
1208MODULE_LICENSE("GPL v2");