blob: 23283b51eb983fe9155ad7e59aeac69f6efadb4d [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/clk.h>
Kiran Kandidb0a4b02011-08-23 09:32:09 -070014#include <linux/delay.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/gpio.h>
16#include <linux/mfd/pm8xxx/pm8921.h>
17#include <linux/platform_device.h>
18#include <linux/gpio.h>
19#include <linux/mfd/pm8xxx/pm8921.h>
20#include <sound/core.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <sound/soc-dsp.h>
24#include <sound/pcm.h>
25#include <sound/jack.h>
Bradley Rubin229c6a52011-07-12 16:18:48 -070026#include <asm/mach-types.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include "msm-pcm-routing.h"
28#include <../codecs/wcd9310.h>
29
30/* 8960 machine driver */
31
32#define PM8921_GPIO_BASE NR_GPIO_IRQS
33#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
34
Kiran Kandidb0a4b02011-08-23 09:32:09 -070035#define TOP_SPK_PAMP (PM8921_GPIO_PM_TO_SYS(18))
36#define BOTTOM_SPK_PAMP (PM8921_GPIO_PM_TO_SYS(19))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037#define MSM8960_SPK_ON 1
38#define MSM8960_SPK_OFF 0
39
40#define msm8960_SLIM_0_RX_MAX_CHANNELS 2
41#define msm8960_SLIM_0_TX_MAX_CHANNELS 4
42
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070043#define BTSCO_RATE_8KHZ 8000
44#define BTSCO_RATE_16KHZ 16000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045
46static int msm8960_spk_control;
Kiran Kandidb0a4b02011-08-23 09:32:09 -070047static int msm8960_bottom_spk_pamp_on;
48static int msm8960_top_spk_pamp_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049static int msm8960_slim_0_rx_ch = 1;
50static int msm8960_slim_0_tx_ch = 1;
51
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -070052static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
53static int msm8960_btsco_ch = 1;
54
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055struct tabla_mbhc_calibration tabla_cal = {
56 .bias = TABLA_MICBIAS2,
57 .tldoh = 100,
58 .bg_fast_settle = 100,
59 .mic_current = TABLA_PID_MIC_5_UA,
60 .mic_pid = 100,
61 .hph_current = TABLA_PID_MIC_5_UA,
62 .setup_plug_removal_delay = 1000000,
63 .shutdown_plug_removal = 100000,
64};
65
66static struct clk *codec_clk;
67static int clk_users;
68
69static int msm8960_headset_gpios_configured;
70
71static struct snd_soc_jack hs_jack;
Bradley Rubincb1e2732011-06-23 16:49:20 -070072static struct snd_soc_jack button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073
Kiran Kandidb0a4b02011-08-23 09:32:09 -070074static void codec_poweramp_on(int bottom_spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075{
76 int ret = 0;
77
78 struct pm_gpio param = {
79 .direction = PM_GPIO_DIR_OUT,
80 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
81 .output_value = 1,
82 .pull = PM_GPIO_PULL_NO,
83 .vin_sel = PM_GPIO_VIN_S4,
84 .out_strength = PM_GPIO_STRENGTH_MED,
85 .function = PM_GPIO_FUNC_NORMAL,
86 };
87
Kiran Kandidb0a4b02011-08-23 09:32:09 -070088 if (bottom_spk) {
89 if (msm8960_bottom_spk_pamp_on)
90 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091
Kiran Kandidb0a4b02011-08-23 09:32:09 -070092 ret = gpio_request(BOTTOM_SPK_PAMP, "BOTTOM_SPK_AMP");
93 if (ret) {
94 pr_err("%s: Error requesting GPIO %d\n", __func__,
95 BOTTOM_SPK_PAMP);
96 return;
97 }
98 ret = pm8xxx_gpio_config(BOTTOM_SPK_PAMP, &param);
99 if (ret)
100 pr_err("%s: Failed to configure gpio %d\n", __func__,
101 BOTTOM_SPK_PAMP);
102 else {
103 pr_debug("%s: enable Bottom spkr amp\n", __func__);
104 gpio_direction_output(BOTTOM_SPK_PAMP, 1);
105 msm8960_bottom_spk_pamp_on = 1;
106 }
107
108 } else {
109 if (msm8960_top_spk_pamp_on)
110 return;
111
112 ret = gpio_request(TOP_SPK_PAMP, "TOP_SPK_AMP");
113 if (ret) {
114 pr_err("%s: Error requesting GPIO %d\n", __func__,
115 TOP_SPK_PAMP);
116 return;
117 }
118 ret = pm8xxx_gpio_config(TOP_SPK_PAMP, &param);
119 if (ret)
120 pr_err("%s: Failed to configure gpio %d\n", __func__,
121 TOP_SPK_PAMP);
122 else {
123 pr_debug("%s: enable Top spkr amp\n", __func__);
124 gpio_direction_output(TOP_SPK_PAMP, 1);
125 msm8960_top_spk_pamp_on = 1;
126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 }
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700128 pr_debug("%s: slepping 4 ms", __func__);
129 usleep_range(4000, 4000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700131
132static void codec_poweramp_off(int bottom_spk)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133{
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700134 if (bottom_spk) {
135 if (!msm8960_bottom_spk_pamp_on)
136 return;
137 pr_debug("%s: disable Bottom spkr amp\n", __func__);
138 gpio_direction_output(BOTTOM_SPK_PAMP, 0);
139 gpio_free(BOTTOM_SPK_PAMP);
140 msm8960_bottom_spk_pamp_on = 0;
141 } else {
142 if (!msm8960_top_spk_pamp_on)
143 return;
144 pr_debug("%s: disable To spkr amp\n", __func__);
145 gpio_direction_output(TOP_SPK_PAMP, 0);
146 gpio_free(TOP_SPK_PAMP);
147 msm8960_top_spk_pamp_on = 0;
148 }
149 pr_debug("%s: slepping 4 ms", __func__);
150 usleep_range(4000, 4000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151}
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153static void msm8960_ext_control(struct snd_soc_codec *codec)
154{
155 struct snd_soc_dapm_context *dapm = &codec->dapm;
156
157 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
158 if (msm8960_spk_control == MSM8960_SPK_ON)
159 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
160 else
161 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
162
163 snd_soc_dapm_sync(dapm);
164}
165
166static int msm8960_get_spk(struct snd_kcontrol *kcontrol,
167 struct snd_ctl_elem_value *ucontrol)
168{
169 pr_debug("%s: msm8960_spk_control = %d", __func__, msm8960_spk_control);
170 ucontrol->value.integer.value[0] = msm8960_spk_control;
171 return 0;
172}
173static int msm8960_set_spk(struct snd_kcontrol *kcontrol,
174 struct snd_ctl_elem_value *ucontrol)
175{
176 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
177
178 pr_debug("%s()\n", __func__);
179 if (msm8960_spk_control == ucontrol->value.integer.value[0])
180 return 0;
181
182 msm8960_spk_control = ucontrol->value.integer.value[0];
183 msm8960_ext_control(codec);
184 return 1;
185}
186static int msm8960_spkramp_event(struct snd_soc_dapm_widget *w,
187 struct snd_kcontrol *k, int event)
188{
189 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700190
191 if (SND_SOC_DAPM_EVENT_ON(event)) {
192 if (!strncmp(w->name, "Ext Spk Bottom", 14))
193 codec_poweramp_on(1);
194 else
195 codec_poweramp_on(0);
196 } else {
197 if (!strncmp(w->name, "Ext Spk Bottom", 14))
198 codec_poweramp_off(1);
199 else
200 codec_poweramp_off(0);
201 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 return 0;
203}
204
205static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700206
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700207 SND_SOC_DAPM_SPK("Ext Spk Bottom", msm8960_spkramp_event),
208 SND_SOC_DAPM_SPK("Ext Spk Top", msm8960_spkramp_event),
Kiran Kandi3a30bda2011-08-15 10:36:42 -0700209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210 SND_SOC_DAPM_MIC("Handset Mic", NULL),
211 SND_SOC_DAPM_MIC("Headset Mic", NULL),
212 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700213 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
214 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700215
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700216 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700217 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700218 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700219 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700220 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
221 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223};
224
Bradley Rubin229c6a52011-07-12 16:18:48 -0700225static const struct snd_soc_dapm_route common_audio_map[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226 /* Speaker path */
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700227
228 {"Ext Spk Bottom", NULL, "LINEOUT1"},
229 {"Ext Spk Bottom", NULL, "LINEOUT3"},
230
231 {"Ext Spk Top", NULL, "LINEOUT2"},
232 {"Ext Spk Top", NULL, "LINEOUT4"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233
234 /* Microphone path */
Bradley Rubin229c6a52011-07-12 16:18:48 -0700235 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
236 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700237
238 {"AMIC2", NULL, "MIC BIAS2 External"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 {"MIC BIAS2 External", NULL, "Headset Mic"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700240
Kiran Kandie9bf86a2011-07-21 16:50:41 -0700241 {"HEADPHONE", NULL, "LDO_H"},
242
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700243 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700244 * The digital Mic routes are setup considering
245 * fluid as default device.
246 */
247
248 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700249 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700250 * Digital Mic GM5 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700251 * Conncted to DMIC2 Input on Tabla codec.
252 */
253 {"DMIC2", NULL, "MIC BIAS1 External"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700254 {"MIC BIAS1 External", NULL, "Digital Mic1"},
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700255
256 /**
257 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700258 * Digital Mic GM6 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700259 * Conncted to DMIC1 Input on Tabla codec.
260 */
261 {"DMIC1", NULL, "MIC BIAS1 External"},
262 {"MIC BIAS1 External", NULL, "Digital Mic2"},
263
264 /**
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700265 * Digital Mic3. Back Bottom Digital Mic on Fluid.
266 * Digital Mic GM1 on CDP mainboard.
267 * Conncted to DMIC4 Input on Tabla codec.
268 */
269 {"DMIC4", NULL, "MIC BIAS3 External"},
270 {"MIC BIAS3 External", NULL, "Digital Mic3"},
271
272 /**
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700273 * Digital Mic4. Back top Digital Mic on Fluid.
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700274 * Digital Mic GM2 on CDP mainboard.
Kiran Kandia21d6bc2011-07-17 21:19:59 -0700275 * Conncted to DMIC3 Input on Tabla codec.
276 */
277 {"DMIC3", NULL, "MIC BIAS3 External"},
278 {"MIC BIAS3 External", NULL, "Digital Mic4"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700279
280 /**
281 * Digital Mic5. Front top Digital Mic on Fluid.
282 * Digital Mic GM3 on CDP mainboard.
283 * Conncted to DMIC5 Input on Tabla codec.
284 */
285 {"DMIC5", NULL, "MIC BIAS4 External"},
286 {"MIC BIAS4 External", NULL, "Digital Mic5"},
287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288};
289
Bradley Rubin229c6a52011-07-12 16:18:48 -0700290static const struct snd_soc_dapm_route cdp_audio_map[] = {
291 {"AMIC3", NULL, "MIC BIAS3 External"},
292 {"MIC BIAS3 External", NULL, "ANCRight Headset Mic"},
293
294 {"AMIC4", NULL, "MIC BIAS4 External"},
295 {"MIC BIAS4 External", NULL, "ANCLeft Headset Mic"},
Bhalchandra Gajarea0101ba2011-08-11 20:05:56 -0700296
297 /** Digital Mic GM4 on CDP mainboard.
298 * Connected to DMIC6 input on Tabla codec.
299 */
300 {"DMIC6", NULL, "MIC BIAS4 External"},
301 {"MIC BIAS4 External", NULL, "Digital Mic6"},
302
Bradley Rubin229c6a52011-07-12 16:18:48 -0700303};
304
305static const struct snd_soc_dapm_route fluid_audio_map[] = {
306 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
307 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
308
309 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
310 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
311};
312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313static const char *spk_function[] = {"Off", "On"};
Patrick Lai9f4b4292011-07-16 22:11:09 -0700314static const char *slim0_rx_ch_text[] = {"One", "Two"};
315static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317static const struct soc_enum msm8960_enum[] = {
318 SOC_ENUM_SINGLE_EXT(2, spk_function),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700319 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
320 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321};
322
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700323static const char *btsco_rate_text[] = {"8000", "16000"};
324static const struct soc_enum msm8960_btsco_enum[] = {
325 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
326};
327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
329 struct snd_ctl_elem_value *ucontrol)
330{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700331 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 msm8960_slim_0_rx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700333 ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 return 0;
335}
336
337static int msm8960_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
338 struct snd_ctl_elem_value *ucontrol)
339{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700340 msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341
Patrick Lai9f4b4292011-07-16 22:11:09 -0700342 pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 msm8960_slim_0_rx_ch);
344 return 1;
345}
346
347static int msm8960_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
348 struct snd_ctl_elem_value *ucontrol)
349{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700350 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 msm8960_slim_0_tx_ch);
Patrick Lai9f4b4292011-07-16 22:11:09 -0700352 ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 return 0;
354}
355
356static int msm8960_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
357 struct snd_ctl_elem_value *ucontrol)
358{
Patrick Lai9f4b4292011-07-16 22:11:09 -0700359 msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360
361 pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
362 msm8960_slim_0_tx_ch);
363 return 1;
364}
365
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700366static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
367 struct snd_ctl_elem_value *ucontrol)
368{
369 pr_debug("%s: msm8960_btsco_rate = %d", __func__,
370 msm8960_btsco_rate);
371 ucontrol->value.integer.value[0] = msm8960_btsco_rate;
372 return 0;
373}
374
375static int msm8960_btsco_rate_put(struct snd_kcontrol *kcontrol,
376 struct snd_ctl_elem_value *ucontrol)
377{
378 switch (ucontrol->value.integer.value[0]) {
379 case 0:
380 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
381 break;
382 case 1:
383 msm8960_btsco_rate = BTSCO_RATE_16KHZ;
384 break;
385 default:
386 msm8960_btsco_rate = BTSCO_RATE_8KHZ;
387 break;
388 }
389 pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
390 msm8960_btsco_rate);
391 return 0;
392}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393
394static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
395 SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
396 msm8960_set_spk),
Patrick Lai9f4b4292011-07-16 22:11:09 -0700397 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8960_enum[1],
398 msm8960_slim_0_rx_ch_get, msm8960_slim_0_rx_ch_put),
399 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8960_enum[2],
400 msm8960_slim_0_tx_ch_get, msm8960_slim_0_tx_ch_put),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401};
402
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700403static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
404 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8960_btsco_enum[0],
405 msm8960_btsco_rate_get, msm8960_btsco_rate_put),
406};
407
408static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
409{
410 int err = 0;
411 struct snd_soc_platform *platform = rtd->platform;
412
413 err = snd_soc_add_platform_controls(platform,
414 int_btsco_rate_mixer_controls,
415 ARRAY_SIZE(int_btsco_rate_mixer_controls));
416 if (err < 0)
417 return err;
418 return 0;
419}
420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
422{
423 int err;
424 struct snd_soc_codec *codec = rtd->codec;
425 struct snd_soc_dapm_context *dapm = &codec->dapm;
426
427 pr_debug("%s()\n", __func__);
428
429 err = snd_soc_add_controls(codec, tabla_msm8960_controls,
430 ARRAY_SIZE(tabla_msm8960_controls));
431 if (err < 0)
432 return err;
433
434 snd_soc_dapm_new_controls(dapm, msm8960_dapm_widgets,
435 ARRAY_SIZE(msm8960_dapm_widgets));
436
Bradley Rubin229c6a52011-07-12 16:18:48 -0700437 snd_soc_dapm_add_routes(dapm, common_audio_map,
438 ARRAY_SIZE(common_audio_map));
439
440 if (machine_is_msm8960_cdp())
441 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
442 ARRAY_SIZE(cdp_audio_map));
443 else if (machine_is_msm8960_mtp())
444 snd_soc_dapm_add_routes(dapm, cdp_audio_map,
445 ARRAY_SIZE(cdp_audio_map));
446 else if (machine_is_msm8960_fluid())
447 snd_soc_dapm_add_routes(dapm, fluid_audio_map,
448 ARRAY_SIZE(fluid_audio_map));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449
450 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
451
452 snd_soc_dapm_sync(dapm);
453
454 err = snd_soc_jack_new(codec, "Headset Jack",
455 SND_JACK_HEADSET, &hs_jack);
456 if (err) {
457 pr_err("failed to create new jack\n");
458 return err;
459 }
Bradley Rubincb1e2732011-06-23 16:49:20 -0700460
461 err = snd_soc_jack_new(codec, "Button Jack",
462 SND_JACK_BTN_0, &button_jack);
463 if (err) {
464 pr_err("failed to create new jack\n");
465 return err;
466 }
467
468 tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469
470 return 0;
471}
472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473static struct snd_soc_dsp_link lpa_fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700474 .playback = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 .trigger = {
476 SND_SOC_DSP_TRIGGER_POST,
477 SND_SOC_DSP_TRIGGER_POST
478 },
479};
480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481static struct snd_soc_dsp_link fe_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700482 .playback = true,
483 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 .trigger = {
485 SND_SOC_DSP_TRIGGER_POST,
486 SND_SOC_DSP_TRIGGER_POST
487 },
488};
489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490static struct snd_soc_dsp_link slimbus0_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700491 .playback = true,
492 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 .trigger = {
494 SND_SOC_DSP_TRIGGER_POST,
495 SND_SOC_DSP_TRIGGER_POST
496 },
497};
498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499static struct snd_soc_dsp_link int_fm_hl_media = {
Patrick Lai5b3fdfc2011-09-01 11:04:56 -0700500 .playback = true,
501 .capture = true,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 .trigger = {
503 SND_SOC_DSP_TRIGGER_POST,
504 SND_SOC_DSP_TRIGGER_POST
505 },
506};
507
508static int msm8960_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
509 struct snd_pcm_hw_params *params)
510{
511 struct snd_interval *rate = hw_param_interval(params,
512 SNDRV_PCM_HW_PARAM_RATE);
513
514 struct snd_interval *channels = hw_param_interval(params,
515 SNDRV_PCM_HW_PARAM_CHANNELS);
516
517 pr_debug("%s()\n", __func__);
518 rate->min = rate->max = 48000;
519 channels->min = channels->max = msm8960_slim_0_rx_ch;
520
521 return 0;
522}
523
524static int msm8960_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
525 struct snd_pcm_hw_params *params)
526{
527 struct snd_interval *rate = hw_param_interval(params,
528 SNDRV_PCM_HW_PARAM_RATE);
529
530 struct snd_interval *channels = hw_param_interval(params,
531 SNDRV_PCM_HW_PARAM_CHANNELS);
532
533 pr_debug("%s()\n", __func__);
534 rate->min = rate->max = 48000;
535 channels->min = channels->max = msm8960_slim_0_tx_ch;
536
537 return 0;
538}
539
540static int msm8960_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
541 struct snd_pcm_hw_params *params)
542{
543 struct snd_interval *rate = hw_param_interval(params,
544 SNDRV_PCM_HW_PARAM_RATE);
545
546 pr_debug("%s()\n", __func__);
547 rate->min = rate->max = 48000;
548
549 return 0;
550}
551
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700552static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
553 struct snd_pcm_hw_params *params)
554{
555 struct snd_interval *rate = hw_param_interval(params,
556 SNDRV_PCM_HW_PARAM_RATE);
557
558 struct snd_interval *channels = hw_param_interval(params,
559 SNDRV_PCM_HW_PARAM_CHANNELS);
560
561 rate->min = rate->max = msm8960_btsco_rate;
562 channels->min = channels->max = msm8960_btsco_ch;
563
564 return 0;
565}
566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567static int msm8960_startup(struct snd_pcm_substream *substream)
568{
Sriranjan Srikantam8912c382011-09-12 12:20:57 -0700569 if (clk_users++)
570 return 0;
571
572 codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
573 if (codec_clk) {
574 clk_set_rate(codec_clk, 12288000);
575 clk_enable(codec_clk);
576 } else {
577 pr_err("%s: Error setting Tabla MCLK\n", __func__);
578 clk_users--;
579 return -EINVAL;
580 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 return 0;
582}
583
584static void msm8960_shutdown(struct snd_pcm_substream *substream)
585{
Sriranjan Srikantam8912c382011-09-12 12:20:57 -0700586 clk_users--;
587 if (!clk_users) {
588 clk_disable(codec_clk);
589 clk_put(codec_clk);
590 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591}
592
593static struct snd_soc_ops msm8960_be_ops = {
594 .startup = msm8960_startup,
595 .shutdown = msm8960_shutdown,
596};
597
598/* Digital audio interface glue - connects codec <---> CPU */
599static struct snd_soc_dai_link msm8960_dai[] = {
600 /* FrontEnd DAI Links */
601 {
602 .name = "MSM8960 Media1",
603 .stream_name = "MultiMedia1",
604 .cpu_dai_name = "MultiMedia1",
605 .platform_name = "msm-pcm-dsp",
606 .dynamic = 1,
607 .dsp_link = &fe_media,
608 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
609 },
610 {
611 .name = "MSM8960 Media2",
612 .stream_name = "MultiMedia2",
613 .cpu_dai_name = "MultiMedia2",
614 .platform_name = "msm-pcm-dsp",
615 .dynamic = 1,
616 .dsp_link = &fe_media,
617 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
618 },
619 {
620 .name = "Circuit-Switch Voice",
621 .stream_name = "CS-Voice",
622 .cpu_dai_name = "CS-VOICE",
623 .platform_name = "msm-pcm-voice",
624 .dynamic = 1,
625 .dsp_link = &fe_media,
626 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
627 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
628 },
629 {
630 .name = "MSM VoIP",
631 .stream_name = "VoIP",
632 .cpu_dai_name = "VoIP",
633 .platform_name = "msm-voip-dsp",
634 .dynamic = 1,
635 .dsp_link = &fe_media,
636 .be_id = MSM_FRONTEND_DAI_VOIP,
637 },
638 {
639 .name = "MSM8960 LPA",
640 .stream_name = "LPA",
641 .cpu_dai_name = "MultiMedia3",
642 .platform_name = "msm-pcm-lpa",
643 .dynamic = 1,
644 .dsp_link = &lpa_fe_media,
645 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
646 },
647 /* Hostless PMC purpose */
648 {
649 .name = "SLIMBUS_0 Hostless",
650 .stream_name = "SLIMBUS_0 Hostless",
651 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
652 .platform_name = "msm-pcm-hostless",
653 .dynamic = 1,
654 .dsp_link = &slimbus0_hl_media,
655 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
656 /* .be_id = do not care */
657 },
658 {
659 .name = "INT_FM Hostless",
660 .stream_name = "INT_FM Hostless",
661 .cpu_dai_name = "INT_FM_HOSTLESS",
662 .platform_name = "msm-pcm-hostless",
663 .dynamic = 1,
664 .dsp_link = &int_fm_hl_media,
665 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
666 /* .be_id = do not care */
667 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530668 {
669 .name = "MSM AFE-PCM RX",
670 .stream_name = "AFE-PROXY RX",
671 .cpu_dai_name = "msm-dai-q6.241",
672 .codec_name = "msm-stub-codec.1",
673 .codec_dai_name = "msm-stub-rx",
674 .platform_name = "msm-pcm-afe",
675 },
676 {
677 .name = "MSM AFE-PCM TX",
678 .stream_name = "AFE-PROXY TX",
679 .cpu_dai_name = "msm-dai-q6.240",
680 .codec_name = "msm-stub-codec.1",
681 .codec_dai_name = "msm-stub-tx",
682 .platform_name = "msm-pcm-afe",
683 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684 /* Backend DAI Links */
685 {
686 .name = LPASS_BE_SLIMBUS_0_RX,
687 .stream_name = "Slimbus Playback",
688 .cpu_dai_name = "msm-dai-q6.16384",
689 .platform_name = "msm-pcm-routing",
690 .codec_name = "tabla_codec",
691 .codec_dai_name = "tabla_rx1",
692 .no_pcm = 1,
693 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
694 .init = &msm8960_audrx_init,
695 .be_hw_params_fixup = msm8960_slim_0_rx_be_hw_params_fixup,
696 .ops = &msm8960_be_ops,
697 },
698 {
699 .name = LPASS_BE_SLIMBUS_0_TX,
700 .stream_name = "Slimbus Capture",
701 .cpu_dai_name = "msm-dai-q6.16385",
702 .platform_name = "msm-pcm-routing",
703 .codec_name = "tabla_codec",
704 .codec_dai_name = "tabla_tx1",
705 .no_pcm = 1,
706 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
707 .be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
708 .ops = &msm8960_be_ops,
709 },
710 /* Backend BT/FM DAI Links */
711 {
712 .name = LPASS_BE_INT_BT_SCO_RX,
713 .stream_name = "Internal BT-SCO Playback",
714 .cpu_dai_name = "msm-dai-q6.12288",
715 .platform_name = "msm-pcm-routing",
716 .codec_name = "msm-stub-codec.1",
717 .codec_dai_name = "msm-stub-rx",
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700718 .init = &msm8960_btsco_init,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 .no_pcm = 1,
720 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700721 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 },
723 {
724 .name = LPASS_BE_INT_BT_SCO_TX,
725 .stream_name = "Internal BT-SCO Capture",
726 .cpu_dai_name = "msm-dai-q6.12289",
727 .platform_name = "msm-pcm-routing",
728 .codec_name = "msm-stub-codec.1",
729 .codec_dai_name = "msm-stub-tx",
730 .no_pcm = 1,
731 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
Jayasena Sangaraboina47c08242011-08-10 11:30:57 -0700732 .be_hw_params_fixup = msm8960_btsco_be_hw_params_fixup,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 },
734 {
735 .name = LPASS_BE_INT_FM_RX,
736 .stream_name = "Internal FM Playback",
737 .cpu_dai_name = "msm-dai-q6.12292",
738 .platform_name = "msm-pcm-routing",
739 .codec_name = "msm-stub-codec.1",
740 .codec_dai_name = "msm-stub-rx",
741 .no_pcm = 1,
742 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
743 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
744 },
745 {
746 .name = LPASS_BE_INT_FM_TX,
747 .stream_name = "Internal FM Capture",
748 .cpu_dai_name = "msm-dai-q6.12293",
749 .platform_name = "msm-pcm-routing",
750 .codec_name = "msm-stub-codec.1",
751 .codec_dai_name = "msm-stub-tx",
752 .no_pcm = 1,
753 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
754 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
755 },
756 /* HDMI BACK END DAI Link */
757 {
758 .name = LPASS_BE_HDMI,
759 .stream_name = "HDMI Playback",
760 .cpu_dai_name = "msm-dai-q6.8",
761 .platform_name = "msm-pcm-routing",
762 .codec_name = "msm-stub-codec.1",
763 .codec_dai_name = "msm-stub-rx",
764 .no_pcm = 1,
765 .no_codec = 1,
766 .be_id = MSM_BACKEND_DAI_HDMI_RX,
767 .be_hw_params_fixup = msm8960_be_hw_params_fixup,
768 },
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530769 /* Backend AFE DAI Links */
770 {
771 .name = LPASS_BE_AFE_PCM_RX,
772 .stream_name = "AFE Playback",
773 .cpu_dai_name = "msm-dai-q6.224",
774 .platform_name = "msm-pcm-routing",
775 .codec_name = "msm-stub-codec.1",
776 .codec_dai_name = "msm-stub-rx",
777 .no_codec = 1,
778 .no_pcm = 1,
779 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
780 },
781 {
782 .name = LPASS_BE_AFE_PCM_TX,
783 .stream_name = "AFE Capture",
784 .cpu_dai_name = "msm-dai-q6.225",
785 .platform_name = "msm-pcm-routing",
786 .codec_name = "msm-stub-codec.1",
787 .codec_dai_name = "msm-stub-tx",
788 .no_codec = 1,
789 .no_pcm = 1,
790 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
791 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792};
793
794struct snd_soc_card snd_soc_card_msm8960 = {
795 .name = "msm8960-snd-card",
796 .dai_link = msm8960_dai,
797 .num_links = ARRAY_SIZE(msm8960_dai),
798};
799
800static struct platform_device *msm8960_snd_device;
801
802static int msm8960_configure_headset_mic_gpios(void)
803{
804 int ret;
805 struct pm_gpio param = {
806 .direction = PM_GPIO_DIR_OUT,
807 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
808 .output_value = 1,
809 .pull = PM_GPIO_PULL_NO,
810 .vin_sel = PM_GPIO_VIN_S4,
811 .out_strength = PM_GPIO_STRENGTH_MED,
812 .function = PM_GPIO_FUNC_NORMAL,
813 };
814
815 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
816 if (ret) {
817 pr_err("%s: Failed to request gpio %d\n", __func__,
818 PM8921_GPIO_PM_TO_SYS(23));
819 return ret;
820 }
821
822 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
823 if (ret)
824 pr_err("%s: Failed to configure gpio %d\n", __func__,
825 PM8921_GPIO_PM_TO_SYS(23));
826 else
827 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
828
829 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
830 if (ret) {
831 pr_err("%s: Failed to request gpio %d\n", __func__,
832 PM8921_GPIO_PM_TO_SYS(35));
833 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
834 return ret;
835 }
836 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
837 if (ret)
838 pr_err("%s: Failed to configure gpio %d\n", __func__,
839 PM8921_GPIO_PM_TO_SYS(35));
840 else
841 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 1);
842
843 return 0;
844}
845static void msm8960_free_headset_mic_gpios(void)
846{
847 if (msm8960_headset_gpios_configured) {
848 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
849 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
850 }
851}
852
853static int __init msm8960_audio_init(void)
854{
855 int ret;
856
857 msm8960_snd_device = platform_device_alloc("soc-audio", 0);
858 if (!msm8960_snd_device) {
859 pr_err("Platform device allocation failed\n");
860 return -ENOMEM;
861 }
862
863 platform_set_drvdata(msm8960_snd_device, &snd_soc_card_msm8960);
864 ret = platform_device_add(msm8960_snd_device);
865 if (ret) {
866 platform_device_put(msm8960_snd_device);
867 return ret;
868 }
869
870 if (msm8960_configure_headset_mic_gpios()) {
871 pr_err("%s Fail to configure headset mic gpios\n", __func__);
872 msm8960_headset_gpios_configured = 0;
873 } else
874 msm8960_headset_gpios_configured = 1;
875
876 return ret;
877
878}
879module_init(msm8960_audio_init);
880
881static void __exit msm8960_audio_exit(void)
882{
883 msm8960_free_headset_mic_gpios();
884 platform_device_unregister(msm8960_snd_device);
885}
886module_exit(msm8960_audio_exit);
887
888MODULE_DESCRIPTION("ALSA SoC MSM8960");
889MODULE_LICENSE("GPL v2");