blob: f78f58d8b82dce8736359ebfdc1fb508c152be7f [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)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070064
Harmandeep Singh0dd82412011-11-11 09:46:17 -080065static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
66static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067static int msm8960_spk_control;
Kiran Kandi462acea2011-08-31 23:53:14 -070068static int msm8960_ext_bottom_spk_pamp;
69static int msm8960_ext_top_spk_pamp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070static int msm8960_slim_0_rx_ch = 1;
71static int msm8960_slim_0_tx_ch = 1;
72
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070073static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
74static int msm8960_btsco_ch = 1;
75
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076static struct clk *codec_clk;
77static int clk_users;
78
79static int msm8960_headset_gpios_configured;
80
81static struct snd_soc_jack hs_jack;
Bradley Rubincb1e2732011-06-23 16:49:20 -070082static struct snd_soc_jack button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083
Joonwoo Park9115ade2012-04-18 13:14:10 -070084static bool hs_detect_use_gpio;
85module_param(hs_detect_use_gpio, bool, 0444);
86MODULE_PARM_DESC(hs_detect_use_gpio, "Use GPIO for headset detection");
87
88static bool hs_detect_use_firmware;
89module_param(hs_detect_use_firmware, bool, 0444);
90MODULE_PARM_DESC(hs_detect_use_firmware, "Use firmware for headset detection");
91
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070092static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
93 bool dapm);
94
95static struct tabla_mbhc_config mbhc_cfg = {
96 .headset_jack = &hs_jack,
97 .button_jack = &button_jack,
98 .read_fw_bin = false,
99 .calibration = NULL,
100 .micbias = TABLA_MICBIAS2,
101 .mclk_cb_fn = msm8960_enable_codec_ext_clk,
102 .mclk_rate = TABLA_EXT_CLK_RATE,
103 .gpio = 0,
104 .gpio_irq = 0,
105 .gpio_level_insert = 1,
106};
Joonwoo Park0976d012011-12-22 11:48:18 -0800107
Joonwoo Park28f49c82012-03-16 12:29:21 -0700108static struct mutex cdc_mclk_mutex;
109
Kiran Kandi462acea2011-08-31 23:53:14 -0700110static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111{
112 int ret = 0;
113
114 struct pm_gpio param = {
115 .direction = PM_GPIO_DIR_OUT,
116 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
117 .output_value = 1,
118 .pull = PM_GPIO_PULL_NO,
119 .vin_sel = PM_GPIO_VIN_S4,
120 .out_strength = PM_GPIO_STRENGTH_MED,
Kiran Kandi462acea2011-08-31 23:53:14 -0700121 .
122 function = PM_GPIO_FUNC_NORMAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 };
124
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800125 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800127 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
Kiran Kandi462acea2011-08-31 23:53:14 -0700128 if (ret) {
129 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800130 __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700131 return;
132 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800133 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
Kiran Kandi462acea2011-08-31 23:53:14 -0700134 if (ret)
135 pr_err("%s: Failed to configure Bottom Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800136 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700137 else {
138 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800139 gpio_direction_output(bottom_spk_pamp_gpio, 1);
Kiran Kandi462acea2011-08-31 23:53:14 -0700140 }
141
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800142 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700143
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800144 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700145 if (ret) {
146 pr_err("%s: Error requesting GPIO %d\n", __func__,
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800147 top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700148 return;
149 }
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800150 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700151 if (ret)
Kiran Kandi462acea2011-08-31 23:53:14 -0700152 pr_err("%s: Failed to configure Top Spk Ampl"
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800153 " gpio %u\n", __func__, top_spk_pamp_gpio);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700154 else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700155 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800156 gpio_direction_output(top_spk_pamp_gpio, 1);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700157 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700158 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700159 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
160 " gpio = %u\n", __func__, spk_amp_gpio);
161 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700164
Kiran Kandi462acea2011-08-31 23:53:14 -0700165static void msm8960_ext_spk_power_amp_on(u32 spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166{
Kiran Kandi462acea2011-08-31 23:53:14 -0700167 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
168
169 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
170 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
171
172 pr_debug("%s() External Bottom Speaker Ampl already "
173 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700174 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700175 }
176
177 msm8960_ext_bottom_spk_pamp |= spk;
178
179 if ((msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
180 (msm8960_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
181
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800182 msm8960_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700183 pr_debug("%s: slepping 4 ms after turning on external "
184 " Bottom Speaker Ampl\n", __func__);
185 usleep_range(4000, 4000);
186 }
187
188 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
189
190 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
191 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
192
193 pr_debug("%s() External Top Speaker Ampl already"
194 "turned on. spk = 0x%08x\n", __func__, spk);
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700195 return;
Kiran Kandi462acea2011-08-31 23:53:14 -0700196 }
197
198 msm8960_ext_top_spk_pamp |= spk;
199
200 if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
201 (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
202
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800203 msm8960_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700204 pr_debug("%s: sleeping 4 ms after turning on "
205 " external Top Speaker Ampl\n", __func__);
206 usleep_range(4000, 4000);
207 }
208 } else {
209
210 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
211 __func__, spk);
212 return;
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700213 }
Kiran Kandi462acea2011-08-31 23:53:14 -0700214}
215
216static void msm8960_ext_spk_power_amp_off(u32 spk)
217{
218 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
219
220 if (!msm8960_ext_bottom_spk_pamp)
221 return;
222
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800223 gpio_direction_output(bottom_spk_pamp_gpio, 0);
224 gpio_free(bottom_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700225 msm8960_ext_bottom_spk_pamp = 0;
226
227 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
228 " Speaker Ampl\n", __func__);
229
230 usleep_range(4000, 4000);
231
232 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
233
234 if (!msm8960_ext_top_spk_pamp)
235 return;
236
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800237 gpio_direction_output(top_spk_pamp_gpio, 0);
238 gpio_free(top_spk_pamp_gpio);
Kiran Kandi462acea2011-08-31 23:53:14 -0700239 msm8960_ext_top_spk_pamp = 0;
240
241 pr_debug("%s: sleeping 4 ms after turning off external Top"
242 " Spkaker Ampl\n", __func__);
243
244 usleep_range(4000, 4000);
245 } else {
246
247 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
248 __func__, spk);
249 return;
250 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253static void msm8960_ext_control(struct snd_soc_codec *codec)
254{
255 struct snd_soc_dapm_context *dapm = &codec->dapm;
256
Jayasena Sangaraboina247d36e2012-04-17 10:16:18 -0700257 mutex_lock(&dapm->codec->mutex);
258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700260 if (msm8960_spk_control == MSM8960_SPK_ON) {
261 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
262 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
263 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
264 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
265 } else {
266 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
267 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
268 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
269 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
270 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271
272 snd_soc_dapm_sync(dapm);
Jayasena Sangaraboina247d36e2012-04-17 10:16:18 -0700273 mutex_unlock(&dapm->codec->mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274}
275
276static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_value *ucontrol)
278{
279 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
280 ucontrol->value.integer.value[0] = msm8960_spk_control;
281 return 0;
282}
283static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
284 struct snd_ctl_elem_value *ucontrol)
285{
286 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
287
288 pr_debug("%s()\n", __func__);
289 if (msm8960_spk_control == ucontrol->value.integer.value[0])
290 return 0;
291
292 msm8960_spk_control = ucontrol->value.integer.value[0];
293 msm8960_ext_control(codec);
294 return 1;
295}
296static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
297 struct snd_kcontrol *k, int event)
298{
299 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700300
301 if (SND_SOC_DAPM_EVENT_ON(event)) {
Kiran Kandi462acea2011-08-31 23:53:14 -0700302 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
303 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
304 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
305 msm8960_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
306 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
307 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
308 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
309 msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
310 else {
311 pr_err("%s() Invalid Speaker Widget = %s\n",
312 __func__, w->name);
313 return -EINVAL;
314 }
315
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700316 } else {
Kiran Kandi462acea2011-08-31 23:53:14 -0700317 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
318 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
319 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
320 msm8960_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
321 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
322 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
323 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
324 msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
325 else {
326 pr_err("%s() Invalid Speaker Widget = %s\n",
327 __func__, w->name);
328 return -EINVAL;
329 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700330 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 return 0;
332}
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700333
334static int msm8960_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
335 bool dapm)
Joonwoo Park0976d012011-12-22 11:48:18 -0800336{
Joonwoo Park28f49c82012-03-16 12:29:21 -0700337 int r = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -0800338 pr_debug("%s: enable = %d\n", __func__, enable);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700339
340 mutex_lock(&cdc_mclk_mutex);
Joonwoo Park0976d012011-12-22 11:48:18 -0800341 if (enable) {
342 clk_users++;
343 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700344 if (clk_users == 1) {
345 if (codec_clk) {
346 clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530347 clk_prepare_enable(codec_clk);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700348 tabla_mclk_enable(codec, 1, dapm);
349 } else {
350 pr_err("%s: Error setting Tabla MCLK\n",
351 __func__);
352 clk_users--;
353 r = -EINVAL;
354 }
Joonwoo Park0976d012011-12-22 11:48:18 -0800355 }
356 } else {
Joonwoo Park28f49c82012-03-16 12:29:21 -0700357 if (clk_users > 0) {
358 clk_users--;
359 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
360 if (clk_users == 0) {
361 pr_debug("%s: disabling MCLK. clk_users = %d\n",
Joonwoo Park0976d012011-12-22 11:48:18 -0800362 __func__, clk_users);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700363 tabla_mclk_enable(codec, 0, dapm);
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530364 clk_disable_unprepare(codec_clk);
Joonwoo Park28f49c82012-03-16 12:29:21 -0700365 }
366 } else {
367 pr_err("%s: Error releasing Tabla MCLK\n", __func__);
368 r = -EINVAL;
Joonwoo Park0976d012011-12-22 11:48:18 -0800369 }
370 }
Joonwoo Park28f49c82012-03-16 12:29:21 -0700371 mutex_unlock(&cdc_mclk_mutex);
372 return r;
Joonwoo Park0976d012011-12-22 11:48:18 -0800373}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700375static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
376 struct snd_kcontrol *kcontrol, int event)
377{
378 pr_debug("%s: event = %d\n", __func__, event);
379
380 switch (event) {
381 case SND_SOC_DAPM_PRE_PMU:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700382 return msm8960_enable_codec_ext_clk(w->codec, 1, true);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700383 case SND_SOC_DAPM_POST_PMD:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700384 return msm8960_enable_codec_ext_clk(w->codec, 0, true);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700385 }
386 return 0;
387}
388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700390
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700391 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
392 msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
393
Kiran Kandi462acea2011-08-31 23:53:14 -0700394 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm8960_spkramp_event),
395 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm8960_spkramp_event),
396
397 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
398 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 SND_SOC_DAPM_MIC("Handset Mic", NULL),
401 SND_SOC_DAPM_MIC("Headset Mic", NULL),
402 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700403 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
404 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700405
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700406 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700407 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700408 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700409 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700410 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
411 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413};
414
Bradley Rubin229c6a52011-07-12 16:18:48 -0700415static const struct snd_soc_dapm_route common_audio_map[] = {
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700416
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700417 {"RX_BIAS", NULL, "MCLK"},
418 {"LDO_H", NULL, "MCLK"},
419
420 /* Speaker path */
Kiran Kandi462acea2011-08-31 23:53:14 -0700421 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
422 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700423
Kiran Kandi462acea2011-08-31 23:53:14 -0700424 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
425 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
427 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700428 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
429 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700430
431 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700433
Patrick Laie519dd62011-09-28 12:37:11 -0700434 /**
435 * AMIC3 and AMIC4 inputs are connected to ANC microphones
436 * These mics are biased differently on CDP and FLUID
437 * routing entries below are based on bias arrangement
438 * on FLUID.
439 */
440 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
441 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
442
443 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
444 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
445
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700446 {"HEADPHONE", NULL, "LDO_H"},
447
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700448 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700449 * The digital Mic routes are setup considering
450 * fluid as default device.
451 */
452
453 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700454 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700455 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700456 * Conncted to DMIC2 Input on Tabla codec.
457 */
458 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700459 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700460
461 /**
462 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700463 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700464 * Conncted to DMIC1 Input on Tabla codec.
465 */
466 {"DMIC1", NULL, "MIC BIAS1 External"},
467 {"MIC BIAS1 External", NULL, "Digital Mic2"},
468
469 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700470 * Digital Mic3. Back Bottom Digital Mic on Fluid.
471 * Digital Mic GM1 on CDP mainboard.
472 * Conncted to DMIC4 Input on Tabla codec.
473 */
474 {"DMIC4", NULL, "MIC BIAS3 External"},
475 {"MIC BIAS3 External", NULL, "Digital Mic3"},
476
477 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700478 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700479 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700480 * Conncted to DMIC3 Input on Tabla codec.
481 */
482 {"DMIC3", NULL, "MIC BIAS3 External"},
483 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700484
485 /**
486 * Digital Mic5. Front top Digital Mic on Fluid.
487 * Digital Mic GM3 on CDP mainboard.
488 * Conncted to DMIC5 Input on Tabla codec.
489 */
490 {"DMIC5", NULL, "MIC BIAS4 External"},
491 {"MIC BIAS4 External", NULL, "Digital Mic5"},
492
Patrick Laicb7802b2011-10-04 12:39:18 -0700493 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
494 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700495 */
496 {"DMIC6", NULL, "MIC BIAS4 External"},
497 {"MIC BIAS4 External", NULL, "Digital Mic6"},
Bradley Rubin229c6a52011-07-12 16:18:48 -0700498};
499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700501static const char *slim0_rx_ch_text[] = {"One", "Two"};
502static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504static const struct soc_enum msm8960_enum[] = {
505 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700506 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
507 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508};
509
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700510static const char *btsco_rate_text[] = {"8000", "16000"};
511static const struct soc_enum msm8960_btsco_enum[] = {
512 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
513};
514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
516 struct snd_ctl_elem_value *ucontrol)
517{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700518 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800519 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700520 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 return 0;
522}
523
524static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
525 struct snd_ctl_elem_value *ucontrol)
526{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700527 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528
Patrick Lai9f4b4292011-07-16 22:11:09 -0700529 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800530 msm8960_slim_0_rx_ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 return 1;
532}
533
534static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
535 struct snd_ctl_elem_value *ucontrol)
536{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700537 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800538 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700539 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540 return 0;
541}
542
543static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
545{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700546 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547
548 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -0800549 msm8960_slim_0_tx_ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 return 1;
551}
552
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700553static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
554 struct snd_ctl_elem_value *ucontrol)
555{
Joonwoo Park0976d012011-12-22 11:48:18 -0800556 pr_debug("%s: msm8960_btsco_rate = %d", __func__, msm8960_btsco_rate);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700557 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
558 return 0;
559}
560
561static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
563{
564 switch (ucontrol->value.integer.value[0]) {
565 case 0:
566 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
567 break;
568 case 1:
569 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
570 break;
571 default:
572 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
573 break;
574 }
Joonwoo Park0976d012011-12-22 11:48:18 -0800575 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700576 return 0;
577}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578
579static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
580 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
581 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700582 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
583 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
584 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
585 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586};
587
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700588static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
589 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
590 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
591};
592
593static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
594{
595 int err = 0;
596 struct snd_soc_platform *platform = rtd->platform;
597
598 err = snd_soc_add_platform_controls(platform,
599 int_btsco_rate_mixer_controls,
600 ARRAY_SIZE(int_btsco_rate_mixer_controls));
601 if (err < 0)
602 return err;
603 return 0;
604}
605
Joonwoo Park0976d012011-12-22 11:48:18 -0800606static void *def_tabla_mbhc_cal(void)
607{
608 void *tabla_cal;
609 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
610 u16 *btn_low, *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -0800611 u8 *n_ready, *n_cic, *gain;
Joonwoo Park0976d012011-12-22 11:48:18 -0800612
613 tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
614 TABLA_MBHC_DEF_RLOADS),
615 GFP_KERNEL);
616 if (!tabla_cal) {
617 pr_err("%s: out of memory\n", __func__);
618 return NULL;
619 }
620
621#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
622 S(t_ldoh, 100);
623 S(t_bg_fast_settle, 100);
624 S(t_shutdown_plug_rem, 255);
625 S(mbhc_nsa, 4);
626 S(mbhc_navg, 4);
627#undef S
628#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
629 S(mic_current, TABLA_PID_MIC_5_UA);
630 S(hph_current, TABLA_PID_MIC_5_UA);
631 S(t_mic_pid, 100);
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800632 S(t_ins_complete, 250);
Joonwoo Park0976d012011-12-22 11:48:18 -0800633 S(t_ins_retry, 200);
634#undef S
635#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
636 S(v_no_mic, 30);
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700637 S(v_hs_max, 2400);
Joonwoo Park0976d012011-12-22 11:48:18 -0800638#undef S
639#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800640 S(c[0], 62);
641 S(c[1], 124);
642 S(nc, 1);
643 S(n_meas, 3);
Joonwoo Park0976d012011-12-22 11:48:18 -0800644 S(mbhc_nsc, 11);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800645 S(n_btn_meas, 1);
646 S(n_btn_con, 2);
Joonwoo Park0976d012011-12-22 11:48:18 -0800647 S(num_btn, TABLA_MBHC_DEF_BUTTONS);
648 S(v_btn_press_delta_sta, 100);
649 S(v_btn_press_delta_cic, 50);
650#undef S
651 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
652 btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
653 btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800654 btn_low[0] = -50;
Joonwoo Parkfee17432012-04-16 16:33:55 -0700655 btn_high[0] = 20;
656 btn_low[1] = 21;
657 btn_high[1] = 62;
658 btn_low[2] = 63;
659 btn_high[2] = 104;
660 btn_low[3] = 105;
661 btn_high[3] = 143;
662 btn_low[4] = 144;
663 btn_high[4] = 181;
664 btn_low[5] = 182;
665 btn_high[5] = 218;
666 btn_low[6] = 219;
667 btn_high[6] = 254;
668 btn_low[7] = 255;
669 btn_high[7] = 330;
Joonwoo Parkc0672392012-01-11 11:03:14 -0800670 n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700671 n_ready[0] = 80;
672 n_ready[1] = 68;
Joonwoo Park0976d012011-12-22 11:48:18 -0800673 n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800674 n_cic[0] = 60;
675 n_cic[1] = 47;
Joonwoo Park0976d012011-12-22 11:48:18 -0800676 gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
677 gain[0] = 11;
678 gain[1] = 9;
679
680 return tabla_cal;
681}
682
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800683static int msm8960_hw_params(struct snd_pcm_substream *substream,
684 struct snd_pcm_hw_params *params)
685{
686 struct snd_soc_pcm_runtime *rtd = substream->private_data;
687 struct snd_soc_dai *codec_dai = rtd->codec_dai;
688 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
689 int ret = 0;
690 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
691 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700692 unsigned int user_set_tx_ch = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800693
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700694
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800695 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700696
697 pr_debug("%s: rx_0_ch=%d\n", __func__, msm8960_slim_0_rx_ch);
698
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800699 ret = snd_soc_dai_get_channel_map(codec_dai,
700 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
701 if (ret < 0) {
702 pr_err("%s: failed to get codec chan map\n", __func__);
703 goto end;
704 }
705
706 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
707 msm8960_slim_0_rx_ch, rx_ch);
708 if (ret < 0) {
709 pr_err("%s: failed to set cpu chan map\n", __func__);
710 goto end;
711 }
712 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
713 msm8960_slim_0_rx_ch, rx_ch);
714 if (ret < 0) {
715 pr_err("%s: failed to set codec channel map\n",
716 __func__);
717 goto end;
718 }
719 } else {
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700720
721 if (codec_dai->id == 2)
722 user_set_tx_ch = msm8960_slim_0_tx_ch;
723 else if (codec_dai->id == 4)
724 user_set_tx_ch = params_channels(params);
725
726 pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
727 codec_dai->name, codec_dai->id, user_set_tx_ch);
728
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800729 ret = snd_soc_dai_get_channel_map(codec_dai,
730 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
731 if (ret < 0) {
732 pr_err("%s: failed to get codec chan map\n", __func__);
733 goto end;
734 }
735 ret = snd_soc_dai_set_channel_map(cpu_dai,
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700736 user_set_tx_ch, tx_ch, 0 , 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800737 if (ret < 0) {
738 pr_err("%s: failed to set cpu chan map\n", __func__);
739 goto end;
740 }
741 ret = snd_soc_dai_set_channel_map(codec_dai,
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700742 user_set_tx_ch, tx_ch, 0, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800743 if (ret < 0) {
744 pr_err("%s: failed to set codec channel map\n",
745 __func__);
746 goto end;
747 }
748
749
750 }
751end:
752 return ret;
753}
754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700755static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
756{
757 int err;
758 struct snd_soc_codec *codec = rtd->codec;
759 struct snd_soc_dapm_context *dapm = &codec->dapm;
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800760 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700761 struct pm_gpio jack_gpio_cfg = {
762 .direction = PM_GPIO_DIR_IN,
763 .pull = PM_GPIO_PULL_UP_1P5,
764 .function = PM_GPIO_FUNC_NORMAL,
765 .vin_sel = 2,
766 .inv_int_pol = 0,
767 };
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800769 pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770
Harmandeep Singh0dd82412011-11-11 09:46:17 -0800771 if (machine_is_msm8960_liquid()) {
772 top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
773 bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
774 }
775
Kiran Kandi28ef14e2011-09-16 15:45:47 -0700776 rtd->pmdown_time = 0;
777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
779 ARRAY_SIZE(tabla_msm8960_controls));
780 if (err < 0)
781 return err;
782
783 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
784 ARRAY_SIZE(msm8960_dapm_widgets));
785
Bradley Rubin229c6a52011-07-12 16:18:48 -0700786 snd_soc_dapm_add_routes(dapm, common_audio_map,
787 ARRAY_SIZE(common_audio_map));
788
Peter Lohmannb8203ef2011-10-07 15:05:28 -0700789 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
790 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
791 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
792 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793
794 snd_soc_dapm_sync(dapm);
795
796 err = snd_soc_jack_new(codec, "Headset Jack",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800797 (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
798 SND_JACK_OC_HPHR),
799 &hs_jack);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 if (err) {
801 pr_err("failed to create new jack\n");
802 return err;
803 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700804
805 err = snd_soc_jack_new(codec, "Button Jack",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800806 TABLA_JACK_BUTTON_MASK, &button_jack);
Bradley Rubincb1e2732011-06-23 16:49:20 -0700807 if (err) {
808 pr_err("failed to create new jack\n");
809 return err;
810 }
811
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800812 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
813
Joonwoo Park9115ade2012-04-18 13:14:10 -0700814 if (hs_detect_use_gpio) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700815 mbhc_cfg.gpio = PM8921_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
816 mbhc_cfg.gpio_irq = JACK_DETECT_INT;
817 }
818
819 if (mbhc_cfg.gpio) {
820 err = pm8xxx_gpio_config(mbhc_cfg.gpio, &jack_gpio_cfg);
821 if (err) {
822 pr_err("%s: pm8xxx_gpio_config failed %d\n", __func__,
823 err);
824 return err;
825 }
826 }
Joonwoo Park9115ade2012-04-18 13:14:10 -0700827
828 mbhc_cfg.read_fw_bin = hs_detect_use_firmware;
829
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700830 err = tabla_hs_detect(codec, &mbhc_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831
Joonwoo Park03324832012-03-19 19:36:16 -0700832 return err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833}
834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700836 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837 .trigger = {
838 SND_SOC_DSP_TRIGGER_POST,
839 SND_SOC_DSP_TRIGGER_POST
840 },
841};
842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700844 .playback = true,
845 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846 .trigger = {
847 SND_SOC_DSP_TRIGGER_POST,
848 SND_SOC_DSP_TRIGGER_POST
849 },
850};
851
Patrick Lai9b56e1d2012-01-22 22:14:15 -0800852/* bi-directional media definition for hostless PCM device */
853static struct snd_soc_dsp_link bidir_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700854 .playback = true,
855 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 .trigger = {
857 SND_SOC_DSP_TRIGGER_POST,
858 SND_SOC_DSP_TRIGGER_POST
859 },
860};
861
Alex Wongb3d06a02012-01-12 10:00:41 -0800862static struct snd_soc_dsp_link hdmi_rx_hl = {
863 .playback = true,
864 .trigger = {
865 SND_SOC_DSP_TRIGGER_POST,
866 SND_SOC_DSP_TRIGGER_POST
867 },
868};
869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
871 struct snd_pcm_hw_params *params)
872{
873 struct snd_interval *rate = hw_param_interval(params,
874 SNDRV_PCM_HW_PARAM_RATE);
875
876 struct snd_interval *channels = hw_param_interval(params,
877 SNDRV_PCM_HW_PARAM_CHANNELS);
878
879 pr_debug("%s()\n", __func__);
880 rate->min = rate->max = 48000;
881 channels->min = channels->max = msm8960_slim_0_rx_ch;
882
883 return 0;
884}
885
886static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
887 struct snd_pcm_hw_params *params)
888{
889 struct snd_interval *rate = hw_param_interval(params,
890 SNDRV_PCM_HW_PARAM_RATE);
891
892 struct snd_interval *channels = hw_param_interval(params,
893 SNDRV_PCM_HW_PARAM_CHANNELS);
894
895 pr_debug("%s()\n", __func__);
896 rate->min = rate->max = 48000;
897 channels->min = channels->max = msm8960_slim_0_tx_ch;
898
899 return 0;
900}
901
902static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
903 struct snd_pcm_hw_params *params)
904{
905 struct snd_interval *rate = hw_param_interval(params,
906 SNDRV_PCM_HW_PARAM_RATE);
907
908 pr_debug("%s()\n", __func__);
909 rate->min = rate->max = 48000;
910
911 return 0;
912}
913
Helen Zeng73f7fc62011-11-18 16:29:59 -0800914static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
915 struct snd_pcm_hw_params *params)
916{
917 struct snd_interval *rate = hw_param_interval(params,
918 SNDRV_PCM_HW_PARAM_RATE);
919
920 struct snd_interval *channels = hw_param_interval(params,
921 SNDRV_PCM_HW_PARAM_CHANNELS);
922
Kiran Kandi5e809b02012-01-31 00:24:33 -0800923 pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
924 channels->min, channels->max);
925
Helen Zeng73f7fc62011-11-18 16:29:59 -0800926 rate->min = rate->max = 48000;
Helen Zeng73f7fc62011-11-18 16:29:59 -0800927
928 return 0;
929}
930
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700931static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
932 struct snd_pcm_hw_params *params)
933{
934 struct snd_interval *rate = hw_param_interval(params,
935 SNDRV_PCM_HW_PARAM_RATE);
936
937 struct snd_interval *channels = hw_param_interval(params,
938 SNDRV_PCM_HW_PARAM_CHANNELS);
939
940 rate->min = rate->max = msm8960_btsco_rate;
941 channels->min = channels->max = msm8960_btsco_ch;
942
943 return 0;
944}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700945static int msm8960_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
946 struct snd_pcm_hw_params *params)
947{
948 struct snd_interval *rate = hw_param_interval(params,
949 SNDRV_PCM_HW_PARAM_RATE);
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700950
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700951 struct snd_interval *channels = hw_param_interval(params,
952 SNDRV_PCM_HW_PARAM_CHANNELS);
953
954 /* PCM only supports mono output with 8khz sample rate */
955 rate->min = rate->max = 8000;
956 channels->min = channels->max = 1;
957
958 return 0;
959}
960static int msm8960_aux_pcm_get_gpios(void)
961{
962 int ret = 0;
963
964 pr_debug("%s\n", __func__);
965
966 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
967 if (ret < 0) {
968 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
969 __func__, GPIO_AUX_PCM_DOUT);
970 goto fail_dout;
971 }
972
973 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
974 if (ret < 0) {
975 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
976 __func__, GPIO_AUX_PCM_DIN);
977 goto fail_din;
978 }
979
980 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
981 if (ret < 0) {
982 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
983 __func__, GPIO_AUX_PCM_SYNC);
984 goto fail_sync;
985 }
986 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
987 if (ret < 0) {
988 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
989 __func__, GPIO_AUX_PCM_CLK);
990 goto fail_clk;
991 }
992
993 return 0;
994
995fail_clk:
996 gpio_free(GPIO_AUX_PCM_SYNC);
997fail_sync:
998 gpio_free(GPIO_AUX_PCM_DIN);
999fail_din:
1000 gpio_free(GPIO_AUX_PCM_DOUT);
1001fail_dout:
1002
1003 return ret;
1004}
1005
1006static int msm8960_aux_pcm_free_gpios(void)
1007{
1008 gpio_free(GPIO_AUX_PCM_DIN);
1009 gpio_free(GPIO_AUX_PCM_DOUT);
1010 gpio_free(GPIO_AUX_PCM_SYNC);
1011 gpio_free(GPIO_AUX_PCM_CLK);
1012
1013 return 0;
1014}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015static int msm8960_startup(struct snd_pcm_substream *substream)
1016{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001017 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1018 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 return 0;
1020}
1021
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001022static int msm8960_auxpcm_startup(struct snd_pcm_substream *substream)
1023{
1024 int ret = 0;
1025
1026 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1027 ret = msm8960_aux_pcm_get_gpios();
1028 if (ret < 0) {
1029 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
1030 return -EINVAL;
1031 }
1032 return 0;
1033}
1034
1035static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
1036{
1037
1038 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1039 msm8960_aux_pcm_free_gpios();
1040}
1041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042static void msm8960_shutdown(struct snd_pcm_substream *substream)
1043{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001044 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1045 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046}
1047
1048static struct snd_soc_ops msm8960_be_ops = {
1049 .startup = msm8960_startup,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001050 .hw_params = msm8960_hw_params,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 .shutdown = msm8960_shutdown,
1052};
1053
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001054static struct snd_soc_ops msm8960_auxpcm_be_ops = {
1055 .startup = msm8960_auxpcm_startup,
1056 .shutdown = msm8960_auxpcm_shutdown,
1057};
1058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059/* Digital audio interface glue - connects codec <---> CPU */
Kuirong Wangb25838e2012-01-16 23:37:23 -08001060static struct snd_soc_dai_link msm8960_dai_common[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 /* FrontEnd DAI Links */
1062 {
1063 .name = "MSM8960 Media1",
1064 .stream_name = "MultiMedia1",
1065 .cpu_dai_name = "MultiMedia1",
1066 .platform_name = "msm-pcm-dsp",
1067 .dynamic = 1,
1068 .dsp_link = &fe_media,
1069 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
1070 },
1071 {
1072 .name = "MSM8960 Media2",
1073 .stream_name = "MultiMedia2",
1074 .cpu_dai_name = "MultiMedia2",
Kiran Kandi5e809b02012-01-31 00:24:33 -08001075 .platform_name = "msm-multi-ch-pcm-dsp",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 .dynamic = 1,
1077 .dsp_link = &fe_media,
1078 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
1079 },
1080 {
1081 .name = "Circuit-Switch Voice",
1082 .stream_name = "CS-Voice",
1083 .cpu_dai_name = "CS-VOICE",
1084 .platform_name = "msm-pcm-voice",
1085 .dynamic = 1,
1086 .dsp_link = &fe_media,
1087 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
1088 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -07001089 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 },
1091 {
1092 .name = "MSM VoIP",
1093 .stream_name = "VoIP",
1094 .cpu_dai_name = "VoIP",
1095 .platform_name = "msm-voip-dsp",
1096 .dynamic = 1,
1097 .dsp_link = &fe_media,
1098 .be_id = MSM_FRONTEND_DAI_VOIP,
1099 },
1100 {
1101 .name = "MSM8960 LPA",
1102 .stream_name = "LPA",
1103 .cpu_dai_name = "MultiMedia3",
1104 .platform_name = "msm-pcm-lpa",
1105 .dynamic = 1,
1106 .dsp_link = &lpa_fe_media,
1107 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
1108 },
1109 /* Hostless PMC purpose */
1110 {
1111 .name = "SLIMBUS_0 Hostless",
1112 .stream_name = "SLIMBUS_0 Hostless",
1113 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
1114 .platform_name = "msm-pcm-hostless",
1115 .dynamic = 1,
Patrick Lai9b56e1d2012-01-22 22:14:15 -08001116 .dsp_link = &bidir_hl_media,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -07001118 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 /* .be_id = do not care */
1120 },
1121 {
1122 .name = "INT_FM Hostless",
1123 .stream_name = "INT_FM Hostless",
1124 .cpu_dai_name = "INT_FM_HOSTLESS",
1125 .platform_name = "msm-pcm-hostless",
1126 .dynamic = 1,
Patrick Lai9b56e1d2012-01-22 22:14:15 -08001127 .dsp_link = &bidir_hl_media,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
Alex Wongb9367922011-09-21 23:09:43 -07001129 .ignore_suspend = 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 /* .be_id = do not care */
1131 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301132 {
1133 .name = "MSM AFE-PCM RX",
1134 .stream_name = "AFE-PROXY RX",
1135 .cpu_dai_name = "msm-dai-q6.241",
1136 .codec_name = "msm-stub-codec.1",
1137 .codec_dai_name = "msm-stub-rx",
1138 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -07001139 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301140 },
1141 {
1142 .name = "MSM AFE-PCM TX",
1143 .stream_name = "AFE-PROXY TX",
1144 .cpu_dai_name = "msm-dai-q6.240",
1145 .codec_name = "msm-stub-codec.1",
1146 .codec_dai_name = "msm-stub-tx",
1147 .platform_name = "msm-pcm-afe",
Alex Wongb9367922011-09-21 23:09:43 -07001148 .ignore_suspend = 1,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301149 },
Asish Bhattacharya09f9e0a2011-11-11 13:22:47 +05301150 {
1151 .name = "MSM8960 Compr",
1152 .stream_name = "COMPR",
1153 .cpu_dai_name = "MultiMedia4",
1154 .platform_name = "msm-compr-dsp",
1155 .dynamic = 1,
1156 .dsp_link = &lpa_fe_media,
1157 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
1158 },
Patrick Lai9b56e1d2012-01-22 22:14:15 -08001159 {
1160 .name = "AUXPCM Hostless",
1161 .stream_name = "AUXPCM Hostless",
1162 .cpu_dai_name = "AUXPCM_HOSTLESS",
1163 .platform_name = "msm-pcm-hostless",
1164 .dynamic = 1,
1165 .dsp_link = &bidir_hl_media,
1166 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1167 .ignore_suspend = 1,
1168 },
Alex Wongb3d06a02012-01-12 10:00:41 -08001169 /* HDMI Hostless */
1170 {
1171 .name = "HDMI_RX_HOSTLESS",
1172 .stream_name = "HDMI_RX_HOSTLESS",
1173 .cpu_dai_name = "HDMI_HOSTLESS",
1174 .platform_name = "msm-pcm-hostless",
1175 .dynamic = 1,
1176 .dsp_link = &hdmi_rx_hl,
1177 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1178 .no_codec = 1,
1179 .ignore_suspend = 1,
1180 },
Venkat Sudhir1c79c3b2012-04-09 23:42:28 -07001181 {
1182 .name = "VoLTE",
1183 .stream_name = "VoLTE",
1184 .cpu_dai_name = "VoLTE",
1185 .platform_name = "msm-pcm-voice",
1186 .dynamic = 1,
1187 .dsp_link = &fe_media,
1188 .be_id = MSM_FRONTEND_DAI_VOLTE,
1189 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1190 .ignore_suspend = 1,
1191 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 /* Backend BT/FM DAI Links */
1193 {
1194 .name = LPASS_BE_INT_BT_SCO_RX,
1195 .stream_name = "Internal BT-SCO Playback",
1196 .cpu_dai_name = "msm-dai-q6.12288",
1197 .platform_name = "msm-pcm-routing",
1198 .codec_name = "msm-stub-codec.1",
1199 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -07001200 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 .no_pcm = 1,
1202 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -07001203 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 },
1205 {
1206 .name = LPASS_BE_INT_BT_SCO_TX,
1207 .stream_name = "Internal BT-SCO Capture",
1208 .cpu_dai_name = "msm-dai-q6.12289",
1209 .platform_name = "msm-pcm-routing",
1210 .codec_name = "msm-stub-codec.1",
1211 .codec_dai_name = "msm-stub-tx",
1212 .no_pcm = 1,
1213 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -07001214 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 },
1216 {
1217 .name = LPASS_BE_INT_FM_RX,
1218 .stream_name = "Internal FM Playback",
1219 .cpu_dai_name = "msm-dai-q6.12292",
1220 .platform_name = "msm-pcm-routing",
1221 .codec_name = "msm-stub-codec.1",
1222 .codec_dai_name = "msm-stub-rx",
1223 .no_pcm = 1,
1224 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
1225 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1226 },
1227 {
1228 .name = LPASS_BE_INT_FM_TX,
1229 .stream_name = "Internal FM Capture",
1230 .cpu_dai_name = "msm-dai-q6.12293",
1231 .platform_name = "msm-pcm-routing",
1232 .codec_name = "msm-stub-codec.1",
1233 .codec_dai_name = "msm-stub-tx",
1234 .no_pcm = 1,
1235 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
1236 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1237 },
1238 /* HDMI BACK END DAI Link */
1239 {
1240 .name = LPASS_BE_HDMI,
1241 .stream_name = "HDMI Playback",
Kiran Kandi5e809b02012-01-31 00:24:33 -08001242 .cpu_dai_name = "msm-dai-q6-hdmi.8",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 .platform_name = "msm-pcm-routing",
1244 .codec_name = "msm-stub-codec.1",
1245 .codec_dai_name = "msm-stub-rx",
1246 .no_pcm = 1,
1247 .no_codec = 1,
1248 .be_id = MSM_BACKEND_DAI_HDMI_RX,
Helen Zeng73f7fc62011-11-18 16:29:59 -08001249 .be_hw_params_fixup = msm8960_hdmi_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301251 /* Backend AFE DAI Links */
1252 {
1253 .name = LPASS_BE_AFE_PCM_RX,
1254 .stream_name = "AFE Playback",
1255 .cpu_dai_name = "msm-dai-q6.224",
1256 .platform_name = "msm-pcm-routing",
1257 .codec_name = "msm-stub-codec.1",
1258 .codec_dai_name = "msm-stub-rx",
1259 .no_codec = 1,
1260 .no_pcm = 1,
1261 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1262 },
1263 {
1264 .name = LPASS_BE_AFE_PCM_TX,
1265 .stream_name = "AFE Capture",
1266 .cpu_dai_name = "msm-dai-q6.225",
1267 .platform_name = "msm-pcm-routing",
1268 .codec_name = "msm-stub-codec.1",
1269 .codec_dai_name = "msm-stub-tx",
1270 .no_codec = 1,
1271 .no_pcm = 1,
1272 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1273 },
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001274 /* AUX PCM Backend DAI Links */
1275 {
1276 .name = LPASS_BE_AUXPCM_RX,
1277 .stream_name = "AUX PCM Playback",
1278 .cpu_dai_name = "msm-dai-q6.2",
1279 .platform_name = "msm-pcm-routing",
1280 .codec_name = "msm-stub-codec.1",
1281 .codec_dai_name = "msm-stub-rx",
1282 .no_pcm = 1,
1283 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1284 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1285 .ops = &msm8960_auxpcm_be_ops,
1286 },
1287 {
1288 .name = LPASS_BE_AUXPCM_TX,
1289 .stream_name = "AUX PCM Capture",
1290 .cpu_dai_name = "msm-dai-q6.3",
1291 .platform_name = "msm-pcm-routing",
1292 .codec_name = "msm-stub-codec.1",
1293 .codec_dai_name = "msm-stub-tx",
1294 .no_pcm = 1,
1295 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1296 .be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
1297 },
Helen Zeng0705a5f2011-10-14 15:29:52 -07001298 /* Incall Music BACK END DAI Link */
1299 {
1300 .name = LPASS_BE_VOICE_PLAYBACK_TX,
1301 .stream_name = "Voice Farend Playback",
1302 .cpu_dai_name = "msm-dai-q6.32773",
1303 .platform_name = "msm-pcm-routing",
1304 .codec_name = "msm-stub-codec.1",
1305 .codec_dai_name = "msm-stub-rx",
1306 .no_pcm = 1,
1307 .no_codec = 1,
1308 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
1309 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1310 },
Helen Zenge3d716a2011-10-14 16:32:16 -07001311 /* Incall Record Uplink BACK END DAI Link */
1312 {
1313 .name = LPASS_BE_INCALL_RECORD_TX,
1314 .stream_name = "Voice Uplink Capture",
1315 .cpu_dai_name = "msm-dai-q6.32772",
1316 .platform_name = "msm-pcm-routing",
1317 .codec_name = "msm-stub-codec.1",
1318 .codec_dai_name = "msm-stub-tx",
1319 .no_pcm = 1,
1320 .no_codec = 1,
1321 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
1322 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1323 },
1324 /* Incall Record Downlink BACK END DAI Link */
1325 {
1326 .name = LPASS_BE_INCALL_RECORD_RX,
1327 .stream_name = "Voice Downlink Capture",
1328 .cpu_dai_name = "msm-dai-q6.32771",
1329 .platform_name = "msm-pcm-routing",
1330 .codec_name = "msm-stub-codec.1",
1331 .codec_dai_name = "msm-stub-tx",
1332 .no_pcm = 1,
1333 .no_codec = 1,
1334 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
1335 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
1336 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337};
1338
Kuirong Wangb25838e2012-01-16 23:37:23 -08001339static struct snd_soc_dai_link msm8960_dai_delta_tabla1x[] = {
1340 /* Backend DAI Links */
1341 {
1342 .name = LPASS_BE_SLIMBUS_0_RX,
1343 .stream_name = "Slimbus Playback",
1344 .cpu_dai_name = "msm-dai-q6.16384",
1345 .platform_name = "msm-pcm-routing",
1346 .codec_name = "tabla1x_codec",
1347 .codec_dai_name = "tabla_rx1",
1348 .no_pcm = 1,
1349 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
1350 .init = &msm8960_audrx_init,
1351 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
1352 .ops = &msm8960_be_ops,
1353 },
1354 {
1355 .name = LPASS_BE_SLIMBUS_0_TX,
1356 .stream_name = "Slimbus Capture",
1357 .cpu_dai_name = "msm-dai-q6.16385",
1358 .platform_name = "msm-pcm-routing",
1359 .codec_name = "tabla1x_codec",
1360 .codec_dai_name = "tabla_tx1",
1361 .no_pcm = 1,
1362 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
1363 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
1364 .ops = &msm8960_be_ops,
1365 },
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001366 {
1367 .name = "SLIMBUS_2 Hostless",
1368 .stream_name = "SLIMBUS_2 Hostless",
1369 .cpu_dai_name = "msm-dai-q6.16389",
1370 .platform_name = "msm-pcm-hostless",
1371 .codec_name = "tabla1x_codec",
1372 .codec_dai_name = "tabla_tx2",
Swaminathan Sathappan630c5a42012-05-10 17:33:01 -07001373 .ignore_suspend = 1,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001374 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1375 .ops = &msm8960_be_ops,
1376 },
Kuirong Wangb25838e2012-01-16 23:37:23 -08001377};
1378
1379
1380static struct snd_soc_dai_link msm8960_dai_delta_tabla2x[] = {
1381 /* Backend DAI Links */
1382 {
1383 .name = LPASS_BE_SLIMBUS_0_RX,
1384 .stream_name = "Slimbus Playback",
1385 .cpu_dai_name = "msm-dai-q6.16384",
1386 .platform_name = "msm-pcm-routing",
1387 .codec_name = "tabla_codec",
1388 .codec_dai_name = "tabla_rx1",
1389 .no_pcm = 1,
1390 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
1391 .init = &msm8960_audrx_init,
1392 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
1393 .ops = &msm8960_be_ops,
1394 },
1395 {
1396 .name = LPASS_BE_SLIMBUS_0_TX,
1397 .stream_name = "Slimbus Capture",
1398 .cpu_dai_name = "msm-dai-q6.16385",
1399 .platform_name = "msm-pcm-routing",
1400 .codec_name = "tabla_codec",
1401 .codec_dai_name = "tabla_tx1",
1402 .no_pcm = 1,
1403 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
1404 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
1405 .ops = &msm8960_be_ops,
1406 },
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001407 {
1408 .name = "SLIMBUS_2 Hostless",
1409 .stream_name = "SLIMBUS_2 Hostless",
1410 .cpu_dai_name = "msm-dai-q6.16389",
1411 .platform_name = "msm-pcm-hostless",
1412 .codec_name = "tabla_codec",
1413 .codec_dai_name = "tabla_tx2",
Swaminathan Sathappan630c5a42012-05-10 17:33:01 -07001414 .ignore_suspend = 1,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001415 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1416 .ops = &msm8960_be_ops,
1417 },
Kuirong Wangb25838e2012-01-16 23:37:23 -08001418};
1419
1420static struct snd_soc_dai_link msm8960_tabla1x_dai[
1421 ARRAY_SIZE(msm8960_dai_common) +
1422 ARRAY_SIZE(msm8960_dai_delta_tabla1x)];
1423
1424
1425static struct snd_soc_dai_link msm8960_dai[
1426 ARRAY_SIZE(msm8960_dai_common) +
1427 ARRAY_SIZE(msm8960_dai_delta_tabla2x)];
1428
1429static struct snd_soc_card snd_soc_tabla1x_card_msm8960 = {
1430 .name = "msm8960-tabla1x-snd-card",
1431 .dai_link = msm8960_tabla1x_dai,
1432 .num_links = ARRAY_SIZE(msm8960_tabla1x_dai),
1433};
1434
1435static struct snd_soc_card snd_soc_card_msm8960 = {
1436 .name = "msm8960-snd-card",
1437 .dai_link = msm8960_dai,
1438 .num_links = ARRAY_SIZE(msm8960_dai),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439};
1440
1441static struct platform_device *msm8960_snd_device;
Kuirong Wangb25838e2012-01-16 23:37:23 -08001442static struct platform_device *msm8960_snd_tabla1x_device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443
1444static int msm8960_configure_headset_mic_gpios(void)
1445{
1446 int ret;
1447 struct pm_gpio param = {
1448 .direction = PM_GPIO_DIR_OUT,
1449 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1450 .output_value = 1,
1451 .pull = PM_GPIO_PULL_NO,
1452 .vin_sel = PM_GPIO_VIN_S4,
1453 .out_strength = PM_GPIO_STRENGTH_MED,
1454 .function = PM_GPIO_FUNC_NORMAL,
1455 };
1456
1457 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1458 if (ret) {
1459 pr_err("%s: Failed to request gpio %d\n", __func__,
1460 PM8921_GPIO_PM_TO_SYS(23));
1461 return ret;
1462 }
1463
1464 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
1465 if (ret)
1466 pr_err("%s: Failed to configure gpio %d\n", __func__,
1467 PM8921_GPIO_PM_TO_SYS(23));
1468 else
1469 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
1470
1471 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1472 if (ret) {
1473 pr_err("%s: Failed to request gpio %d\n", __func__,
1474 PM8921_GPIO_PM_TO_SYS(35));
1475 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1476 return ret;
1477 }
1478 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
1479 if (ret)
1480 pr_err("%s: Failed to configure gpio %d\n", __func__,
1481 PM8921_GPIO_PM_TO_SYS(35));
1482 else
Patrick Lai2ae0a002011-09-26 14:51:09 -07001483 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484
1485 return 0;
1486}
1487static void msm8960_free_headset_mic_gpios(void)
1488{
1489 if (msm8960_headset_gpios_configured) {
1490 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1491 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
1492 }
1493}
1494
1495static int __init msm8960_audio_init(void)
1496{
1497 int ret;
1498
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301499 if (!cpu_is_msm8960()) {
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001500 pr_err("%s: Not the right machine type\n", __func__);
1501 return -ENODEV ;
1502 }
Joonwoo Park0976d012011-12-22 11:48:18 -08001503
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001504 mbhc_cfg.calibration = def_tabla_mbhc_cal();
1505 if (!mbhc_cfg.calibration) {
Joonwoo Park0976d012011-12-22 11:48:18 -08001506 pr_err("Calibration data allocation failed\n");
1507 return -ENOMEM;
1508 }
1509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
1511 if (!msm8960_snd_device) {
1512 pr_err("Platform device allocation failed\n");
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001513 kfree(mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 return -ENOMEM;
1515 }
1516
Kuirong Wangb25838e2012-01-16 23:37:23 -08001517 memcpy(msm8960_dai, msm8960_dai_common, sizeof(msm8960_dai_common));
1518 memcpy(msm8960_dai + ARRAY_SIZE(msm8960_dai_common),
1519 msm8960_dai_delta_tabla2x, sizeof(msm8960_dai_delta_tabla2x));
1520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
1522 ret = platform_device_add(msm8960_snd_device);
1523 if (ret) {
1524 platform_device_put(msm8960_snd_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001525 kfree(mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 return ret;
1527 }
1528
Kuirong Wangb25838e2012-01-16 23:37:23 -08001529 msm8960_snd_tabla1x_device = platform_device_alloc("soc-audio", 1);
1530 if (!msm8960_snd_tabla1x_device) {
1531 pr_err("Platform device allocation failed\n");
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001532 kfree(mbhc_cfg.calibration);
Kuirong Wangb25838e2012-01-16 23:37:23 -08001533 return -ENOMEM;
1534 }
1535
1536 memcpy(msm8960_tabla1x_dai, msm8960_dai_common,
1537 sizeof(msm8960_dai_common));
1538 memcpy(msm8960_tabla1x_dai + ARRAY_SIZE(msm8960_dai_common),
1539 msm8960_dai_delta_tabla1x, sizeof(msm8960_dai_delta_tabla1x));
1540
1541 platform_set_drvdata(msm8960_snd_tabla1x_device,
1542 &snd_soc_tabla1x_card_msm8960);
1543 ret = platform_device_add(msm8960_snd_tabla1x_device);
1544 if (ret) {
1545 platform_device_put(msm8960_snd_tabla1x_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001546 kfree(mbhc_cfg.calibration);
Kuirong Wangb25838e2012-01-16 23:37:23 -08001547 return ret;
1548 }
1549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 if (msm8960_configure_headset_mic_gpios()) {
1551 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1552 msm8960_headset_gpios_configured = 0;
1553 } else
1554 msm8960_headset_gpios_configured = 1;
1555
Joonwoo Park28f49c82012-03-16 12:29:21 -07001556 mutex_init(&cdc_mclk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 return ret;
1558
1559}
1560module_init(msm8960_audio_init);
1561
1562static void __exit msm8960_audio_exit(void)
1563{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301564 if (!cpu_is_msm8960()) {
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001565 pr_err("%s: Not the right machine type\n", __func__);
1566 return ;
1567 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 msm8960_free_headset_mic_gpios();
1569 platform_device_unregister(msm8960_snd_device);
Kuirong Wangb25838e2012-01-16 23:37:23 -08001570 platform_device_unregister(msm8960_snd_tabla1x_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001571 kfree(mbhc_cfg.calibration);
Joonwoo Park28f49c82012-03-16 12:29:21 -07001572 mutex_destroy(&cdc_mclk_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573}
1574module_exit(msm8960_audio_exit);
1575
1576MODULE_DESCRIPTION("ALSA SoC MSM8960");
1577MODULE_LICENSE("GPL v2");