blob: 9bf3f694bc8476e3ec43d0c839cfde703c421748 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051static int msm8960_spk_control;
Kiran Kandi462acea2011-08-31 23:53:14 -070052static int msm8960_ext_bottom_spk_pamp;
53static int msm8960_ext_top_spk_pamp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054static int msm8960_slim_0_rx_ch = 1;
55static int msm8960_slim_0_tx_ch = 1;
56
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070057static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
58static int msm8960_btsco_ch = 1;
59
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060struct tabla_mbhc_calibration tabla_cal = {
61 .bias = TABLA_MICBIAS2,
62 .tldoh = 100,
63 .bg_fast_settle = 100,
64 .mic_current = TABLA_PID_MIC_5_UA,
65 .mic_pid = 100,
66 .hph_current = TABLA_PID_MIC_5_UA,
67 .setup_plug_removal_delay = 1000000,
68 .shutdown_plug_removal = 100000,
69};
70
71static struct clk *codec_clk;
72static int clk_users;
73
74static int msm8960_headset_gpios_configured;
75
76static struct snd_soc_jack hs_jack;
Bradley Rubincb1e2732011-06-23 16:49:20 -070077static struct snd_soc_jack button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078
Kiran Kandi462acea2011-08-31 23:53:14 -070079static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070080{
81 int ret = 0;
82
83 struct pm_gpio param = {
84 .direction = PM_GPIO_DIR_OUT,
85 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
86 .output_value = 1,
87 .pull = PM_GPIO_PULL_NO,
88 .vin_sel = PM_GPIO_VIN_S4,
89 .out_strength = PM_GPIO_STRENGTH_MED,
Kiran Kandi462acea2011-08-31 23:53:14 -070090 .
91 function = PM_GPIO_FUNC_NORMAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092 };
93
Kiran Kandi462acea2011-08-31 23:53:14 -070094 if (spk_amp_gpio == BOTTOM_SPK_PAMP_GPIO) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070095
Kiran Kandi462acea2011-08-31 23:53:14 -070096 ret = gpio_request(BOTTOM_SPK_PAMP_GPIO, "BOTTOM_SPK_AMP");
97 if (ret) {
98 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
99 __func__, BOTTOM_SPK_PAMP_GPIO);
100 return;
101 }
102 ret = pm8xxx_gpio_config(BOTTOM_SPK_PAMP_GPIO, &param);
103 if (ret)
104 pr_err("%s: Failed to configure Bottom Spk Ampl"
105 " gpio %u\n", __func__, BOTTOM_SPK_PAMP_GPIO);
106 else {
107 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
108 gpio_direction_output(BOTTOM_SPK_PAMP_GPIO, 1);
109 }
110
111 } else if (spk_amp_gpio == TOP_SPK_PAMP_GPIO) {
112
113 ret = gpio_request(TOP_SPK_PAMP_GPIO, "TOP_SPK_AMP");
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700114 if (ret) {
115 pr_err("%s: Error requesting GPIO %d\n", __func__,
Kiran Kandi462acea2011-08-31 23:53:14 -0700116 TOP_SPK_PAMP_GPIO);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700117 return;
118 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700119 ret = pm8xxx_gpio_config(TOP_SPK_PAMP_GPIO, &param);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700120 if (ret)
Kiran Kandi462acea2011-08-31 23:53:14 -0700121 pr_err("%s: Failed to configure Top Spk Ampl"
122 " gpio %u\n", __func__, TOP_SPK_PAMP_GPIO);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700123 else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700124 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
125 gpio_direction_output(TOP_SPK_PAMP_GPIO, 1);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700126 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700127 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700128 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
129 " gpio = %u\n", __func__, spk_amp_gpio);
130 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700133
Kiran Kandi462acea2011-08-31 23:53:14 -0700134static void msm8960_ext_spk_power_amp_on(u32 spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135{
Kiran Kandi462acea2011-08-31 23:53:14 -0700136 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
137
138 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
139 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
140
141 pr_debug("%s() External Bottom Speaker Ampl already "
142 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700143 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700144 }
145
146 msm8960_ext_bottom_spk_pamp |= spk;
147
148 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
149 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
150
151 msm8960_enable_ext_spk_amp_gpio(BOTTOM_SPK_PAMP_GPIO);
152 pr_debug("%s: slepping 4 ms after turning on external "
153 " Bottom Speaker Ampl\n", __func__);
154 usleep_range(4000, 4000);
155 }
156
157 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
158
159 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
160 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
161
162 pr_debug("%s() External Top Speaker Ampl already"
163 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700164 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700165 }
166
167 msm8960_ext_top_spk_pamp |= spk;
168
169 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
170 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
171
172 msm8960_enable_ext_spk_amp_gpio(TOP_SPK_PAMP_GPIO);
173 pr_debug("%s: sleeping 4 ms after turning on "
174 " external Top Speaker Ampl\n", __func__);
175 usleep_range(4000, 4000);
176 }
177 } else {
178
179 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
180 __func__, spk);
181 return;
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700182 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700183}
184
185static void msm8960_ext_spk_power_amp_off(u32 spk)
186{
187 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
188
189 if (!msm8960_ext_bottom_spk_pamp)
190 return;
191
192 gpio_direction_output(BOTTOM_SPK_PAMP_GPIO, 0);
193 gpio_free(BOTTOM_SPK_PAMP_GPIO);
194 msm8960_ext_bottom_spk_pamp = 0;
195
196 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
197 " Speaker Ampl\n", __func__);
198
199 usleep_range(4000, 4000);
200
201 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
202
203 if (!msm8960_ext_top_spk_pamp)
204 return;
205
206 gpio_direction_output(TOP_SPK_PAMP_GPIO, 0);
207 gpio_free(TOP_SPK_PAMP_GPIO);
208 msm8960_ext_top_spk_pamp = 0;
209
210 pr_debug("%s: sleeping 4 ms after turning off external Top"
211 " Spkaker Ampl\n", __func__);
212
213 usleep_range(4000, 4000);
214 } else {
215
216 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
217 __func__, spk);
218 return;
219 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222static void msm8960_ext_control(struct snd_soc_codec *codec)
223{
224 struct snd_soc_dapm_context *dapm = &codec->dapm;
225
226 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
227 if (msm8960_spk_control == MSM8960_SPK_ON)
228 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
229 else
230 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
231
232 snd_soc_dapm_sync(dapm);
233}
234
235static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
236 struct snd_ctl_elem_value *ucontrol)
237{
238 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
239 ucontrol->value.integer.value[0] = msm8960_spk_control;
240 return 0;
241}
242static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
243 struct snd_ctl_elem_value *ucontrol)
244{
245 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
246
247 pr_debug("%s()\n", __func__);
248 if (msm8960_spk_control == ucontrol->value.integer.value[0])
249 return 0;
250
251 msm8960_spk_control = ucontrol->value.integer.value[0];
252 msm8960_ext_control(codec);
253 return 1;
254}
255static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
256 struct snd_kcontrol *k, int event)
257{
258 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700259
260 if (SND_SOC_DAPM_EVENT_ON(event)) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700261 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
262 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
263 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
264 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
265 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
266 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
267 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
268 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
269 else {
270 pr_err("%s() Invalid Speaker Widget = %s\n",
271 __func__, w->name);
272 return -EINVAL;
273 }
274
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700275 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700276 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
277 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
278 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
279 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
280 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
281 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
282 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
283 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
284 else {
285 pr_err("%s() Invalid Speaker Widget = %s\n",
286 __func__, w->name);
287 return -EINVAL;
288 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700289 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 return 0;
291}
292
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700293static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
294 struct snd_kcontrol *kcontrol, int event)
295{
296 pr_debug("%s: event = %d\n", __func__, event);
297
298 switch (event) {
299 case SND_SOC_DAPM_PRE_PMU:
300
301 clk_users++;
302 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
303
304 if (clk_users != 1)
305 return 0;
306
307 codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
308 if (codec_clk) {
309 clk_set_rate(codec_clk, 12288000);
310 clk_enable(codec_clk);
311 tabla_mclk_enable(w->codec, 1);
312
313 } else {
314 pr_err("%s: Error setting Tabla MCLK\n", __func__);
315 clk_users--;
316 return -EINVAL;
317 }
318 break;
319 case SND_SOC_DAPM_POST_PMD:
320
321 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
322
323 if (clk_users == 0)
324 return 0;
325
326 clk_users--;
327
328 if (!clk_users) {
329 pr_debug("%s: disabling MCLK. clk_users = %d\n",
330 __func__, clk_users);
331
332 clk_disable(codec_clk);
333 clk_put(codec_clk);
334 tabla_mclk_enable(w->codec, 0);
335 }
336 break;
337 }
338 return 0;
339}
340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700342
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700343 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
344 msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
345
Kiran Kandi462acea2011-08-31 23:53:14 -0700346 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
347 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
348
349 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
350 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352 SND_SOC_DAPM_MIC("Handset Mic", NULL),
353 SND_SOC_DAPM_MIC("Headset Mic", NULL),
354 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700355 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
356 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700357
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700358 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700359 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700360 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700361 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700362 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
363 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365};
366
Bradley Rubin229c6a52011-07-12 16:18:48 -0700367static const struct snd_soc_dapm_route common_audio_map[] = {
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700368
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700369 {"RX_BIAS", NULL, "MCLK"},
370 {"LDO_H", NULL, "MCLK"},
371
372 /* Speaker path */
Kiran Kandi462acea2011-08-31 23:53:14 -0700373 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
374 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700375
Kiran Kandi462acea2011-08-31 23:53:14 -0700376 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
377 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378
379 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700380 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
381 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700382
383 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700385
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700386 {"HEADPHONE", NULL, "LDO_H"},
387
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700388 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700389 * The digital Mic routes are setup considering
390 * fluid as default device.
391 */
392
393 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700394 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700395 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700396 * Conncted to DMIC2 Input on Tabla codec.
397 */
398 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700399 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700400
401 /**
402 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700403 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700404 * Conncted to DMIC1 Input on Tabla codec.
405 */
406 {"DMIC1", NULL, "MIC BIAS1 External"},
407 {"MIC BIAS1 External", NULL, "Digital Mic2"},
408
409 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700410 * Digital Mic3. Back Bottom Digital Mic on Fluid.
411 * Digital Mic GM1 on CDP mainboard.
412 * Conncted to DMIC4 Input on Tabla codec.
413 */
414 {"DMIC4", NULL, "MIC BIAS3 External"},
415 {"MIC BIAS3 External", NULL, "Digital Mic3"},
416
417 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700418 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700419 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700420 * Conncted to DMIC3 Input on Tabla codec.
421 */
422 {"DMIC3", NULL, "MIC BIAS3 External"},
423 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700424
425 /**
426 * Digital Mic5. Front top Digital Mic on Fluid.
427 * Digital Mic GM3 on CDP mainboard.
428 * Conncted to DMIC5 Input on Tabla codec.
429 */
430 {"DMIC5", NULL, "MIC BIAS4 External"},
431 {"MIC BIAS4 External", NULL, "Digital Mic5"},
432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433};
434
Bradley Rubin229c6a52011-07-12 16:18:48 -0700435static const struct snd_soc_dapm_route cdp_audio_map[] = {
436 {"AMIC3", NULL, "MIC BIAS3 External"},
437 {"MIC BIAS3 External", NULL, "ANCRight Headset Mic"},
438
439 {"AMIC4", NULL, "MIC BIAS4 External"},
440 {"MIC BIAS4 External", NULL, "ANCLeft Headset Mic"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700441
442 /** Digital Mic GM4 on CDP mainboard.
443 * Connected to DMIC6 input on Tabla codec.
444 */
445 {"DMIC6", NULL, "MIC BIAS4 External"},
446 {"MIC BIAS4 External", NULL, "Digital Mic6"},
447
Bradley Rubin229c6a52011-07-12 16:18:48 -0700448};
449
450static const struct snd_soc_dapm_route fluid_audio_map[] = {
451 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
452 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
453
454 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
455 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
456};
457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700459static const char *slim0_rx_ch_text[] = {"One", "Two"};
460static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462static const struct soc_enum msm8960_enum[] = {
463 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700464 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
465 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466};
467
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700468static const char *btsco_rate_text[] = {"8000", "16000"};
469static const struct soc_enum msm8960_btsco_enum[] = {
470 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
471};
472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
474 struct snd_ctl_elem_value *ucontrol)
475{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700476 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700478 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479 return 0;
480}
481
482static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
483 struct snd_ctl_elem_value *ucontrol)
484{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700485 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486
Patrick Lai9f4b4292011-07-16 22:11:09 -0700487 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 msm8960_slim_0_rx_ch);
489 return 1;
490}
491
492static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
494{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700495 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700497 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498 return 0;
499}
500
501static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
502 struct snd_ctl_elem_value *ucontrol)
503{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700504 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505
506 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
507 msm8960_slim_0_tx_ch);
508 return 1;
509}
510
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700511static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
512 struct snd_ctl_elem_value *ucontrol)
513{
514 pr_debug("%s: msm8960_btsco_rate = %d", __func__,
515 msm8960_btsco_rate);
516 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
517 return 0;
518}
519
520static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
521 struct snd_ctl_elem_value *ucontrol)
522{
523 switch (ucontrol->value.integer.value[0]) {
524 case 0:
525 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
526 break;
527 case 1:
528 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
529 break;
530 default:
531 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
532 break;
533 }
534 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
535 msm8960_btsco_rate);
536 return 0;
537}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538
539static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
540 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
541 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700542 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
543 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
544 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
545 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546};
547
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700548static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
549 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
550 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
551};
552
553static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
554{
555 int err = 0;
556 struct snd_soc_platform *platform = rtd->platform;
557
558 err = snd_soc_add_platform_controls(platform,
559 int_btsco_rate_mixer_controls,
560 ARRAY_SIZE(int_btsco_rate_mixer_controls));
561 if (err < 0)
562 return err;
563 return 0;
564}
565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
567{
568 int err;
569 struct snd_soc_codec *codec = rtd->codec;
570 struct snd_soc_dapm_context *dapm = &codec->dapm;
571
572 pr_debug("%s()\n", __func__);
573
574 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
575 ARRAY_SIZE(tabla_msm8960_controls));
576 if (err < 0)
577 return err;
578
579 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
580 ARRAY_SIZE(msm8960_dapm_widgets));
581
Bradley Rubin229c6a52011-07-12 16:18:48 -0700582 snd_soc_dapm_add_routes(dapm, common_audio_map,
583 ARRAY_SIZE(common_audio_map));
584
585 if (machine_is_msm8960_cdp())
586 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
587 ARRAY_SIZE(cdp_audio_map));
588 else if (machine_is_msm8960_mtp())
589 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
590 ARRAY_SIZE(cdp_audio_map));
591 else if (machine_is_msm8960_fluid())
592 snd_soc_dapm_add_routes(dapm, fluid_audio_map,
593 ARRAY_SIZE(fluid_audio_map));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594
595 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
596
597 snd_soc_dapm_sync(dapm);
598
599 err = snd_soc_jack_new(codec, "Headset Jack",
600 SND_JACK_HEADSET, &hs_jack);
601 if (err) {
602 pr_err("failed to create new jack\n");
603 return err;
604 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700605
606 err = snd_soc_jack_new(codec, "Button Jack",
607 SND_JACK_BTN_0, &button_jack);
608 if (err) {
609 pr_err("failed to create new jack\n");
610 return err;
611 }
612
613 tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614
615 return 0;
616}
617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700619 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 .trigger = {
621 SND_SOC_DSP_TRIGGER_POST,
622 SND_SOC_DSP_TRIGGER_POST
623 },
624};
625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700627 .playback = true,
628 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629 .trigger = {
630 SND_SOC_DSP_TRIGGER_POST,
631 SND_SOC_DSP_TRIGGER_POST
632 },
633};
634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635static struct snd_soc_dsp_link slimbus0_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700636 .playback = true,
637 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 .trigger = {
639 SND_SOC_DSP_TRIGGER_POST,
640 SND_SOC_DSP_TRIGGER_POST
641 },
642};
643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644static struct snd_soc_dsp_link int_fm_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700645 .playback = true,
646 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 .trigger = {
648 SND_SOC_DSP_TRIGGER_POST,
649 SND_SOC_DSP_TRIGGER_POST
650 },
651};
652
653static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
654 struct snd_pcm_hw_params *params)
655{
656 struct snd_interval *rate = hw_param_interval(params,
657 SNDRV_PCM_HW_PARAM_RATE);
658
659 struct snd_interval *channels = hw_param_interval(params,
660 SNDRV_PCM_HW_PARAM_CHANNELS);
661
662 pr_debug("%s()\n", __func__);
663 rate->min = rate->max = 48000;
664 channels->min = channels->max = msm8960_slim_0_rx_ch;
665
666 return 0;
667}
668
669static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
670 struct snd_pcm_hw_params *params)
671{
672 struct snd_interval *rate = hw_param_interval(params,
673 SNDRV_PCM_HW_PARAM_RATE);
674
675 struct snd_interval *channels = hw_param_interval(params,
676 SNDRV_PCM_HW_PARAM_CHANNELS);
677
678 pr_debug("%s()\n", __func__);
679 rate->min = rate->max = 48000;
680 channels->min = channels->max = msm8960_slim_0_tx_ch;
681
682 return 0;
683}
684
685static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
686 struct snd_pcm_hw_params *params)
687{
688 struct snd_interval *rate = hw_param_interval(params,
689 SNDRV_PCM_HW_PARAM_RATE);
690
691 pr_debug("%s()\n", __func__);
692 rate->min = rate->max = 48000;
693
694 return 0;
695}
696
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700697static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
698 struct snd_pcm_hw_params *params)
699{
700 struct snd_interval *rate = hw_param_interval(params,
701 SNDRV_PCM_HW_PARAM_RATE);
702
703 struct snd_interval *channels = hw_param_interval(params,
704 SNDRV_PCM_HW_PARAM_CHANNELS);
705
706 rate->min = rate->max = msm8960_btsco_rate;
707 channels->min = channels->max = msm8960_btsco_ch;
708
709 return 0;
710}
711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712static int msm8960_startup(struct snd_pcm_substream *substream)
713{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700714 pr_debug("%s(): substream = %s stream = %d\n", __func__,
715 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716 return 0;
717}
718
719static void msm8960_shutdown(struct snd_pcm_substream *substream)
720{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700721 pr_debug("%s(): substream = %s stream = %d\n", __func__,
722 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723}
724
725static struct snd_soc_ops msm8960_be_ops = {
726 .startup = msm8960_startup,
727 .shutdown = msm8960_shutdown,
728};
729
730/* Digital audio interface glue - connects codec <---> CPU */
731static struct snd_soc_dai_link msm8960_dai[] = {
732 /* FrontEnd DAI Links */
733 {
734 .name = "MSM8960 Media1",
735 .stream_name = "MultiMedia1",
736 .cpu_dai_name = "MultiMedia1",
737 .platform_name = "msm-pcm-dsp",
738 .dynamic = 1,
739 .dsp_link = &fe_media,
740 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
741 },
742 {
743 .name = "MSM8960 Media2",
744 .stream_name = "MultiMedia2",
745 .cpu_dai_name = "MultiMedia2",
746 .platform_name = "msm-pcm-dsp",
747 .dynamic = 1,
748 .dsp_link = &fe_media,
749 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
750 },
751 {
752 .name = "Circuit-Switch Voice",
753 .stream_name = "CS-Voice",
754 .cpu_dai_name = "CS-VOICE",
755 .platform_name = "msm-pcm-voice",
756 .dynamic = 1,
757 .dsp_link = &fe_media,
758 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
759 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
760 },
761 {
762 .name = "MSM VoIP",
763 .stream_name = "VoIP",
764 .cpu_dai_name = "VoIP",
765 .platform_name = "msm-voip-dsp",
766 .dynamic = 1,
767 .dsp_link = &fe_media,
768 .be_id = MSM_FRONTEND_DAI_VOIP,
769 },
770 {
771 .name = "MSM8960 LPA",
772 .stream_name = "LPA",
773 .cpu_dai_name = "MultiMedia3",
774 .platform_name = "msm-pcm-lpa",
775 .dynamic = 1,
776 .dsp_link = &lpa_fe_media,
777 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
778 },
779 /* Hostless PMC purpose */
780 {
781 .name = "SLIMBUS_0 Hostless",
782 .stream_name = "SLIMBUS_0 Hostless",
783 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
784 .platform_name = "msm-pcm-hostless",
785 .dynamic = 1,
786 .dsp_link = &slimbus0_hl_media,
787 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
788 /* .be_id = do not care */
789 },
790 {
791 .name = "INT_FM Hostless",
792 .stream_name = "INT_FM Hostless",
793 .cpu_dai_name = "INT_FM_HOSTLESS",
794 .platform_name = "msm-pcm-hostless",
795 .dynamic = 1,
796 .dsp_link = &int_fm_hl_media,
797 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
798 /* .be_id = do not care */
799 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530800 {
801 .name = "MSM AFE-PCM RX",
802 .stream_name = "AFE-PROXY RX",
803 .cpu_dai_name = "msm-dai-q6.241",
804 .codec_name = "msm-stub-codec.1",
805 .codec_dai_name = "msm-stub-rx",
806 .platform_name = "msm-pcm-afe",
807 },
808 {
809 .name = "MSM AFE-PCM TX",
810 .stream_name = "AFE-PROXY TX",
811 .cpu_dai_name = "msm-dai-q6.240",
812 .codec_name = "msm-stub-codec.1",
813 .codec_dai_name = "msm-stub-tx",
814 .platform_name = "msm-pcm-afe",
815 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 /* Backend DAI Links */
817 {
818 .name = LPASS_BE_SLIMBUS_0_RX,
819 .stream_name = "Slimbus Playback",
820 .cpu_dai_name = "msm-dai-q6.16384",
821 .platform_name = "msm-pcm-routing",
822 .codec_name = "tabla_codec",
823 .codec_dai_name = "tabla_rx1",
824 .no_pcm = 1,
825 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
826 .init = &msm8960_audrx_init,
827 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
828 .ops = &msm8960_be_ops,
829 },
830 {
831 .name = LPASS_BE_SLIMBUS_0_TX,
832 .stream_name = "Slimbus Capture",
833 .cpu_dai_name = "msm-dai-q6.16385",
834 .platform_name = "msm-pcm-routing",
835 .codec_name = "tabla_codec",
836 .codec_dai_name = "tabla_tx1",
837 .no_pcm = 1,
838 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
839 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
840 .ops = &msm8960_be_ops,
841 },
842 /* Backend BT/FM DAI Links */
843 {
844 .name = LPASS_BE_INT_BT_SCO_RX,
845 .stream_name = "Internal BT-SCO Playback",
846 .cpu_dai_name = "msm-dai-q6.12288",
847 .platform_name = "msm-pcm-routing",
848 .codec_name = "msm-stub-codec.1",
849 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700850 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851 .no_pcm = 1,
852 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700853 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 },
855 {
856 .name = LPASS_BE_INT_BT_SCO_TX,
857 .stream_name = "Internal BT-SCO Capture",
858 .cpu_dai_name = "msm-dai-q6.12289",
859 .platform_name = "msm-pcm-routing",
860 .codec_name = "msm-stub-codec.1",
861 .codec_dai_name = "msm-stub-tx",
862 .no_pcm = 1,
863 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700864 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865 },
866 {
867 .name = LPASS_BE_INT_FM_RX,
868 .stream_name = "Internal FM Playback",
869 .cpu_dai_name = "msm-dai-q6.12292",
870 .platform_name = "msm-pcm-routing",
871 .codec_name = "msm-stub-codec.1",
872 .codec_dai_name = "msm-stub-rx",
873 .no_pcm = 1,
874 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
875 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
876 },
877 {
878 .name = LPASS_BE_INT_FM_TX,
879 .stream_name = "Internal FM Capture",
880 .cpu_dai_name = "msm-dai-q6.12293",
881 .platform_name = "msm-pcm-routing",
882 .codec_name = "msm-stub-codec.1",
883 .codec_dai_name = "msm-stub-tx",
884 .no_pcm = 1,
885 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
886 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
887 },
888 /* HDMI BACK END DAI Link */
889 {
890 .name = LPASS_BE_HDMI,
891 .stream_name = "HDMI Playback",
892 .cpu_dai_name = "msm-dai-q6.8",
893 .platform_name = "msm-pcm-routing",
894 .codec_name = "msm-stub-codec.1",
895 .codec_dai_name = "msm-stub-rx",
896 .no_pcm = 1,
897 .no_codec = 1,
898 .be_id = MSM_BACKEND_DAI_HDMI_RX,
899 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
900 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530901 /* Backend AFE DAI Links */
902 {
903 .name = LPASS_BE_AFE_PCM_RX,
904 .stream_name = "AFE Playback",
905 .cpu_dai_name = "msm-dai-q6.224",
906 .platform_name = "msm-pcm-routing",
907 .codec_name = "msm-stub-codec.1",
908 .codec_dai_name = "msm-stub-rx",
909 .no_codec = 1,
910 .no_pcm = 1,
911 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
912 },
913 {
914 .name = LPASS_BE_AFE_PCM_TX,
915 .stream_name = "AFE Capture",
916 .cpu_dai_name = "msm-dai-q6.225",
917 .platform_name = "msm-pcm-routing",
918 .codec_name = "msm-stub-codec.1",
919 .codec_dai_name = "msm-stub-tx",
920 .no_codec = 1,
921 .no_pcm = 1,
922 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
923 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924};
925
926struct snd_soc_card snd_soc_card_msm8960 = {
927 .name = "msm8960-snd-card",
928 .dai_link = msm8960_dai,
929 .num_links = ARRAY_SIZE(msm8960_dai),
930};
931
932static struct platform_device *msm8960_snd_device;
933
934static int msm8960_configure_headset_mic_gpios(void)
935{
936 int ret;
937 struct pm_gpio param = {
938 .direction = PM_GPIO_DIR_OUT,
939 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
940 .output_value = 1,
941 .pull = PM_GPIO_PULL_NO,
942 .vin_sel = PM_GPIO_VIN_S4,
943 .out_strength = PM_GPIO_STRENGTH_MED,
944 .function = PM_GPIO_FUNC_NORMAL,
945 };
946
947 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
948 if (ret) {
949 pr_err("%s: Failed to request gpio %d\n", __func__,
950 PM8921_GPIO_PM_TO_SYS(23));
951 return ret;
952 }
953
954 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
955 if (ret)
956 pr_err("%s: Failed to configure gpio %d\n", __func__,
957 PM8921_GPIO_PM_TO_SYS(23));
958 else
959 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
960
961 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
962 if (ret) {
963 pr_err("%s: Failed to request gpio %d\n", __func__,
964 PM8921_GPIO_PM_TO_SYS(35));
965 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
966 return ret;
967 }
968 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
969 if (ret)
970 pr_err("%s: Failed to configure gpio %d\n", __func__,
971 PM8921_GPIO_PM_TO_SYS(35));
972 else
973 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 1);
974
975 return 0;
976}
977static void msm8960_free_headset_mic_gpios(void)
978{
979 if (msm8960_headset_gpios_configured) {
980 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
981 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
982 }
983}
984
985static int __init msm8960_audio_init(void)
986{
987 int ret;
988
989 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
990 if (!msm8960_snd_device) {
991 pr_err("Platform device allocation failed\n");
992 return -ENOMEM;
993 }
994
995 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
996 ret = platform_device_add(msm8960_snd_device);
997 if (ret) {
998 platform_device_put(msm8960_snd_device);
999 return ret;
1000 }
1001
1002 if (msm8960_configure_headset_mic_gpios()) {
1003 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1004 msm8960_headset_gpios_configured = 0;
1005 } else
1006 msm8960_headset_gpios_configured = 1;
1007
1008 return ret;
1009
1010}
1011module_init(msm8960_audio_init);
1012
1013static void __exit msm8960_audio_exit(void)
1014{
1015 msm8960_free_headset_mic_gpios();
1016 platform_device_unregister(msm8960_snd_device);
1017}
1018module_exit(msm8960_audio_exit);
1019
1020MODULE_DESCRIPTION("ALSA SoC MSM8960");
1021MODULE_LICENSE("GPL v2");