blob: fff978f32c32230a21480b7a7723bb6477907748 [file] [log] [blame]
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/gpio.h>
16#include <linux/mfd/pm8xxx/pm8018.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <sound/core.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22#include <sound/soc-dsp.h>
23#include <sound/pcm.h>
24#include <sound/jack.h>
25#include <asm/mach-types.h>
26#include <mach/socinfo.h>
27#include "msm-pcm-routing.h"
28#include "../codecs/wcd9310.h"
29
30/* 9615 machine driver */
31
32#define PM8018_GPIO_BASE NR_GPIO_IRQS
33#define PM8018_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8018_GPIO_BASE)
34
35#define MDM9615_SPK_ON 1
36#define MDM9615_SPK_OFF 0
37
38#define MDM9615_SLIM_0_RX_MAX_CHANNELS 2
39#define MDM9615_SLIM_0_TX_MAX_CHANNELS 4
40
41#define BTSCO_RATE_8KHZ 8000
42#define BTSCO_RATE_16KHZ 16000
43
44#define BOTTOM_SPK_AMP_POS 0x1
45#define BOTTOM_SPK_AMP_NEG 0x2
46#define TOP_SPK_AMP_POS 0x4
47#define TOP_SPK_AMP_NEG 0x8
48
49#define GPIO_AUX_PCM_DOUT 63
50#define GPIO_AUX_PCM_DIN 64
51#define GPIO_AUX_PCM_SYNC 65
52#define GPIO_AUX_PCM_CLK 66
53
54#define TABLA_EXT_CLK_RATE 12288000
55
56#define TABLA_MBHC_DEF_BUTTONS 8
57#define TABLA_MBHC_DEF_RLOADS 5
58
59static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(18);
60static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(19);
61static int mdm9615_spk_control;
62static int mdm9615_ext_bottom_spk_pamp;
63static int mdm9615_ext_top_spk_pamp;
64static int mdm9615_slim_0_rx_ch = 1;
65static int mdm9615_slim_0_tx_ch = 1;
66
67static int mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
68static int mdm9615_btsco_ch = 1;
69
70static struct clk *codec_clk;
71static int clk_users;
72
73static int mdm9615_headset_gpios_configured;
74
75static struct snd_soc_jack hs_jack;
76static struct snd_soc_jack button_jack;
77
78static void *tabla_mbhc_cal;
79
80static void mdm9615_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
81{
82 int ret = 0;
83
84 struct pm_gpio param = {
85 .direction = PM_GPIO_DIR_OUT,
86 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
87 .output_value = 1,
88 .pull = PM_GPIO_PULL_NO,
89 .vin_sel = PM_GPIO_VIN_S4,
90 .out_strength = PM_GPIO_STRENGTH_MED,
91 .function = PM_GPIO_FUNC_NORMAL,
92 };
93
94 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
95
96 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
97 if (ret) {
98 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
99 __func__, bottom_spk_pamp_gpio);
100 return;
101 }
102 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
103 if (ret)
104 pr_err("%s: Failed to configure Bottom Spk Ampl"
105 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
106 else {
107 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
108 gpio_direction_output(bottom_spk_pamp_gpio, 1);
109 }
110
111 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
112
113 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
114 if (ret) {
115 pr_err("%s: Error requesting GPIO %d\n", __func__,
116 top_spk_pamp_gpio);
117 return;
118 }
119 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
120 if (ret)
121 pr_err("%s: Failed to configure Top Spk Ampl"
122 " gpio %u\n", __func__, top_spk_pamp_gpio);
123 else {
124 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
125 gpio_direction_output(top_spk_pamp_gpio, 1);
126 }
127 } else {
128 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
129 " gpio = %u\n", __func__, spk_amp_gpio);
130 return;
131 }
132}
133
134static void mdm9615_ext_spk_power_amp_on(u32 spk)
135{
136 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
137
138 if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
139 (mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
140
141 pr_debug("%s() External Bottom Speaker Ampl already "
142 "turned on. spk = 0x%08x\n", __func__, spk);
143 return;
144 }
145
146 mdm9615_ext_bottom_spk_pamp |= spk;
147
148 if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
149 (mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
150
151 mdm9615_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
152 pr_debug("%s: slepping 4 ms after turning on external "
153 " Bottom Speaker Ampl\n", __func__);
154 usleep_range(4000, 4000);
155 }
156
157 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
158
159 if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
160 (mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
161
162 pr_debug("%s() External Top Speaker Ampl already"
163 "turned on. spk = 0x%08x\n", __func__, spk);
164 return;
165 }
166
167 mdm9615_ext_top_spk_pamp |= spk;
168
169 if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
170 (mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
171
172 mdm9615_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
173 pr_debug("%s: sleeping 4 ms after turning on "
174 " external Top Speaker Ampl\n", __func__);
175 usleep_range(4000, 4000);
176 }
177 } else {
178
179 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
180 __func__, spk);
181 return;
182 }
183}
184
185static void mdm9615_ext_spk_power_amp_off(u32 spk)
186{
187 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
188
189 if (!mdm9615_ext_bottom_spk_pamp)
190 return;
191
192 gpio_direction_output(bottom_spk_pamp_gpio, 0);
193 gpio_free(bottom_spk_pamp_gpio);
194 mdm9615_ext_bottom_spk_pamp = 0;
195
196 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
197 " Speaker Ampl\n", __func__);
198
199 usleep_range(4000, 4000);
200
201 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
202
203 if (!mdm9615_ext_top_spk_pamp)
204 return;
205
206 gpio_direction_output(top_spk_pamp_gpio, 0);
207 gpio_free(top_spk_pamp_gpio);
208 mdm9615_ext_top_spk_pamp = 0;
209
210 pr_debug("%s: sleeping 4 ms after turning off external Top"
211 " Spkaker Ampl\n", __func__);
212
213 usleep_range(4000, 4000);
214 } else {
215
216 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
217 __func__, spk);
218 return;
219 }
220}
221
222static void mdm9615_ext_control(struct snd_soc_codec *codec)
223{
224 struct snd_soc_dapm_context *dapm = &codec->dapm;
225
226 pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
227 if (mdm9615_spk_control == MDM9615_SPK_ON) {
228 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
229 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
230 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
231 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
232 } else {
233 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
234 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
235 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
236 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
237 }
238
239 snd_soc_dapm_sync(dapm);
240}
241
242static int mdm9615_get_spk(struct snd_kcontrol *kcontrol,
243 struct snd_ctl_elem_value *ucontrol)
244{
245 pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
246 ucontrol->value.integer.value[0] = mdm9615_spk_control;
247 return 0;
248}
249static int mdm9615_set_spk(struct snd_kcontrol *kcontrol,
250 struct snd_ctl_elem_value *ucontrol)
251{
252 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
253
254 pr_debug("%s()\n", __func__);
255 if (mdm9615_spk_control == ucontrol->value.integer.value[0])
256 return 0;
257
258 mdm9615_spk_control = ucontrol->value.integer.value[0];
259 mdm9615_ext_control(codec);
260 return 1;
261}
262static int mdm9615_spkramp_event(struct snd_soc_dapm_widget *w,
263 struct snd_kcontrol *k, int event)
264{
265 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
266
267 if (SND_SOC_DAPM_EVENT_ON(event)) {
268 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
269 mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
270 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
271 mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
272 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
273 mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
274 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
275 mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
276 else {
277 pr_err("%s() Invalid Speaker Widget = %s\n",
278 __func__, w->name);
279 return -EINVAL;
280 }
281
282 } else {
283 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
284 mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
285 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
286 mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
287 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
288 mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
289 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
290 mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
291 else {
292 pr_err("%s() Invalid Speaker Widget = %s\n",
293 __func__, w->name);
294 return -EINVAL;
295 }
296 }
297 return 0;
298}
299int mdm9615_enable_codec_ext_clk(
300 struct snd_soc_codec *codec, int enable)
301{
302 pr_debug("%s: enable = %d\n", __func__, enable);
303 if (enable) {
304 clk_users++;
305 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
306 if (clk_users != 1)
307 return 0;
308
309 if (codec_clk) {
310 clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
311 clk_enable(codec_clk);
312 tabla_mclk_enable(codec, 1);
313 } else {
314 pr_err("%s: Error setting Tabla MCLK\n", __func__);
315 clk_users--;
316 return -EINVAL;
317 }
318 } else {
319 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
320 if (clk_users == 0)
321 return 0;
322 clk_users--;
323 if (!clk_users) {
324 pr_debug("%s: disabling MCLK. clk_users = %d\n",
325 __func__, clk_users);
326 clk_disable(codec_clk);
327 tabla_mclk_enable(codec, 0);
328 }
329 }
330 return 0;
331}
332
333static int mdm9615_mclk_event(struct snd_soc_dapm_widget *w,
334 struct snd_kcontrol *kcontrol, int event)
335{
336 pr_debug("%s: event = %d\n", __func__, event);
337
338 switch (event) {
339 case SND_SOC_DAPM_PRE_PMU:
340 return mdm9615_enable_codec_ext_clk(w->codec, 1);
341 case SND_SOC_DAPM_POST_PMD:
342 return mdm9615_enable_codec_ext_clk(w->codec, 0);
343 }
344 return 0;
345}
346
347static const struct snd_soc_dapm_widget mdm9615_dapm_widgets[] = {
348
349 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
350 mdm9615_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
351
352 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", mdm9615_spkramp_event),
353 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", mdm9615_spkramp_event),
354
355 SND_SOC_DAPM_SPK("Ext Spk Top Pos", mdm9615_spkramp_event),
356 SND_SOC_DAPM_SPK("Ext Spk Top Neg", mdm9615_spkramp_event),
357
358 SND_SOC_DAPM_MIC("Handset Mic", NULL),
359 SND_SOC_DAPM_MIC("Headset Mic", NULL),
360 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
361 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
362 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
363
364 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
365 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
366 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
367 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
368 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
369 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
370
371};
372
373static const struct snd_soc_dapm_route common_audio_map[] = {
374
375 {"RX_BIAS", NULL, "MCLK"},
376 {"LDO_H", NULL, "MCLK"},
377
378 /* Speaker path */
379 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
380 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
381
382 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
383 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
384
385 /* Microphone path */
386 {"AMIC1", NULL, "MIC BIAS1 External"},
387 {"MIC BIAS1 External", NULL, "Handset Mic"},
388
389 {"AMIC2", NULL, "MIC BIAS2 External"},
390 {"MIC BIAS2 External", NULL, "Headset Mic"},
391
392 /**
393 * AMIC3 and AMIC4 inputs are connected to ANC microphones
394 * These mics are biased differently on CDP and FLUID
395 * routing entries below are based on bias arrangement
396 * on FLUID.
397 */
398 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
399 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
400
401 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
402 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
403
404 {"HEADPHONE", NULL, "LDO_H"},
405
406 /**
407 * The digital Mic routes are setup considering
408 * fluid as default device.
409 */
410
411 /**
412 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
413 * Digital Mic GM5 on CDP mainboard.
414 * Conncted to DMIC2 Input on Tabla codec.
415 */
416 {"DMIC2", NULL, "MIC BIAS1 External"},
417 {"MIC BIAS1 External", NULL, "Digital Mic1"},
418
419 /**
420 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
421 * Digital Mic GM6 on CDP mainboard.
422 * Conncted to DMIC1 Input on Tabla codec.
423 */
424 {"DMIC1", NULL, "MIC BIAS1 External"},
425 {"MIC BIAS1 External", NULL, "Digital Mic2"},
426
427 /**
428 * Digital Mic3. Back Bottom Digital Mic on Fluid.
429 * Digital Mic GM1 on CDP mainboard.
430 * Conncted to DMIC4 Input on Tabla codec.
431 */
432 {"DMIC4", NULL, "MIC BIAS3 External"},
433 {"MIC BIAS3 External", NULL, "Digital Mic3"},
434
435 /**
436 * Digital Mic4. Back top Digital Mic on Fluid.
437 * Digital Mic GM2 on CDP mainboard.
438 * Conncted to DMIC3 Input on Tabla codec.
439 */
440 {"DMIC3", NULL, "MIC BIAS3 External"},
441 {"MIC BIAS3 External", NULL, "Digital Mic4"},
442
443 /**
444 * Digital Mic5. Front top Digital Mic on Fluid.
445 * Digital Mic GM3 on CDP mainboard.
446 * Conncted to DMIC5 Input on Tabla codec.
447 */
448 {"DMIC5", NULL, "MIC BIAS4 External"},
449 {"MIC BIAS4 External", NULL, "Digital Mic5"},
450
451 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
452 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
453 */
454 {"DMIC6", NULL, "MIC BIAS4 External"},
455 {"MIC BIAS4 External", NULL, "Digital Mic6"},
456};
457
458static const char *spk_function[] = {"Off", "On"};
459static const char *slim0_rx_ch_text[] = {"One", "Two"};
460static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
461
462static const struct soc_enum mdm9615_enum[] = {
463 SOC_ENUM_SINGLE_EXT(2, spk_function),
464 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
465 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
466};
467
468static const char *btsco_rate_text[] = {"8000", "16000"};
469static const struct soc_enum mdm9615_btsco_enum[] = {
470 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
471};
472
473static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
474 struct snd_ctl_elem_value *ucontrol)
475{
476 pr_debug("%s: mdm9615_slim_0_rx_ch = %d\n", __func__,
477 mdm9615_slim_0_rx_ch);
478 ucontrol->value.integer.value[0] = mdm9615_slim_0_rx_ch - 1;
479 return 0;
480}
481
482static int mdm9615_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
483 struct snd_ctl_elem_value *ucontrol)
484{
485 mdm9615_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
486
487 pr_debug("%s: mdm9615_slim_0_rx_ch = %d\n", __func__,
488 mdm9615_slim_0_rx_ch);
489 return 1;
490}
491
492static int mdm9615_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
494{
495 pr_debug("%s: mdm9615_slim_0_tx_ch = %d\n", __func__,
496 mdm9615_slim_0_tx_ch);
497 ucontrol->value.integer.value[0] = mdm9615_slim_0_tx_ch - 1;
498 return 0;
499}
500
501static int mdm9615_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
502 struct snd_ctl_elem_value *ucontrol)
503{
504 mdm9615_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
505
506 pr_debug("%s: mdm9615_slim_0_tx_ch = %d\n", __func__,
507 mdm9615_slim_0_tx_ch);
508 return 1;
509}
510
511static int mdm9615_btsco_rate_get(struct snd_kcontrol *kcontrol,
512 struct snd_ctl_elem_value *ucontrol)
513{
514 pr_debug("%s: mdm9615_btsco_rate = %d", __func__, mdm9615_btsco_rate);
515 ucontrol->value.integer.value[0] = mdm9615_btsco_rate;
516 return 0;
517}
518
519static int mdm9615_btsco_rate_put(struct snd_kcontrol *kcontrol,
520 struct snd_ctl_elem_value *ucontrol)
521{
522 switch (ucontrol->value.integer.value[0]) {
523 case 0:
524 mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
525 break;
526 case 1:
527 mdm9615_btsco_rate = BTSCO_RATE_16KHZ;
528 break;
529 default:
530 mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
531 break;
532 }
533 pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
534 return 0;
535}
536
537static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
538 SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
539 mdm9615_set_spk),
540 SOC_ENUM_EXT("SLIM_0_RX Channels", mdm9615_enum[1],
541 mdm9615_slim_0_rx_ch_get, mdm9615_slim_0_rx_ch_put),
542 SOC_ENUM_EXT("SLIM_0_TX Channels", mdm9615_enum[2],
543 mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
544};
545
546static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
547 SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
548 mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
549};
550
551static int mdm9615_btsco_init(struct snd_soc_pcm_runtime *rtd)
552{
553 int err = 0;
554 struct snd_soc_platform *platform = rtd->platform;
555
556 err = snd_soc_add_platform_controls(platform,
557 int_btsco_rate_mixer_controls,
558 ARRAY_SIZE(int_btsco_rate_mixer_controls));
559 if (err < 0)
560 return err;
561 return 0;
562}
563
564static void *def_tabla_mbhc_cal(void)
565{
566 void *tabla_cal;
567 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
568 u16 *btn_low, *btn_high;
569 u8 *n_ready, *n_cic, *gain;
570
571 tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
572 TABLA_MBHC_DEF_RLOADS),
573 GFP_KERNEL);
574 if (!tabla_cal) {
575 pr_err("%s: out of memory\n", __func__);
576 return NULL;
577 }
578
579#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
580 S(t_ldoh, 100);
581 S(t_bg_fast_settle, 100);
582 S(t_shutdown_plug_rem, 255);
583 S(mbhc_nsa, 4);
584 S(mbhc_navg, 4);
585#undef S
586#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
587 S(mic_current, TABLA_PID_MIC_5_UA);
588 S(hph_current, TABLA_PID_MIC_5_UA);
589 S(t_mic_pid, 100);
590 S(t_ins_complete, 250);
591 S(t_ins_retry, 200);
592#undef S
593#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
594 S(v_no_mic, 30);
595 S(v_hs_max, 1550);
596#undef S
597#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
598 S(c[0], 62);
599 S(c[1], 124);
600 S(nc, 1);
601 S(n_meas, 3);
602 S(mbhc_nsc, 11);
603 S(n_btn_meas, 1);
604 S(n_btn_con, 2);
605 S(num_btn, TABLA_MBHC_DEF_BUTTONS);
606 S(v_btn_press_delta_sta, 100);
607 S(v_btn_press_delta_cic, 50);
608#undef S
609 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
610 btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
611 btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
612 btn_low[0] = -50;
613 btn_high[0] = 10;
614 btn_low[1] = 11;
615 btn_high[1] = 38;
616 btn_low[2] = 39;
617 btn_high[2] = 64;
618 btn_low[3] = 65;
619 btn_high[3] = 91;
620 btn_low[4] = 92;
621 btn_high[4] = 115;
622 btn_low[5] = 116;
623 btn_high[5] = 141;
624 btn_low[6] = 142;
625 btn_high[6] = 163;
626 btn_low[7] = 164;
627 btn_high[7] = 250;
628 n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
629 n_ready[0] = 48;
630 n_ready[1] = 38;
631 n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
632 n_cic[0] = 60;
633 n_cic[1] = 47;
634 gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
635 gain[0] = 11;
636 gain[1] = 9;
637
638 return tabla_cal;
639}
640
641static int mdm9615_hw_params(struct snd_pcm_substream *substream,
642 struct snd_pcm_hw_params *params)
643{
644 struct snd_soc_pcm_runtime *rtd = substream->private_data;
645 struct snd_soc_dai *codec_dai = rtd->codec_dai;
646 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
647 int ret = 0;
648 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
649 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
650
651 pr_debug("%s: ch=%d\n", __func__,
652 mdm9615_slim_0_rx_ch);
653 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
654 ret = snd_soc_dai_get_channel_map(codec_dai,
655 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
656 if (ret < 0) {
657 pr_err("%s: failed to get codec chan map\n", __func__);
658 goto end;
659 }
660
661 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
662 mdm9615_slim_0_rx_ch, rx_ch);
663 if (ret < 0) {
664 pr_err("%s: failed to set cpu chan map\n", __func__);
665 goto end;
666 }
667 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
668 mdm9615_slim_0_rx_ch, rx_ch);
669 if (ret < 0) {
670 pr_err("%s: failed to set codec channel map\n",
671 __func__);
672 goto end;
673 }
674 } else {
675 ret = snd_soc_dai_get_channel_map(codec_dai,
676 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
677 if (ret < 0) {
678 pr_err("%s: failed to get codec chan map\n", __func__);
679 goto end;
680 }
681 ret = snd_soc_dai_set_channel_map(cpu_dai,
682 mdm9615_slim_0_tx_ch, tx_ch, 0 , 0);
683 if (ret < 0) {
684 pr_err("%s: failed to set cpu chan map\n", __func__);
685 goto end;
686 }
687 ret = snd_soc_dai_set_channel_map(codec_dai,
688 mdm9615_slim_0_tx_ch, tx_ch, 0, 0);
689 if (ret < 0) {
690 pr_err("%s: failed to set codec channel map\n",
691 __func__);
692 goto end;
693 }
694
695
696 }
697end:
698 return ret;
699}
700
701static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
702{
703 int err;
704 struct snd_soc_codec *codec = rtd->codec;
705 struct snd_soc_dapm_context *dapm = &codec->dapm;
706 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
707
708 pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
709
710 rtd->pmdown_time = 0;
711 err = snd_soc_add_controls(codec, tabla_mdm9615_controls,
712 ARRAY_SIZE(tabla_mdm9615_controls));
713 if (err < 0)
714 return err;
715
716 snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
717 ARRAY_SIZE(mdm9615_dapm_widgets));
718
719 snd_soc_dapm_add_routes(dapm, common_audio_map,
720 ARRAY_SIZE(common_audio_map));
721
722 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
723 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
724 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
725 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
726
727 snd_soc_dapm_sync(dapm);
728
729 err = snd_soc_jack_new(codec, "Headset Jack",
730 (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
731 SND_JACK_OC_HPHR),
732 &hs_jack);
733 if (err) {
734 pr_err("failed to create new jack\n");
735 return err;
736 }
737
738 err = snd_soc_jack_new(codec, "Button Jack",
739 TABLA_JACK_BUTTON_MASK, &button_jack);
740 if (err) {
741 pr_err("failed to create new jack\n");
742 return err;
743 }
744 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
745 tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
746 TABLA_MICBIAS2, mdm9615_enable_codec_ext_clk, 0,
747 TABLA_EXT_CLK_RATE);
748
749 return 0;
750}
751
752static struct snd_soc_dsp_link fe_media = {
753 .playback = true,
754 .capture = true,
755 .trigger = {
756 SND_SOC_DSP_TRIGGER_POST,
757 SND_SOC_DSP_TRIGGER_POST
758 },
759};
760
761/* bi-directional media definition for hostless PCM device */
762static struct snd_soc_dsp_link bidir_hl_media = {
763 .playback = true,
764 .capture = true,
765 .trigger = {
766 SND_SOC_DSP_TRIGGER_POST,
767 SND_SOC_DSP_TRIGGER_POST
768 },
769};
770
771static int mdm9615_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
772 struct snd_pcm_hw_params *params)
773{
774 struct snd_interval *rate = hw_param_interval(params,
775 SNDRV_PCM_HW_PARAM_RATE);
776
777 struct snd_interval *channels = hw_param_interval(params,
778 SNDRV_PCM_HW_PARAM_CHANNELS);
779
780 pr_debug("%s()\n", __func__);
781 rate->min = rate->max = 48000;
782 channels->min = channels->max = mdm9615_slim_0_rx_ch;
783
784 return 0;
785}
786
787static int mdm9615_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
788 struct snd_pcm_hw_params *params)
789{
790 struct snd_interval *rate = hw_param_interval(params,
791 SNDRV_PCM_HW_PARAM_RATE);
792
793 struct snd_interval *channels = hw_param_interval(params,
794 SNDRV_PCM_HW_PARAM_CHANNELS);
795
796 pr_debug("%s()\n", __func__);
797 rate->min = rate->max = 48000;
798 channels->min = channels->max = mdm9615_slim_0_tx_ch;
799
800 return 0;
801}
802
803static int mdm9615_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
804 struct snd_pcm_hw_params *params)
805{
806 struct snd_interval *rate = hw_param_interval(params,
807 SNDRV_PCM_HW_PARAM_RATE);
808
809 struct snd_interval *channels = hw_param_interval(params,
810 SNDRV_PCM_HW_PARAM_CHANNELS);
811
812 rate->min = rate->max = mdm9615_btsco_rate;
813 channels->min = channels->max = mdm9615_btsco_ch;
814
815 return 0;
816}
817static int mdm9615_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
818 struct snd_pcm_hw_params *params)
819{
820 struct snd_interval *rate = hw_param_interval(params,
821 SNDRV_PCM_HW_PARAM_RATE);
822
823 struct snd_interval *channels = hw_param_interval(params,
824 SNDRV_PCM_HW_PARAM_CHANNELS);
825
826 /* PCM only supports mono output with 8khz sample rate */
827 rate->min = rate->max = 8000;
828 channels->min = channels->max = 1;
829
830 return 0;
831}
832static int mdm9615_aux_pcm_get_gpios(void)
833{
834 int ret = 0;
835
836 pr_debug("%s\n", __func__);
837
838 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
839 if (ret < 0) {
840 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
841 __func__, GPIO_AUX_PCM_DOUT);
842 goto fail_dout;
843 }
844
845 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
846 if (ret < 0) {
847 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
848 __func__, GPIO_AUX_PCM_DIN);
849 goto fail_din;
850 }
851
852 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
853 if (ret < 0) {
854 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
855 __func__, GPIO_AUX_PCM_SYNC);
856 goto fail_sync;
857 }
858 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
859 if (ret < 0) {
860 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
861 __func__, GPIO_AUX_PCM_CLK);
862 goto fail_clk;
863 }
864
865 return 0;
866
867fail_clk:
868 gpio_free(GPIO_AUX_PCM_SYNC);
869fail_sync:
870 gpio_free(GPIO_AUX_PCM_DIN);
871fail_din:
872 gpio_free(GPIO_AUX_PCM_DOUT);
873fail_dout:
874
875 return ret;
876}
877
878static int mdm9615_aux_pcm_free_gpios(void)
879{
880 gpio_free(GPIO_AUX_PCM_DIN);
881 gpio_free(GPIO_AUX_PCM_DOUT);
882 gpio_free(GPIO_AUX_PCM_SYNC);
883 gpio_free(GPIO_AUX_PCM_CLK);
884
885 return 0;
886}
887static int mdm9615_startup(struct snd_pcm_substream *substream)
888{
889 pr_debug("%s(): substream = %s stream = %d\n", __func__,
890 substream->name, substream->stream);
891 return 0;
892}
893
894static int mdm9615_auxpcm_startup(struct snd_pcm_substream *substream)
895{
896 int ret = 0;
897
898 pr_debug("%s(): substream = %s\n", __func__, substream->name);
899 ret = mdm9615_aux_pcm_get_gpios();
900 if (ret < 0) {
901 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
902 return -EINVAL;
903 }
904 return 0;
905}
906
907static void mdm9615_auxpcm_shutdown(struct snd_pcm_substream *substream)
908{
909
910 pr_debug("%s(): substream = %s\n", __func__, substream->name);
911 mdm9615_aux_pcm_free_gpios();
912}
913
914static void mdm9615_shutdown(struct snd_pcm_substream *substream)
915{
916 pr_debug("%s(): substream = %s stream = %d\n", __func__,
917 substream->name, substream->stream);
918}
919
920static struct snd_soc_ops mdm9615_be_ops = {
921 .startup = mdm9615_startup,
922 .hw_params = mdm9615_hw_params,
923 .shutdown = mdm9615_shutdown,
924};
925
926static struct snd_soc_ops mdm9615_auxpcm_be_ops = {
927 .startup = mdm9615_auxpcm_startup,
928 .shutdown = mdm9615_auxpcm_shutdown,
929};
930
931/* Digital audio interface glue - connects codec <---> CPU */
932static struct snd_soc_dai_link mdm9615_dai_common[] = {
933 /* FrontEnd DAI Links */
934 {
935 .name = "MDM9615 Media1",
936 .stream_name = "MultiMedia1",
937 .cpu_dai_name = "MultiMedia1",
938 .platform_name = "msm-pcm-dsp",
939 .dynamic = 1,
940 .dsp_link = &fe_media,
941 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
942 },
943 {
944 .name = "MDM9615 Media2",
945 .stream_name = "MultiMedia2",
946 .cpu_dai_name = "MultiMedia2",
947 .platform_name = "msm-pcm-dsp",
948 .dynamic = 1,
949 .dsp_link = &fe_media,
950 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
951 },
952 {
953 .name = "Circuit-Switch Voice",
954 .stream_name = "CS-Voice",
955 .cpu_dai_name = "CS-VOICE",
956 .platform_name = "msm-pcm-voice",
957 .dynamic = 1,
958 .dsp_link = &fe_media,
959 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
960 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
961 .ignore_suspend = 1,
962 },
963 {
964 .name = "MSM VoIP",
965 .stream_name = "VoIP",
966 .cpu_dai_name = "VoIP",
967 .platform_name = "msm-voip-dsp",
968 .dynamic = 1,
969 .dsp_link = &fe_media,
970 .be_id = MSM_FRONTEND_DAI_VOIP,
971 },
972 /* Hostless PMC purpose */
973 {
974 .name = "SLIMBUS_0 Hostless",
975 .stream_name = "SLIMBUS_0 Hostless",
976 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
977 .platform_name = "msm-pcm-hostless",
978 .dynamic = 1,
979 .dsp_link = &bidir_hl_media,
980 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
981 .ignore_suspend = 1,
982 /* .be_id = do not care */
983 },
984 {
985 .name = "MSM AFE-PCM RX",
986 .stream_name = "AFE-PROXY RX",
987 .cpu_dai_name = "msm-dai-q6.241",
988 .codec_name = "msm-stub-codec.1",
989 .codec_dai_name = "msm-stub-rx",
990 .platform_name = "msm-pcm-afe",
991 .ignore_suspend = 1,
992 },
993 {
994 .name = "MSM AFE-PCM TX",
995 .stream_name = "AFE-PROXY TX",
996 .cpu_dai_name = "msm-dai-q6.240",
997 .codec_name = "msm-stub-codec.1",
998 .codec_dai_name = "msm-stub-tx",
999 .platform_name = "msm-pcm-afe",
1000 .ignore_suspend = 1,
1001 },
1002 {
1003 .name = "AUXPCM Hostless",
1004 .stream_name = "AUXPCM Hostless",
1005 .cpu_dai_name = "AUXPCM_HOSTLESS",
1006 .platform_name = "msm-pcm-hostless",
1007 .dynamic = 1,
1008 .dsp_link = &bidir_hl_media,
1009 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1010 .ignore_suspend = 1,
1011 },
1012 /* Backend BT DAI Links */
1013 {
1014 .name = LPASS_BE_INT_BT_SCO_RX,
1015 .stream_name = "Internal BT-SCO Playback",
1016 .cpu_dai_name = "msm-dai-q6.12288",
1017 .platform_name = "msm-pcm-routing",
1018 .codec_name = "msm-stub-codec.1",
1019 .codec_dai_name = "msm-stub-rx",
1020 .init = &mdm9615_btsco_init,
1021 .no_pcm = 1,
1022 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
1023 .be_hw_params_fixup = mdm9615_btsco_be_hw_params_fixup,
1024 },
1025 {
1026 .name = LPASS_BE_INT_BT_SCO_TX,
1027 .stream_name = "Internal BT-SCO Capture",
1028 .cpu_dai_name = "msm-dai-q6.12289",
1029 .platform_name = "msm-pcm-routing",
1030 .codec_name = "msm-stub-codec.1",
1031 .codec_dai_name = "msm-stub-tx",
1032 .no_pcm = 1,
1033 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
1034 .be_hw_params_fixup = mdm9615_btsco_be_hw_params_fixup,
1035 },
1036
1037 /* Backend AFE DAI Links */
1038 {
1039 .name = LPASS_BE_AFE_PCM_RX,
1040 .stream_name = "AFE Playback",
1041 .cpu_dai_name = "msm-dai-q6.224",
1042 .platform_name = "msm-pcm-routing",
1043 .codec_name = "msm-stub-codec.1",
1044 .codec_dai_name = "msm-stub-rx",
1045 .no_codec = 1,
1046 .no_pcm = 1,
1047 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1048 },
1049 {
1050 .name = LPASS_BE_AFE_PCM_TX,
1051 .stream_name = "AFE Capture",
1052 .cpu_dai_name = "msm-dai-q6.225",
1053 .platform_name = "msm-pcm-routing",
1054 .codec_name = "msm-stub-codec.1",
1055 .codec_dai_name = "msm-stub-tx",
1056 .no_codec = 1,
1057 .no_pcm = 1,
1058 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1059 },
1060 /* AUX PCM Backend DAI Links */
1061 {
1062 .name = LPASS_BE_AUXPCM_RX,
1063 .stream_name = "AUX PCM Playback",
1064 .cpu_dai_name = "msm-dai-q6.2",
1065 .platform_name = "msm-pcm-routing",
1066 .codec_name = "msm-stub-codec.1",
1067 .codec_dai_name = "msm-stub-rx",
1068 .no_pcm = 1,
1069 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1070 .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
1071 .ops = &mdm9615_auxpcm_be_ops,
1072 },
1073 {
1074 .name = LPASS_BE_AUXPCM_TX,
1075 .stream_name = "AUX PCM Capture",
1076 .cpu_dai_name = "msm-dai-q6.3",
1077 .platform_name = "msm-pcm-routing",
1078 .codec_name = "msm-stub-codec.1",
1079 .codec_dai_name = "msm-stub-tx",
1080 .no_pcm = 1,
1081 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1082 .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
1083 },
1084
1085};
1086
1087static struct snd_soc_dai_link mdm9615_dai_delta_tabla[] = {
1088 /* Backend DAI Links */
1089 {
1090 .name = LPASS_BE_SLIMBUS_0_RX,
1091 .stream_name = "Slimbus Playback",
1092 .cpu_dai_name = "msm-dai-q6.16384",
1093 .platform_name = "msm-pcm-routing",
1094 .codec_name = "tabla_codec",
1095 .codec_dai_name = "tabla_rx1",
1096 .no_pcm = 1,
1097 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
1098 .init = &mdm9615_audrx_init,
1099 .be_hw_params_fixup = mdm9615_slim_0_rx_be_hw_params_fixup,
1100 .ops = &mdm9615_be_ops,
1101 },
1102 {
1103 .name = LPASS_BE_SLIMBUS_0_TX,
1104 .stream_name = "Slimbus Capture",
1105 .cpu_dai_name = "msm-dai-q6.16385",
1106 .platform_name = "msm-pcm-routing",
1107 .codec_name = "tabla_codec",
1108 .codec_dai_name = "tabla_tx1",
1109 .no_pcm = 1,
1110 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
1111 .be_hw_params_fixup = mdm9615_slim_0_tx_be_hw_params_fixup,
1112 .ops = &mdm9615_be_ops,
1113 },
1114};
1115
1116static struct snd_soc_dai_link mdm9615_dai[
1117 ARRAY_SIZE(mdm9615_dai_common) +
1118 ARRAY_SIZE(mdm9615_dai_delta_tabla)];
1119
1120static struct snd_soc_card snd_soc_card_mdm9615 = {
1121 .name = "mdm9615-tabla-snd-card",
1122 .dai_link = mdm9615_dai,
1123 .num_links = ARRAY_SIZE(mdm9615_dai),
1124};
1125
1126static struct platform_device *mdm9615_snd_device;
1127
1128static int mdm9615_configure_headset_mic_gpios(void)
1129{
1130 int ret;
1131 struct pm_gpio param = {
1132 .direction = PM_GPIO_DIR_OUT,
1133 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1134 .output_value = 1,
1135 .pull = PM_GPIO_PULL_NO,
1136 .vin_sel = PM_GPIO_VIN_S4,
1137 .out_strength = PM_GPIO_STRENGTH_MED,
1138 .function = PM_GPIO_FUNC_NORMAL,
1139 };
1140
1141 ret = gpio_request(PM8018_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1142 if (ret) {
1143 pr_err("%s: Failed to request gpio %d\n", __func__,
1144 PM8018_GPIO_PM_TO_SYS(23));
1145 return ret;
1146 }
1147
1148 ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(23), &param);
1149 if (ret)
1150 pr_err("%s: Failed to configure gpio %d\n", __func__,
1151 PM8018_GPIO_PM_TO_SYS(23));
1152 else
1153 gpio_direction_output(PM8018_GPIO_PM_TO_SYS(23), 0);
1154
1155 ret = gpio_request(PM8018_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1156 if (ret) {
1157 pr_err("%s: Failed to request gpio %d\n", __func__,
1158 PM8018_GPIO_PM_TO_SYS(35));
1159 gpio_free(PM8018_GPIO_PM_TO_SYS(23));
1160 return ret;
1161 }
1162 ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(35), &param);
1163 if (ret)
1164 pr_err("%s: Failed to configure gpio %d\n", __func__,
1165 PM8018_GPIO_PM_TO_SYS(35));
1166 else
1167 gpio_direction_output(PM8018_GPIO_PM_TO_SYS(35), 0);
1168
1169 return 0;
1170}
1171static void mdm9615_free_headset_mic_gpios(void)
1172{
1173 if (mdm9615_headset_gpios_configured) {
1174 gpio_free(PM8018_GPIO_PM_TO_SYS(23));
1175 gpio_free(PM8018_GPIO_PM_TO_SYS(35));
1176 }
1177}
1178
1179static int __init mdm9615_audio_init(void)
1180{
1181 int ret;
1182
1183 if (!cpu_is_msm9615()) {
1184 pr_err("%s: Not the right machine type\n", __func__);
1185 return -ENODEV ;
1186 }
1187
1188 tabla_mbhc_cal = def_tabla_mbhc_cal();
1189 if (!tabla_mbhc_cal) {
1190 pr_err("Calibration data allocation failed\n");
1191 return -ENOMEM;
1192 }
1193
1194 mdm9615_snd_device = platform_device_alloc("soc-audio", 0);
1195 if (!mdm9615_snd_device) {
1196 pr_err("Platform device allocation failed\n");
1197 kfree(tabla_mbhc_cal);
1198 return -ENOMEM;
1199 }
1200
1201 memcpy(mdm9615_dai, mdm9615_dai_common, sizeof(mdm9615_dai_common));
1202 memcpy(mdm9615_dai + ARRAY_SIZE(mdm9615_dai_common),
1203 mdm9615_dai_delta_tabla, sizeof(mdm9615_dai_delta_tabla));
1204
1205 platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
1206 ret = platform_device_add(mdm9615_snd_device);
1207 if (ret) {
1208 platform_device_put(mdm9615_snd_device);
1209 kfree(tabla_mbhc_cal);
1210 return ret;
1211 }
1212
1213 if (mdm9615_configure_headset_mic_gpios()) {
1214 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1215 mdm9615_headset_gpios_configured = 0;
1216 } else
1217 mdm9615_headset_gpios_configured = 1;
1218
1219 return ret;
1220
1221}
1222module_init(mdm9615_audio_init);
1223
1224static void __exit mdm9615_audio_exit(void)
1225{
1226 if (!cpu_is_msm9615()) {
1227 pr_err("%s: Not the right machine type\n", __func__);
1228 return ;
1229 }
1230 mdm9615_free_headset_mic_gpios();
1231 platform_device_unregister(mdm9615_snd_device);
1232 kfree(tabla_mbhc_cal);
1233}
1234module_exit(mdm9615_audio_exit);
1235
1236MODULE_DESCRIPTION("ALSA SoC MDM9615");
1237MODULE_LICENSE("GPL v2");