blob: 0d45e8255e39945f6a3067f2b76c33020d0ed0da [file] [log] [blame]
Joonwoo Park0976d012011-12-22 11:48:18 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include <linux/mfd/pm8xxx/pm8921.h>
Joonwoo Park0976d012011-12-22 11:48:18 -080019#include <linux/slab.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#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>
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070028#include <linux/mfd/wcd9xxx/core.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029#include "msm-pcm-routing.h"
Bhalchandra Gajare0b9d4d52011-10-21 16:17:47 -070030#include "../codecs/wcd9310.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
32/* 8960 machine driver */
33
34#define PM8921_GPIO_BASE NR_GPIO_IRQS
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070035#define PM8921_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
37
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#define MSM8960_SPK_ON 1
39#define MSM8960_SPK_OFF 0
40
41#define msm8960_SLIM_0_RX_MAX_CHANNELS 2
42#define msm8960_SLIM_0_TX_MAX_CHANNELS 4
43
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070044#define BTSCO_RATE_8KHZ 8000
45#define BTSCO_RATE_16KHZ 16000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046
Kiran Kandi462acea2011-08-31 23:53:14 -070047#define BOTTOM_SPK_AMP_POS 0x1
48#define BOTTOM_SPK_AMP_NEG 0x2
49#define TOP_SPK_AMP_POS 0x4
50#define TOP_SPK_AMP_NEG 0x8
51
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070052#define GPIO_AUX_PCM_DOUT 63
53#define GPIO_AUX_PCM_DIN 64
54#define GPIO_AUX_PCM_SYNC 65
55#define GPIO_AUX_PCM_CLK 66
56
Joonwoo Park0976d012011-12-22 11:48:18 -080057#define TABLA_EXT_CLK_RATE 12288000
58
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080059#define TABLA_MBHC_DEF_BUTTONS 8
Joonwoo Park0976d012011-12-22 11:48:18 -080060#define TABLA_MBHC_DEF_RLOADS 5
61
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070062#define JACK_DETECT_GPIO 38
63#define JACK_DETECT_INT PM8921_GPIO_IRQ(PM8921_IRQ_BASE, JACK_DETECT_GPIO)
64#define GPIO_DETECT_USED false
65
Harmandeep Singh0dd82412011-11-11 09:46:17 -080066static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
67static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068static int msm8960_spk_control;
Kiran Kandi462acea2011-08-31 23:53:14 -070069static int msm8960_ext_bottom_spk_pamp;
70static int msm8960_ext_top_spk_pamp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071static int msm8960_slim_0_rx_ch = 1;
72static int msm8960_slim_0_tx_ch = 1;
73
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070074static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
75static int msm8960_btsco_ch = 1;
76
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077static 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
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070085static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
86 bool dapm);
87
88static struct tabla_mbhc_config mbhc_cfg = {
89 .headset_jack = &hs_jack,
90 .button_jack = &button_jack,
91 .read_fw_bin = false,
92 .calibration = NULL,
93 .micbias = TABLA_MICBIAS2,
94 .mclk_cb_fn = msm8960_enable_codec_ext_clk,
95 .mclk_rate = TABLA_EXT_CLK_RATE,
96 .gpio = 0,
97 .gpio_irq = 0,
98 .gpio_level_insert = 1,
99};
Joonwoo Park0976d012011-12-22 11:48:18 -0800100
Joonwoo Park28f49c82012-03-16 12:29:21 -0700101static struct mutex cdc_mclk_mutex;
102
Kiran Kandi462acea2011-08-31 23:53:14 -0700103static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104{
105 int ret = 0;
106
107 struct pm_gpio param = {
108 .direction = PM_GPIO_DIR_OUT,
109 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
110 .output_value = 1,
111 .pull = PM_GPIO_PULL_NO,
112 .vin_sel = PM_GPIO_VIN_S4,
113 .out_strength = PM_GPIO_STRENGTH_MED,
Kiran Kandi462acea2011-08-31 23:53:14 -0700114 .
115 function = PM_GPIO_FUNC_NORMAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 };
117
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800118 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800120 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
Kiran Kandi462acea2011-08-31 23:53:14 -0700121 if (ret) {
122 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800123 __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700124 return;
125 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800126 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
Kiran Kandi462acea2011-08-31 23:53:14 -0700127 if (ret)
128 pr_err("%s: Failed to configure Bottom Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800129 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700130 else {
131 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800132 gpio_direction_output(bottom_spk_pamp_gpio, 1);
Kiran Kandi462acea2011-08-31 23:53:14 -0700133 }
134
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800135 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700136
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800137 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700138 if (ret) {
139 pr_err("%s: Error requesting GPIO %d\n", __func__,
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800140 top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700141 return;
142 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800143 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700144 if (ret)
Kiran Kandi462acea2011-08-31 23:53:14 -0700145 pr_err("%s: Failed to configure Top Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800146 " gpio %u\n", __func__, top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700147 else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700148 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800149 gpio_direction_output(top_spk_pamp_gpio, 1);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700150 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700151 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700152 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
153 " gpio = %u\n", __func__, spk_amp_gpio);
154 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700157
Kiran Kandi462acea2011-08-31 23:53:14 -0700158static void msm8960_ext_spk_power_amp_on(u32 spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159{
Kiran Kandi462acea2011-08-31 23:53:14 -0700160 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
161
162 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
163 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
164
165 pr_debug("%s() External Bottom Speaker Ampl already "
166 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700167 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700168 }
169
170 msm8960_ext_bottom_spk_pamp |= spk;
171
172 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
173 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
174
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800175 msm8960_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700176 pr_debug("%s: slepping 4 ms after turning on external "
177 " Bottom Speaker Ampl\n", __func__);
178 usleep_range(4000, 4000);
179 }
180
181 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
182
183 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
184 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
185
186 pr_debug("%s() External Top Speaker Ampl already"
187 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700188 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700189 }
190
191 msm8960_ext_top_spk_pamp |= spk;
192
193 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
194 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
195
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800196 msm8960_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700197 pr_debug("%s: sleeping 4 ms after turning on "
198 " external Top Speaker Ampl\n", __func__);
199 usleep_range(4000, 4000);
200 }
201 } else {
202
203 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
204 __func__, spk);
205 return;
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700206 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700207}
208
209static void msm8960_ext_spk_power_amp_off(u32 spk)
210{
211 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
212
213 if (!msm8960_ext_bottom_spk_pamp)
214 return;
215
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800216 gpio_direction_output(bottom_spk_pamp_gpio, 0);
217 gpio_free(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700218 msm8960_ext_bottom_spk_pamp = 0;
219
220 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
221 " Speaker Ampl\n", __func__);
222
223 usleep_range(4000, 4000);
224
225 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
226
227 if (!msm8960_ext_top_spk_pamp)
228 return;
229
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800230 gpio_direction_output(top_spk_pamp_gpio, 0);
231 gpio_free(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700232 msm8960_ext_top_spk_pamp = 0;
233
234 pr_debug("%s: sleeping 4 ms after turning off external Top"
235 " Spkaker Ampl\n", __func__);
236
237 usleep_range(4000, 4000);
238 } else {
239
240 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
241 __func__, spk);
242 return;
243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246static void msm8960_ext_control(struct snd_soc_codec *codec)
247{
248 struct snd_soc_dapm_context *dapm = &codec->dapm;
249
250 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700251 if (msm8960_spk_control == MSM8960_SPK_ON) {
252 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
253 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
254 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
255 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
256 } else {
257 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
258 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
259 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
260 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
261 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262
263 snd_soc_dapm_sync(dapm);
264}
265
266static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
267 struct snd_ctl_elem_value *ucontrol)
268{
269 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
270 ucontrol->value.integer.value[0] = msm8960_spk_control;
271 return 0;
272}
273static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
274 struct snd_ctl_elem_value *ucontrol)
275{
276 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
277
278 pr_debug("%s()\n", __func__);
279 if (msm8960_spk_control == ucontrol->value.integer.value[0])
280 return 0;
281
282 msm8960_spk_control = ucontrol->value.integer.value[0];
283 msm8960_ext_control(codec);
284 return 1;
285}
286static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
287 struct snd_kcontrol *k, int event)
288{
289 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700290
291 if (SND_SOC_DAPM_EVENT_ON(event)) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700292 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
293 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
294 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
295 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
296 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
297 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
298 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
299 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
300 else {
301 pr_err("%s() Invalid Speaker Widget = %s\n",
302 __func__, w->name);
303 return -EINVAL;
304 }
305
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700306 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700307 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
308 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
309 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
310 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
311 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
312 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
313 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
314 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
315 else {
316 pr_err("%s() Invalid Speaker Widget = %s\n",
317 __func__, w->name);
318 return -EINVAL;
319 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700320 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 return 0;
322}
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700323
324static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
325 bool dapm)
Joonwoo Park0976d012011-12-22 11:48:18 -0800326{
Joonwoo Park28f49c82012-03-16 12:29:21 -0700327 int r = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -0800328 pr_debug("%s: enable = %d\n", __func__, enable);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700329
330 mutex_lock(&cdc_mclk_mutex);
Joonwoo Park0976d012011-12-22 11:48:18 -0800331 if (enable) {
332 clk_users++;
333 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700334 if (clk_users == 1) {
335 if (codec_clk) {
336 clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
337 clk_enable(codec_clk);
338 tabla_mclk_enable(codec, 1, dapm);
339 } else {
340 pr_err("%s: Error setting Tabla MCLK\n",
341 __func__);
342 clk_users--;
343 r = -EINVAL;
344 }
Joonwoo Park0976d012011-12-22 11:48:18 -0800345 }
346 } else {
Joonwoo Park28f49c82012-03-16 12:29:21 -0700347 if (clk_users > 0) {
348 clk_users--;
349 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
350 if (clk_users == 0) {
351 pr_debug("%s: disabling MCLK. clk_users = %d\n",
Joonwoo Park0976d012011-12-22 11:48:18 -0800352 __func__, clk_users);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700353 clk_disable(codec_clk);
354 tabla_mclk_enable(codec, 0, dapm);
355 }
356 } else {
357 pr_err("%s: Error releasing Tabla MCLK\n", __func__);
358 r = -EINVAL;
Joonwoo Park0976d012011-12-22 11:48:18 -0800359 }
360 }
Joonwoo Park28f49c82012-03-16 12:29:21 -0700361 mutex_unlock(&cdc_mclk_mutex);
362 return r;
Joonwoo Park0976d012011-12-22 11:48:18 -0800363}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700365static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
366 struct snd_kcontrol *kcontrol, int event)
367{
368 pr_debug("%s: event = %d\n", __func__, event);
369
370 switch (event) {
371 case SND_SOC_DAPM_PRE_PMU:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700372 return msm8960_enable_codec_ext_clk(w->codec, 1, true);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700373 case SND_SOC_DAPM_POST_PMD:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700374 return msm8960_enable_codec_ext_clk(w->codec, 0, true);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700375 }
376 return 0;
377}
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700380
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700381 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
382 msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
383
Kiran Kandi462acea2011-08-31 23:53:14 -0700384 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
385 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
386
387 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
388 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700389
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 SND_SOC_DAPM_MIC("Handset Mic", NULL),
391 SND_SOC_DAPM_MIC("Headset Mic", NULL),
392 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700393 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
394 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700395
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700396 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700397 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700398 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700399 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700400 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
401 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403};
404
Bradley Rubin229c6a52011-07-12 16:18:48 -0700405static const struct snd_soc_dapm_route common_audio_map[] = {
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700406
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700407 {"RX_BIAS", NULL, "MCLK"},
408 {"LDO_H", NULL, "MCLK"},
409
410 /* Speaker path */
Kiran Kandi462acea2011-08-31 23:53:14 -0700411 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
412 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700413
Kiran Kandi462acea2011-08-31 23:53:14 -0700414 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
415 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416
417 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700418 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
419 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700420
421 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700423
Patrick Laie519dd62011-09-28 12:37:11 -0700424 /**
425 * AMIC3 and AMIC4 inputs are connected to ANC microphones
426 * These mics are biased differently on CDP and FLUID
427 * routing entries below are based on bias arrangement
428 * on FLUID.
429 */
430 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
431 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
432
433 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
434 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
435
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700436 {"HEADPHONE", NULL, "LDO_H"},
437
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700438 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700439 * The digital Mic routes are setup considering
440 * fluid as default device.
441 */
442
443 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700444 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700445 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700446 * Conncted to DMIC2 Input on Tabla codec.
447 */
448 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700449 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700450
451 /**
452 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700453 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700454 * Conncted to DMIC1 Input on Tabla codec.
455 */
456 {"DMIC1", NULL, "MIC BIAS1 External"},
457 {"MIC BIAS1 External", NULL, "Digital Mic2"},
458
459 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700460 * Digital Mic3. Back Bottom Digital Mic on Fluid.
461 * Digital Mic GM1 on CDP mainboard.
462 * Conncted to DMIC4 Input on Tabla codec.
463 */
464 {"DMIC4", NULL, "MIC BIAS3 External"},
465 {"MIC BIAS3 External", NULL, "Digital Mic3"},
466
467 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700468 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700469 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700470 * Conncted to DMIC3 Input on Tabla codec.
471 */
472 {"DMIC3", NULL, "MIC BIAS3 External"},
473 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700474
475 /**
476 * Digital Mic5. Front top Digital Mic on Fluid.
477 * Digital Mic GM3 on CDP mainboard.
478 * Conncted to DMIC5 Input on Tabla codec.
479 */
480 {"DMIC5", NULL, "MIC BIAS4 External"},
481 {"MIC BIAS4 External", NULL, "Digital Mic5"},
482
Patrick Laicb7802b2011-10-04 12:39:18 -0700483 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
484 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700485 */
486 {"DMIC6", NULL, "MIC BIAS4 External"},
487 {"MIC BIAS4 External", NULL, "Digital Mic6"},
Bradley Rubin229c6a52011-07-12 16:18:48 -0700488};
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700491static const char *slim0_rx_ch_text[] = {"One", "Two"};
492static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494static const struct soc_enum msm8960_enum[] = {
495 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700496 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
497 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498};
499
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700500static const char *btsco_rate_text[] = {"8000", "16000"};
501static const struct soc_enum msm8960_btsco_enum[] = {
502 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
503};
504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
506 struct snd_ctl_elem_value *ucontrol)
507{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700508 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800509 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700510 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 return 0;
512}
513
514static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
515 struct snd_ctl_elem_value *ucontrol)
516{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700517 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518
Patrick Lai9f4b4292011-07-16 22:11:09 -0700519 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800520 msm8960_slim_0_rx_ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 return 1;
522}
523
524static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
525 struct snd_ctl_elem_value *ucontrol)
526{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700527 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800528 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700529 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 return 0;
531}
532
533static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
534 struct snd_ctl_elem_value *ucontrol)
535{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700536 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537
538 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800539 msm8960_slim_0_tx_ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540 return 1;
541}
542
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700543static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
545{
Joonwoo Park0976d012011-12-22 11:48:18 -0800546 pr_debug("%s: msm8960_btsco_rate = %d", __func__, msm8960_btsco_rate);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700547 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
548 return 0;
549}
550
551static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
552 struct snd_ctl_elem_value *ucontrol)
553{
554 switch (ucontrol->value.integer.value[0]) {
555 case 0:
556 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
557 break;
558 case 1:
559 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
560 break;
561 default:
562 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
563 break;
564 }
Joonwoo Park0976d012011-12-22 11:48:18 -0800565 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700566 return 0;
567}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568
569static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
570 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
571 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700572 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
573 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
574 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
575 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576};
577
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700578static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
579 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
580 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
581};
582
583static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
584{
585 int err = 0;
586 struct snd_soc_platform *platform = rtd->platform;
587
588 err = snd_soc_add_platform_controls(platform,
589 int_btsco_rate_mixer_controls,
590 ARRAY_SIZE(int_btsco_rate_mixer_controls));
591 if (err < 0)
592 return err;
593 return 0;
594}
595
Joonwoo Park0976d012011-12-22 11:48:18 -0800596static void *def_tabla_mbhc_cal(void)
597{
598 void *tabla_cal;
599 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
600 u16 *btn_low, *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -0800601 u8 *n_ready, *n_cic, *gain;
Joonwoo Park0976d012011-12-22 11:48:18 -0800602
603 tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
604 TABLA_MBHC_DEF_RLOADS),
605 GFP_KERNEL);
606 if (!tabla_cal) {
607 pr_err("%s: out of memory\n", __func__);
608 return NULL;
609 }
610
611#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
612 S(t_ldoh, 100);
613 S(t_bg_fast_settle, 100);
614 S(t_shutdown_plug_rem, 255);
615 S(mbhc_nsa, 4);
616 S(mbhc_navg, 4);
617#undef S
618#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
619 S(mic_current, TABLA_PID_MIC_5_UA);
620 S(hph_current, TABLA_PID_MIC_5_UA);
621 S(t_mic_pid, 100);
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800622 S(t_ins_complete, 250);
Joonwoo Park0976d012011-12-22 11:48:18 -0800623 S(t_ins_retry, 200);
624#undef S
625#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
626 S(v_no_mic, 30);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800627 S(v_hs_max, 1550);
Joonwoo Park0976d012011-12-22 11:48:18 -0800628#undef S
629#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800630 S(c[0], 62);
631 S(c[1], 124);
632 S(nc, 1);
633 S(n_meas, 3);
Joonwoo Park0976d012011-12-22 11:48:18 -0800634 S(mbhc_nsc, 11);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800635 S(n_btn_meas, 1);
636 S(n_btn_con, 2);
Joonwoo Park0976d012011-12-22 11:48:18 -0800637 S(num_btn, TABLA_MBHC_DEF_BUTTONS);
638 S(v_btn_press_delta_sta, 100);
639 S(v_btn_press_delta_cic, 50);
640#undef S
641 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
642 btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
643 btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800644 btn_low[0] = -50;
645 btn_high[0] = 10;
646 btn_low[1] = 11;
647 btn_high[1] = 38;
648 btn_low[2] = 39;
649 btn_high[2] = 64;
650 btn_low[3] = 65;
651 btn_high[3] = 91;
652 btn_low[4] = 92;
653 btn_high[4] = 115;
654 btn_low[5] = 116;
655 btn_high[5] = 141;
656 btn_low[6] = 142;
657 btn_high[6] = 163;
658 btn_low[7] = 164;
659 btn_high[7] = 250;
Joonwoo Parkc0672392012-01-11 11:03:14 -0800660 n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
661 n_ready[0] = 48;
662 n_ready[1] = 38;
Joonwoo Park0976d012011-12-22 11:48:18 -0800663 n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800664 n_cic[0] = 60;
665 n_cic[1] = 47;
Joonwoo Park0976d012011-12-22 11:48:18 -0800666 gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
667 gain[0] = 11;
668 gain[1] = 9;
669
670 return tabla_cal;
671}
672
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800673static int msm8960_hw_params(struct snd_pcm_substream *substream,
674 struct snd_pcm_hw_params *params)
675{
676 struct snd_soc_pcm_runtime *rtd = substream->private_data;
677 struct snd_soc_dai *codec_dai = rtd->codec_dai;
678 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
679 int ret = 0;
680 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
681 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
682
683 pr_debug("%s: ch=%d\n", __func__,
684 msm8960_slim_0_rx_ch);
685 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
686 ret = snd_soc_dai_get_channel_map(codec_dai,
687 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
688 if (ret < 0) {
689 pr_err("%s: failed to get codec chan map\n", __func__);
690 goto end;
691 }
692
693 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
694 msm8960_slim_0_rx_ch, rx_ch);
695 if (ret < 0) {
696 pr_err("%s: failed to set cpu chan map\n", __func__);
697 goto end;
698 }
699 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
700 msm8960_slim_0_rx_ch, rx_ch);
701 if (ret < 0) {
702 pr_err("%s: failed to set codec channel map\n",
703 __func__);
704 goto end;
705 }
706 } else {
707 ret = snd_soc_dai_get_channel_map(codec_dai,
708 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
709 if (ret < 0) {
710 pr_err("%s: failed to get codec chan map\n", __func__);
711 goto end;
712 }
713 ret = snd_soc_dai_set_channel_map(cpu_dai,
714 msm8960_slim_0_tx_ch, tx_ch, 0 , 0);
715 if (ret < 0) {
716 pr_err("%s: failed to set cpu chan map\n", __func__);
717 goto end;
718 }
719 ret = snd_soc_dai_set_channel_map(codec_dai,
720 msm8960_slim_0_tx_ch, tx_ch, 0, 0);
721 if (ret < 0) {
722 pr_err("%s: failed to set codec channel map\n",
723 __func__);
724 goto end;
725 }
726
727
728 }
729end:
730 return ret;
731}
732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
734{
735 int err;
736 struct snd_soc_codec *codec = rtd->codec;
737 struct snd_soc_dapm_context *dapm = &codec->dapm;
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800738 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700739 struct pm_gpio jack_gpio_cfg = {
740 .direction = PM_GPIO_DIR_IN,
741 .pull = PM_GPIO_PULL_UP_1P5,
742 .function = PM_GPIO_FUNC_NORMAL,
743 .vin_sel = 2,
744 .inv_int_pol = 0,
745 };
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800747 pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800749 if (machine_is_msm8960_liquid()) {
750 top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
751 bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
752 }
753
Kiran Kandi28ef14e2011-09-16 15:45:47 -0700754 rtd->pmdown_time = 0;
755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
757 ARRAY_SIZE(tabla_msm8960_controls));
758 if (err < 0)
759 return err;
760
761 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
762 ARRAY_SIZE(msm8960_dapm_widgets));
763
Bradley Rubin229c6a52011-07-12 16:18:48 -0700764 snd_soc_dapm_add_routes(dapm, common_audio_map,
765 ARRAY_SIZE(common_audio_map));
766
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700767 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
768 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
769 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
770 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771
772 snd_soc_dapm_sync(dapm);
773
774 err = snd_soc_jack_new(codec, "Headset Jack",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800775 (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
776 SND_JACK_OC_HPHR),
777 &hs_jack);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 if (err) {
779 pr_err("failed to create new jack\n");
780 return err;
781 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700782
783 err = snd_soc_jack_new(codec, "Button Jack",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800784 TABLA_JACK_BUTTON_MASK, &button_jack);
Bradley Rubincb1e2732011-06-23 16:49:20 -0700785 if (err) {
786 pr_err("failed to create new jack\n");
787 return err;
788 }
789
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800790 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
791
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700792 if (GPIO_DETECT_USED) {
793 mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
794 mbhc_cfg.gpio_irq = JACK_DETECT_INT;
795 }
796
797 if (mbhc_cfg.gpio) {
798 err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
799 if (err) {
800 pr_err("%s: pm8xxx_gpio_config failed %d\n", __func__,
801 err);
802 return err;
803 }
804 }
805 err = tabla_hs_detect(codec, &mbhc_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806
Joonwoo Park03324832012-03-19 19:36:16 -0700807 return err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808}
809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700811 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812 .trigger = {
813 SND_SOC_DSP_TRIGGER_POST,
814 SND_SOC_DSP_TRIGGER_POST
815 },
816};
817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700819 .playback = true,
820 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 .trigger = {
822 SND_SOC_DSP_TRIGGER_POST,
823 SND_SOC_DSP_TRIGGER_POST
824 },
825};
826
Patrick Lai9b56e1d2012-01-22 22:14:15 -0800827/* bi-directional media definition for hostless PCM device */
828static struct snd_soc_dsp_link bidir_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700829 .playback = true,
830 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831 .trigger = {
832 SND_SOC_DSP_TRIGGER_POST,
833 SND_SOC_DSP_TRIGGER_POST
834 },
835};
836
Alex Wongb3d06a02012-01-12 10:00:41 -0800837static struct snd_soc_dsp_link hdmi_rx_hl = {
838 .playback = true,
839 .trigger = {
840 SND_SOC_DSP_TRIGGER_POST,
841 SND_SOC_DSP_TRIGGER_POST
842 },
843};
844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700845static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
846 struct snd_pcm_hw_params *params)
847{
848 struct snd_interval *rate = hw_param_interval(params,
849 SNDRV_PCM_HW_PARAM_RATE);
850
851 struct snd_interval *channels = hw_param_interval(params,
852 SNDRV_PCM_HW_PARAM_CHANNELS);
853
854 pr_debug("%s()\n", __func__);
855 rate->min = rate->max = 48000;
856 channels->min = channels->max = msm8960_slim_0_rx_ch;
857
858 return 0;
859}
860
861static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
862 struct snd_pcm_hw_params *params)
863{
864 struct snd_interval *rate = hw_param_interval(params,
865 SNDRV_PCM_HW_PARAM_RATE);
866
867 struct snd_interval *channels = hw_param_interval(params,
868 SNDRV_PCM_HW_PARAM_CHANNELS);
869
870 pr_debug("%s()\n", __func__);
871 rate->min = rate->max = 48000;
872 channels->min = channels->max = msm8960_slim_0_tx_ch;
873
874 return 0;
875}
876
877static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
878 struct snd_pcm_hw_params *params)
879{
880 struct snd_interval *rate = hw_param_interval(params,
881 SNDRV_PCM_HW_PARAM_RATE);
882
883 pr_debug("%s()\n", __func__);
884 rate->min = rate->max = 48000;
885
886 return 0;
887}
888
Helen Zeng73f7fc62011-11-18 16:29:59 -0800889static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
890 struct snd_pcm_hw_params *params)
891{
892 struct snd_interval *rate = hw_param_interval(params,
893 SNDRV_PCM_HW_PARAM_RATE);
894
895 struct snd_interval *channels = hw_param_interval(params,
896 SNDRV_PCM_HW_PARAM_CHANNELS);
897
Kiran Kandi5e809b02012-01-31 00:24:33 -0800898 pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
899 channels->min, channels->max);
900
Helen Zeng73f7fc62011-11-18 16:29:59 -0800901 rate->min = rate->max = 48000;
Helen Zeng73f7fc62011-11-18 16:29:59 -0800902
903 return 0;
904}
905
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700906static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
907 struct snd_pcm_hw_params *params)
908{
909 struct snd_interval *rate = hw_param_interval(params,
910 SNDRV_PCM_HW_PARAM_RATE);
911
912 struct snd_interval *channels = hw_param_interval(params,
913 SNDRV_PCM_HW_PARAM_CHANNELS);
914
915 rate->min = rate->max = msm8960_btsco_rate;
916 channels->min = channels->max = msm8960_btsco_ch;
917
918 return 0;
919}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700920static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
921 struct snd_pcm_hw_params *params)
922{
923 struct snd_interval *rate = hw_param_interval(params,
924 SNDRV_PCM_HW_PARAM_RATE);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700925
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700926 struct snd_interval *channels = hw_param_interval(params,
927 SNDRV_PCM_HW_PARAM_CHANNELS);
928
929 /* PCM only supports mono output with 8khz sample rate */
930 rate->min = rate->max = 8000;
931 channels->min = channels->max = 1;
932
933 return 0;
934}
935static int msm8960_aux_pcm_get_gpios(void)
936{
937 int ret = 0;
938
939 pr_debug("%s\n", __func__);
940
941 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
942 if (ret < 0) {
943 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
944 __func__, GPIO_AUX_PCM_DOUT);
945 goto fail_dout;
946 }
947
948 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
949 if (ret < 0) {
950 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
951 __func__, GPIO_AUX_PCM_DIN);
952 goto fail_din;
953 }
954
955 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
956 if (ret < 0) {
957 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
958 __func__, GPIO_AUX_PCM_SYNC);
959 goto fail_sync;
960 }
961 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
962 if (ret < 0) {
963 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
964 __func__, GPIO_AUX_PCM_CLK);
965 goto fail_clk;
966 }
967
968 return 0;
969
970fail_clk:
971 gpio_free(GPIO_AUX_PCM_SYNC);
972fail_sync:
973 gpio_free(GPIO_AUX_PCM_DIN);
974fail_din:
975 gpio_free(GPIO_AUX_PCM_DOUT);
976fail_dout:
977
978 return ret;
979}
980
981static int msm8960_aux_pcm_free_gpios(void)
982{
983 gpio_free(GPIO_AUX_PCM_DIN);
984 gpio_free(GPIO_AUX_PCM_DOUT);
985 gpio_free(GPIO_AUX_PCM_SYNC);
986 gpio_free(GPIO_AUX_PCM_CLK);
987
988 return 0;
989}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990static int msm8960_startup(struct snd_pcm_substream *substream)
991{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700992 pr_debug("%s(): substream = %s stream = %d\n", __func__,
993 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 return 0;
995}
996
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700997static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
998{
999 int ret = 0;
1000
1001 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1002 ret = msm8960_aux_pcm_get_gpios();
1003 if (ret < 0) {
1004 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
1005 return -EINVAL;
1006 }
1007 return 0;
1008}
1009
1010static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
1011{
1012
1013 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1014 msm8960_aux_pcm_free_gpios();
1015}
1016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017static void msm8960_shutdown(struct snd_pcm_substream *substream)
1018{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001019 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1020 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021}
1022
1023static struct snd_soc_ops msm8960_be_ops = {
1024 .startup = msm8960_startup,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001025 .hw_params = msm8960_hw_params,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 .shutdown = msm8960_shutdown,
1027};
1028
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001029static struct snd_soc_ops msm8960_auxpcm_be_ops = {
1030 .startup = msm8960_auxpcm_startup,
1031 .shutdown = msm8960_auxpcm_shutdown,
1032};
1033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034/* Digital audio interface glue - connects codec <---> CPU */
Kuirong Wangb25838e2012-01-16 23:37:23 -08001035static struct snd_soc_dai_link msm8960_dai_common[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 /* FrontEnd DAI Links */
1037 {
1038 .name = "MSM8960 Media1",
1039 .stream_name = "MultiMedia1",
1040 .cpu_dai_name = "MultiMedia1",
1041 .platform_name = "msm-pcm-dsp",
1042 .dynamic = 1,
1043 .dsp_link = &fe_media,
1044 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
1045 },
1046 {
1047 .name = "MSM8960 Media2",
1048 .stream_name = "MultiMedia2",
1049 .cpu_dai_name = "MultiMedia2",
Kiran Kandi5e809b02012-01-31 00:24:33 -08001050 .platform_name = "msm-multi-ch-pcm-dsp",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 .dynamic = 1,
1052 .dsp_link = &fe_media,
1053 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
1054 },
1055 {
1056 .name = "Circuit-Switch Voice",
1057 .stream_name = "CS-Voice",
1058 .cpu_dai_name = "CS-VOICE",
1059 .platform_name = "msm-pcm-voice",
1060 .dynamic = 1,
1061 .dsp_link = &fe_media,
1062 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
1063 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -07001064 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 },
1066 {
1067 .name = "MSM VoIP",
1068 .stream_name = "VoIP",
1069 .cpu_dai_name = "VoIP",
1070 .platform_name = "msm-voip-dsp",
1071 .dynamic = 1,
1072 .dsp_link = &fe_media,
1073 .be_id = MSM_FRONTEND_DAI_VOIP,
1074 },
1075 {
1076 .name = "MSM8960 LPA",
1077 .stream_name = "LPA",
1078 .cpu_dai_name = "MultiMedia3",
1079 .platform_name = "msm-pcm-lpa",
1080 .dynamic = 1,
1081 .dsp_link = &lpa_fe_media,
1082 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
1083 },
1084 /* Hostless PMC purpose */
1085 {
1086 .name = "SLIMBUS_0 Hostless",
1087 .stream_name = "SLIMBUS_0 Hostless",
1088 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
1089 .platform_name = "msm-pcm-hostless",
1090 .dynamic = 1,
Patrick Lai9b56e1d2012-01-22 22:14:15 -08001091 .dsp_link = &bidir_hl_media,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -07001093 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 /* .be_id = do not care */
1095 },
1096 {
1097 .name = "INT_FM Hostless",
1098 .stream_name = "INT_FM Hostless",
1099 .cpu_dai_name = "INT_FM_HOSTLESS",
1100 .platform_name = "msm-pcm-hostless",
1101 .dynamic = 1,
Patrick Lai9b56e1d2012-01-22 22:14:15 -08001102 .dsp_link = &bidir_hl_media,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -07001104 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 /* .be_id = do not care */
1106 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301107 {
1108 .name = "MSM AFE-PCM RX",
1109 .stream_name = "AFE-PROXY RX",
1110 .cpu_dai_name = "msm-dai-q6.241",
1111 .codec_name = "msm-stub-codec.1",
1112 .codec_dai_name = "msm-stub-rx",
1113 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -07001114 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301115 },
1116 {
1117 .name = "MSM AFE-PCM TX",
1118 .stream_name = "AFE-PROXY TX",
1119 .cpu_dai_name = "msm-dai-q6.240",
1120 .codec_name = "msm-stub-codec.1",
1121 .codec_dai_name = "msm-stub-tx",
1122 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -07001123 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301124 },
Asish Bhattacharya09f9e0a2011-11-11 13:22:47 +05301125 {
1126 .name = "MSM8960 Compr",
1127 .stream_name = "COMPR",
1128 .cpu_dai_name = "MultiMedia4",
1129 .platform_name = "msm-compr-dsp",
1130 .dynamic = 1,
1131 .dsp_link = &lpa_fe_media,
1132 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
1133 },
Patrick Lai9b56e1d2012-01-22 22:14:15 -08001134 {
1135 .name = "AUXPCM Hostless",
1136 .stream_name = "AUXPCM Hostless",
1137 .cpu_dai_name = "AUXPCM_HOSTLESS",
1138 .platform_name = "msm-pcm-hostless",
1139 .dynamic = 1,
1140 .dsp_link = &bidir_hl_media,
1141 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1142 .ignore_suspend = 1,
1143 },
Alex Wongb3d06a02012-01-12 10:00:41 -08001144 /* HDMI Hostless */
1145 {
1146 .name = "HDMI_RX_HOSTLESS",
1147 .stream_name = "HDMI_RX_HOSTLESS",
1148 .cpu_dai_name = "HDMI_HOSTLESS",
1149 .platform_name = "msm-pcm-hostless",
1150 .dynamic = 1,
1151 .dsp_link = &hdmi_rx_hl,
1152 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1153 .no_codec = 1,
1154 .ignore_suspend = 1,
1155 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 /* Backend BT/FM DAI Links */
1157 {
1158 .name = LPASS_BE_INT_BT_SCO_RX,
1159 .stream_name = "Internal BT-SCO Playback",
1160 .cpu_dai_name = "msm-dai-q6.12288",
1161 .platform_name = "msm-pcm-routing",
1162 .codec_name = "msm-stub-codec.1",
1163 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -07001164 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 .no_pcm = 1,
1166 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -07001167 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 },
1169 {
1170 .name = LPASS_BE_INT_BT_SCO_TX,
1171 .stream_name = "Internal BT-SCO Capture",
1172 .cpu_dai_name = "msm-dai-q6.12289",
1173 .platform_name = "msm-pcm-routing",
1174 .codec_name = "msm-stub-codec.1",
1175 .codec_dai_name = "msm-stub-tx",
1176 .no_pcm = 1,
1177 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -07001178 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 },
1180 {
1181 .name = LPASS_BE_INT_FM_RX,
1182 .stream_name = "Internal FM Playback",
1183 .cpu_dai_name = "msm-dai-q6.12292",
1184 .platform_name = "msm-pcm-routing",
1185 .codec_name = "msm-stub-codec.1",
1186 .codec_dai_name = "msm-stub-rx",
1187 .no_pcm = 1,
1188 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
1189 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1190 },
1191 {
1192 .name = LPASS_BE_INT_FM_TX,
1193 .stream_name = "Internal FM Capture",
1194 .cpu_dai_name = "msm-dai-q6.12293",
1195 .platform_name = "msm-pcm-routing",
1196 .codec_name = "msm-stub-codec.1",
1197 .codec_dai_name = "msm-stub-tx",
1198 .no_pcm = 1,
1199 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
1200 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1201 },
1202 /* HDMI BACK END DAI Link */
1203 {
1204 .name = LPASS_BE_HDMI,
1205 .stream_name = "HDMI Playback",
Kiran Kandi5e809b02012-01-31 00:24:33 -08001206 .cpu_dai_name = "msm-dai-q6-hdmi.8",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 .platform_name = "msm-pcm-routing",
1208 .codec_name = "msm-stub-codec.1",
1209 .codec_dai_name = "msm-stub-rx",
1210 .no_pcm = 1,
1211 .no_codec = 1,
1212 .be_id = MSM_BACKEND_DAI_HDMI_RX,
Helen Zeng73f7fc62011-11-18 16:29:59 -08001213 .be_hw_params_fixup = msm8960_hdmi_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301215 /* Backend AFE DAI Links */
1216 {
1217 .name = LPASS_BE_AFE_PCM_RX,
1218 .stream_name = "AFE Playback",
1219 .cpu_dai_name = "msm-dai-q6.224",
1220 .platform_name = "msm-pcm-routing",
1221 .codec_name = "msm-stub-codec.1",
1222 .codec_dai_name = "msm-stub-rx",
1223 .no_codec = 1,
1224 .no_pcm = 1,
1225 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1226 },
1227 {
1228 .name = LPASS_BE_AFE_PCM_TX,
1229 .stream_name = "AFE Capture",
1230 .cpu_dai_name = "msm-dai-q6.225",
1231 .platform_name = "msm-pcm-routing",
1232 .codec_name = "msm-stub-codec.1",
1233 .codec_dai_name = "msm-stub-tx",
1234 .no_codec = 1,
1235 .no_pcm = 1,
1236 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1237 },
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001238 /* AUX PCM Backend DAI Links */
1239 {
1240 .name = LPASS_BE_AUXPCM_RX,
1241 .stream_name = "AUX PCM Playback",
1242 .cpu_dai_name = "msm-dai-q6.2",
1243 .platform_name = "msm-pcm-routing",
1244 .codec_name = "msm-stub-codec.1",
1245 .codec_dai_name = "msm-stub-rx",
1246 .no_pcm = 1,
1247 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1248 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1249 .ops = &msm8960_auxpcm_be_ops,
1250 },
1251 {
1252 .name = LPASS_BE_AUXPCM_TX,
1253 .stream_name = "AUX PCM Capture",
1254 .cpu_dai_name = "msm-dai-q6.3",
1255 .platform_name = "msm-pcm-routing",
1256 .codec_name = "msm-stub-codec.1",
1257 .codec_dai_name = "msm-stub-tx",
1258 .no_pcm = 1,
1259 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1260 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1261 },
Helen Zeng0705a5f2011-10-14 15:29:52 -07001262 /* Incall Music BACK END DAI Link */
1263 {
1264 .name = LPASS_BE_VOICE_PLAYBACK_TX,
1265 .stream_name = "Voice Farend Playback",
1266 .cpu_dai_name = "msm-dai-q6.32773",
1267 .platform_name = "msm-pcm-routing",
1268 .codec_name = "msm-stub-codec.1",
1269 .codec_dai_name = "msm-stub-rx",
1270 .no_pcm = 1,
1271 .no_codec = 1,
1272 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
1273 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1274 },
Helen Zenge3d716a2011-10-14 16:32:16 -07001275 /* Incall Record Uplink BACK END DAI Link */
1276 {
1277 .name = LPASS_BE_INCALL_RECORD_TX,
1278 .stream_name = "Voice Uplink Capture",
1279 .cpu_dai_name = "msm-dai-q6.32772",
1280 .platform_name = "msm-pcm-routing",
1281 .codec_name = "msm-stub-codec.1",
1282 .codec_dai_name = "msm-stub-tx",
1283 .no_pcm = 1,
1284 .no_codec = 1,
1285 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
1286 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1287 },
1288 /* Incall Record Downlink BACK END DAI Link */
1289 {
1290 .name = LPASS_BE_INCALL_RECORD_RX,
1291 .stream_name = "Voice Downlink Capture",
1292 .cpu_dai_name = "msm-dai-q6.32771",
1293 .platform_name = "msm-pcm-routing",
1294 .codec_name = "msm-stub-codec.1",
1295 .codec_dai_name = "msm-stub-tx",
1296 .no_pcm = 1,
1297 .no_codec = 1,
1298 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
1299 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1300 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001301};
1302
Kuirong Wangb25838e2012-01-16 23:37:23 -08001303static struct snd_soc_dai_link msm8960_dai_delta_tabla1x[] = {
1304 /* Backend DAI Links */
1305 {
1306 .name = LPASS_BE_SLIMBUS_0_RX,
1307 .stream_name = "Slimbus Playback",
1308 .cpu_dai_name = "msm-dai-q6.16384",
1309 .platform_name = "msm-pcm-routing",
1310 .codec_name = "tabla1x_codec",
1311 .codec_dai_name = "tabla_rx1",
1312 .no_pcm = 1,
1313 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
1314 .init = &msm8960_audrx_init,
1315 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
1316 .ops = &msm8960_be_ops,
1317 },
1318 {
1319 .name = LPASS_BE_SLIMBUS_0_TX,
1320 .stream_name = "Slimbus Capture",
1321 .cpu_dai_name = "msm-dai-q6.16385",
1322 .platform_name = "msm-pcm-routing",
1323 .codec_name = "tabla1x_codec",
1324 .codec_dai_name = "tabla_tx1",
1325 .no_pcm = 1,
1326 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
1327 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
1328 .ops = &msm8960_be_ops,
1329 },
1330};
1331
1332
1333static struct snd_soc_dai_link msm8960_dai_delta_tabla2x[] = {
1334 /* Backend DAI Links */
1335 {
1336 .name = LPASS_BE_SLIMBUS_0_RX,
1337 .stream_name = "Slimbus Playback",
1338 .cpu_dai_name = "msm-dai-q6.16384",
1339 .platform_name = "msm-pcm-routing",
1340 .codec_name = "tabla_codec",
1341 .codec_dai_name = "tabla_rx1",
1342 .no_pcm = 1,
1343 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
1344 .init = &msm8960_audrx_init,
1345 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
1346 .ops = &msm8960_be_ops,
1347 },
1348 {
1349 .name = LPASS_BE_SLIMBUS_0_TX,
1350 .stream_name = "Slimbus Capture",
1351 .cpu_dai_name = "msm-dai-q6.16385",
1352 .platform_name = "msm-pcm-routing",
1353 .codec_name = "tabla_codec",
1354 .codec_dai_name = "tabla_tx1",
1355 .no_pcm = 1,
1356 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
1357 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
1358 .ops = &msm8960_be_ops,
1359 },
1360};
1361
1362static struct snd_soc_dai_link msm8960_tabla1x_dai[
1363 ARRAY_SIZE(msm8960_dai_common) +
1364 ARRAY_SIZE(msm8960_dai_delta_tabla1x)];
1365
1366
1367static struct snd_soc_dai_link msm8960_dai[
1368 ARRAY_SIZE(msm8960_dai_common) +
1369 ARRAY_SIZE(msm8960_dai_delta_tabla2x)];
1370
1371static struct snd_soc_card snd_soc_tabla1x_card_msm8960 = {
1372 .name = "msm8960-tabla1x-snd-card",
1373 .dai_link = msm8960_tabla1x_dai,
1374 .num_links = ARRAY_SIZE(msm8960_tabla1x_dai),
1375};
1376
1377static struct snd_soc_card snd_soc_card_msm8960 = {
1378 .name = "msm8960-snd-card",
1379 .dai_link = msm8960_dai,
1380 .num_links = ARRAY_SIZE(msm8960_dai),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381};
1382
1383static struct platform_device *msm8960_snd_device;
Kuirong Wangb25838e2012-01-16 23:37:23 -08001384static struct platform_device *msm8960_snd_tabla1x_device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385
1386static int msm8960_configure_headset_mic_gpios(void)
1387{
1388 int ret;
1389 struct pm_gpio param = {
1390 .direction = PM_GPIO_DIR_OUT,
1391 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1392 .output_value = 1,
1393 .pull = PM_GPIO_PULL_NO,
1394 .vin_sel = PM_GPIO_VIN_S4,
1395 .out_strength = PM_GPIO_STRENGTH_MED,
1396 .function = PM_GPIO_FUNC_NORMAL,
1397 };
1398
1399 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1400 if (ret) {
1401 pr_err("%s: Failed to request gpio %d\n", __func__,
1402 PM8921_GPIO_PM_TO_SYS(23));
1403 return ret;
1404 }
1405
1406 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
1407 if (ret)
1408 pr_err("%s: Failed to configure gpio %d\n", __func__,
1409 PM8921_GPIO_PM_TO_SYS(23));
1410 else
1411 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
1412
1413 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1414 if (ret) {
1415 pr_err("%s: Failed to request gpio %d\n", __func__,
1416 PM8921_GPIO_PM_TO_SYS(35));
1417 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1418 return ret;
1419 }
1420 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
1421 if (ret)
1422 pr_err("%s: Failed to configure gpio %d\n", __func__,
1423 PM8921_GPIO_PM_TO_SYS(35));
1424 else
Patrick Lai2ae0a002011-09-26 14:51:09 -07001425 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426
1427 return 0;
1428}
1429static void msm8960_free_headset_mic_gpios(void)
1430{
1431 if (msm8960_headset_gpios_configured) {
1432 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1433 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
1434 }
1435}
1436
1437static int __init msm8960_audio_init(void)
1438{
1439 int ret;
1440
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301441 if (!cpu_is_msm8960()) {
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001442 pr_err("%s: Not the right machine type\n", __func__);
1443 return -ENODEV ;
1444 }
Joonwoo Park0976d012011-12-22 11:48:18 -08001445
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001446 mbhc_cfg.calibration = def_tabla_mbhc_cal();
1447 if (!mbhc_cfg.calibration) {
Joonwoo Park0976d012011-12-22 11:48:18 -08001448 pr_err("Calibration data allocation failed\n");
1449 return -ENOMEM;
1450 }
1451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
1453 if (!msm8960_snd_device) {
1454 pr_err("Platform device allocation failed\n");
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001455 kfree(mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 return -ENOMEM;
1457 }
1458
Kuirong Wangb25838e2012-01-16 23:37:23 -08001459 memcpy(msm8960_dai, msm8960_dai_common, sizeof(msm8960_dai_common));
1460 memcpy(msm8960_dai + ARRAY_SIZE(msm8960_dai_common),
1461 msm8960_dai_delta_tabla2x, sizeof(msm8960_dai_delta_tabla2x));
1462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
1464 ret = platform_device_add(msm8960_snd_device);
1465 if (ret) {
1466 platform_device_put(msm8960_snd_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001467 kfree(mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 return ret;
1469 }
1470
Kuirong Wangb25838e2012-01-16 23:37:23 -08001471 msm8960_snd_tabla1x_device = platform_device_alloc("soc-audio", 1);
1472 if (!msm8960_snd_tabla1x_device) {
1473 pr_err("Platform device allocation failed\n");
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001474 kfree(mbhc_cfg.calibration);
Kuirong Wangb25838e2012-01-16 23:37:23 -08001475 return -ENOMEM;
1476 }
1477
1478 memcpy(msm8960_tabla1x_dai, msm8960_dai_common,
1479 sizeof(msm8960_dai_common));
1480 memcpy(msm8960_tabla1x_dai + ARRAY_SIZE(msm8960_dai_common),
1481 msm8960_dai_delta_tabla1x, sizeof(msm8960_dai_delta_tabla1x));
1482
1483 platform_set_drvdata(msm8960_snd_tabla1x_device,
1484 &snd_soc_tabla1x_card_msm8960);
1485 ret = platform_device_add(msm8960_snd_tabla1x_device);
1486 if (ret) {
1487 platform_device_put(msm8960_snd_tabla1x_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001488 kfree(mbhc_cfg.calibration);
Kuirong Wangb25838e2012-01-16 23:37:23 -08001489 return ret;
1490 }
1491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 if (msm8960_configure_headset_mic_gpios()) {
1493 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1494 msm8960_headset_gpios_configured = 0;
1495 } else
1496 msm8960_headset_gpios_configured = 1;
1497
Joonwoo Park28f49c82012-03-16 12:29:21 -07001498 mutex_init(&cdc_mclk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 return ret;
1500
1501}
1502module_init(msm8960_audio_init);
1503
1504static void __exit msm8960_audio_exit(void)
1505{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301506 if (!cpu_is_msm8960()) {
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001507 pr_err("%s: Not the right machine type\n", __func__);
1508 return ;
1509 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 msm8960_free_headset_mic_gpios();
1511 platform_device_unregister(msm8960_snd_device);
Kuirong Wangb25838e2012-01-16 23:37:23 -08001512 platform_device_unregister(msm8960_snd_tabla1x_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001513 kfree(mbhc_cfg.calibration);
Joonwoo Park28f49c82012-03-16 12:29:21 -07001514 mutex_destroy(&cdc_mclk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515}
1516module_exit(msm8960_audio_exit);
1517
1518MODULE_DESCRIPTION("ALSA SoC MSM8960");
1519MODULE_LICENSE("GPL v2");