blob: 5fbe3ce72d9bfe0a98d0df6b44b8893a651d2604 [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
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/platform_device.h>
19#include <linux/bitops.h>
Neema Shettyfeea7742011-09-11 12:30:36 -070020#include <linux/mutex.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <sound/core.h>
22#include <sound/soc.h>
23#include <sound/soc-dapm.h>
24#include <sound/pcm.h>
25#include <sound/initval.h>
26#include <sound/control.h>
27#include <sound/q6adm.h>
28#include <sound/q6afe.h>
Jayasena Sangaraboinacb1e22f2011-07-18 10:36:57 -070029#include <sound/tlv.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030#include "msm-pcm-routing.h"
31#include "qdsp6/q6voice.h"
32
33struct audio_mixer_data {
34 u32 port_id; /* AFE port ID for Rx, FE DAI ID for TX */
35 unsigned long dai_sessions; /* Rx: FE DAIs Tx: BE DAI */
36 u32 mixer_type; /* playback or capture */
37};
38
Neema Shettyfeea7742011-09-11 12:30:36 -070039struct msm_pcm_routing_bdai_data {
40 u16 port_id; /* AFE port ID */
41 u8 active; /* track if this backend is enabled */
42 struct snd_pcm_hw_params *hw_params; /* to get freq and channel mode */
43 unsigned long fe_sessions; /* Front-end sessions */
44 unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
45};
46
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047#define INVALID_SESSION -1
48
Neema Shettyfeea7742011-09-11 12:30:36 -070049static struct mutex routing_lock;
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051enum {
52 AUDIO_MIXER_PRI_I2S_RX = 0,
53 AUDIO_MIXER_SLIMBUS_0_RX,
54 AUDIO_MIXER_HDMI_RX,
55 AUDIO_MIXER_MM_UL1,
56 AUDIO_MIXER_INT_BT_SCO_RX,
57 AUDIO_MIXER_INT_FM_RX,
58 AUDIO_MIXER_MAX,
59};
60
61enum {
62 AUDIO_PORT_MIXER_SLIM_0_RX = 0,
63 AUDIO_PORT_MIXER_MAX,
64};
65
Sriranjan Srikantama4969dd2011-07-14 00:34:56 -070066static int fm_switch_enable;
Jayasena Sangaraboinacb1e22f2011-07-18 10:36:57 -070067#define INT_FM_RX_VOL_MAX_STEPS 100
68#define INT_FM_RX_VOL_GAIN 2000
69
70static int msm_route_fm_vol_control;
71static const DECLARE_TLV_DB_SCALE(fm_rx_vol_gain, 0,
72 INT_FM_RX_VOL_MAX_STEPS, 0);
Sriranjan Srikantama4969dd2011-07-14 00:34:56 -070073
Sriranjan Srikantam269de7f2011-09-06 18:24:45 -070074#define INT_LPA_RX_VOL_MAX_STEPS 100
75#define INT_LPA_RX_VOL_GAIN 0x2000
Asish Bhattacharya0ec76182011-07-29 16:58:11 +053076
77static int msm_route_lpa_vol_control;
78static const DECLARE_TLV_DB_SCALE(lpa_rx_vol_gain, 0,
79 INT_LPA_RX_VOL_MAX_STEPS, 0);
80
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081/* Tx mixer session is stored based on BE DAI ID
82 * Need to map to actual AFE port ID since AFE port
83 * ID can get really large.
84 * The table convert DAI back to AFE port ID
85 */
86static int bedai_port_map[MSM_BACKEND_DAI_MAX] = {
87 PRIMARY_I2S_RX,
88 PRIMARY_I2S_TX,
89 SLIMBUS_0_RX,
90 SLIMBUS_0_TX,
91 HDMI_RX,
92 INT_BT_SCO_RX,
93 INT_BT_SCO_TX,
94 INT_FM_RX,
95 INT_FM_TX,
96};
97
Neema Shettyfeea7742011-09-11 12:30:36 -070098/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
99 * If new back-end is defined, add new back-end DAI ID at the end of enum
100 */
101static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
102 { PRIMARY_I2S_RX, 0, NULL, 0, 0},
103 { PRIMARY_I2S_TX, 0, NULL, 0, 0},
104 { SLIMBUS_0_RX, 0, NULL, 0, 0},
105 { SLIMBUS_0_TX, 0, NULL, 0, 0},
106 { HDMI_RX, 0, NULL, 0, 0},
107 { INT_BT_SCO_RX, 0, NULL, 0, 0},
108 { INT_BT_SCO_TX, 0, NULL, 0, 0},
109 { INT_FM_RX, 0, NULL, 0, 0},
110 { INT_FM_TX, 0, NULL, 0, 0},
111};
112
113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114/* Track ASM playback & capture sessions of DAI */
115static int fe_dai_map[MSM_FRONTEND_DAI_MAX][2] = {
116 /* MULTIMEDIA1 */
117 {INVALID_SESSION, INVALID_SESSION},
118 /* MULTIMEDIA2 */
119 {INVALID_SESSION, INVALID_SESSION},
120 /* MULTIMEDIA3 */
121 {INVALID_SESSION, INVALID_SESSION},
122};
123
124static struct audio_mixer_data audio_mixers[AUDIO_MIXER_MAX] = {
125 /* AUDIO_MIXER_PRI_I2S_RX */
126 {PRIMARY_I2S_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
127 /* AUDIO_MIXER_SLIMBUS_0_RX */
128 {SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
129 /* AUDIO_MIXER_HDMI_RX */
130 {HDMI_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
131 /* AUDIO_MIXER_MM_UL1 */
132 {MSM_FRONTEND_DAI_MULTIMEDIA1, 0, SNDRV_PCM_STREAM_CAPTURE},
133 /* AUDIO_MIXER_INT_BT_SCO_RX */
134 {INT_BT_SCO_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
135 /* AUDIO_MIXER_INT_FM_RX */
136 {INT_FM_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
137};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138
139/* Reuse audio_mixer_data struct but ignore mixer type field
140 * unless there is use case for RX -> TX
141 */
142static struct audio_mixer_data audio_port_mixers[AUDIO_PORT_MIXER_MAX] = {
143 /* AUDIO_PORT_MIXER_SLIM_0_RX */
144 {SLIMBUS_0_RX, 0, SNDRV_PCM_STREAM_PLAYBACK},
145};
146
147void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
148{
149 int i, be_id;
150
151 if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
152 fe_dai_map[fedai_id][0] = dspst_id;
153 for (i = 0; i < AUDIO_MIXER_MAX; i++) {
154 if ((audio_mixers[i].mixer_type == stream_type) &&
155 (test_bit(fedai_id, &audio_mixers[i].dai_sessions)))
156 /* To do: multiple devices case */
157 adm_route_session(audio_mixers[i].port_id,
158 dspst_id, 1);
159 }
160 } else {
161 fe_dai_map[fedai_id][1] = dspst_id;
162 for (i = 0; i < AUDIO_MIXER_MAX; i++) {
163 if ((audio_mixers[i].mixer_type == stream_type) &&
164 (fedai_id == audio_mixers[i].port_id)) {
165 /* To-do: Handle mixing of inputs */
166 be_id = find_next_bit(
167 &audio_mixers[i].dai_sessions,
168 MSM_BACKEND_DAI_MAX, 0);
169 if (be_id < MSM_BACKEND_DAI_MAX)
170 adm_route_session(bedai_port_map[be_id],
171 dspst_id, 1);
172 else
173 pr_err("%s: no routing\n", __func__);
174 }
175 }
176 }
177}
178
179void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
180{
181 int i, be_id;
182
183 if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
184 for (i = 0; i < AUDIO_MIXER_MAX; i++) {
185 if ((audio_mixers[i].mixer_type == stream_type) &&
186 (test_bit(fedai_id, &audio_mixers[i].dai_sessions))) {
187 /* To do: multiple devices case */
188 adm_route_session(audio_mixers[i].port_id,
189 fe_dai_map[fedai_id][0], 0);
190 }
191 }
192 fe_dai_map[fedai_id][0] = INVALID_SESSION;
193 } else {
194 for (i = 0; i < AUDIO_MIXER_MAX; i++) {
195 if ((audio_mixers[i].mixer_type == stream_type) &&
196 (fedai_id == audio_mixers[i].port_id)) {
197 /* To-do: Handle mixing of inputs */
198 be_id = find_next_bit(
199 &audio_mixers[i].dai_sessions,
200 MSM_BACKEND_DAI_MAX, 0);
201 if (be_id < MSM_BACKEND_DAI_MAX)
202 adm_route_session(bedai_port_map[be_id],
203 fe_dai_map[fedai_id][1], 0);
204 else
205 pr_err("%s: no routing\n", __func__);
206 }
207 }
208 fe_dai_map[fedai_id][1] = INVALID_SESSION;
209 }
210}
211
212static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
213{
214
215 pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
216
217 if (set)
218 set_bit(val, &audio_mixers[reg].dai_sessions);
219 else
220 clear_bit(val, &audio_mixers[reg].dai_sessions);
221
222 if (audio_mixers[reg].mixer_type == SNDRV_PCM_STREAM_PLAYBACK) {
223 if (fe_dai_map[val][0] != INVALID_SESSION)
224 adm_route_session(audio_mixers[reg].port_id,
225 fe_dai_map[val][0], set);
226 } else {
227 int fe_id = audio_mixers[reg].port_id;
228 if (fe_dai_map[fe_id][1] != INVALID_SESSION)
229 adm_route_session(bedai_port_map[val],
230 fe_dai_map[fe_id][1], set);
231 }
232}
233
234static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
235 struct snd_ctl_elem_value *ucontrol)
236{
237 struct soc_mixer_control *mc =
238 (struct soc_mixer_control *)kcontrol->private_value;
239
240 if (test_bit(mc->shift, &audio_mixers[mc->reg].dai_sessions))
241 ucontrol->value.integer.value[0] = 1;
242 else
243 ucontrol->value.integer.value[0] = 0;
244
245 pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
246 ucontrol->value.integer.value[0]);
247
248 return 0;
249}
250
251static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
252 struct snd_ctl_elem_value *ucontrol)
253{
Patrick Laiec2b8942011-09-01 11:01:51 -0700254 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
255 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 struct soc_mixer_control *mc =
257 (struct soc_mixer_control *)kcontrol->private_value;
258
259
260 if (ucontrol->value.integer.value[0]) {
261 msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
262 snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
263 } else {
264 msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
265 snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
266 }
267
268 return 1;
269}
270
Neema Shettyfeea7742011-09-11 12:30:36 -0700271static void msm_pcm_routing_process_voice(u16 reg, u16 val, int set)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272{
Neema Shetty2c07eb52011-08-21 20:33:52 -0700273 u16 session_id = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274
Neema Shettyfeea7742011-09-11 12:30:36 -0700275 pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
Neema Shetty2c07eb52011-08-21 20:33:52 -0700276
Neema Shettyfeea7742011-09-11 12:30:36 -0700277 if (val == MSM_FRONTEND_DAI_CS_VOICE)
Neema Shetty2c07eb52011-08-21 20:33:52 -0700278 session_id = voc_get_session_id(VOICE_SESSION_NAME);
279 else
280 session_id = voc_get_session_id(VOIP_SESSION_NAME);
281
282 pr_debug("%s: FE DAI 0x%x session_id 0x%x\n",
Neema Shettyfeea7742011-09-11 12:30:36 -0700283 __func__, val, session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284
Neema Shettyfeea7742011-09-11 12:30:36 -0700285 mutex_lock(&routing_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286
287 if (set)
Neema Shettyfeea7742011-09-11 12:30:36 -0700288 set_bit(val, &msm_bedais[reg].fe_sessions);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 else
Neema Shettyfeea7742011-09-11 12:30:36 -0700290 clear_bit(val, &msm_bedais[reg].fe_sessions);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291
Neema Shettyfeea7742011-09-11 12:30:36 -0700292 mutex_unlock(&routing_lock);
293
294 if (afe_get_port_type(msm_bedais[reg].port_id) ==
295 MSM_AFE_PORT_TYPE_RX) {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700296 voc_set_route_flag(session_id, RX_PATH, set);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 if (set) {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700298 voc_set_rxtx_port(session_id,
Neema Shettyfeea7742011-09-11 12:30:36 -0700299 msm_bedais[reg].port_id, DEV_RX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300
Neema Shetty2c07eb52011-08-21 20:33:52 -0700301 if (voc_get_route_flag(session_id, RX_PATH) &&
302 voc_get_route_flag(session_id, TX_PATH))
303 voc_enable_cvp(session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 } else {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700305 voc_disable_cvp(session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306 }
307 } else {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700308 voc_set_route_flag(session_id, TX_PATH, set);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 if (set) {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700310 voc_set_rxtx_port(session_id,
Neema Shettyfeea7742011-09-11 12:30:36 -0700311 msm_bedais[reg].port_id, DEV_TX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312
Neema Shetty2c07eb52011-08-21 20:33:52 -0700313 if (voc_get_route_flag(session_id, RX_PATH) &&
314 voc_get_route_flag(session_id, TX_PATH))
315 voc_enable_cvp(session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 } else {
Neema Shetty2c07eb52011-08-21 20:33:52 -0700317 voc_disable_cvp(session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 }
319 }
320}
321
322static int msm_routing_get_voice_mixer(struct snd_kcontrol *kcontrol,
323 struct snd_ctl_elem_value *ucontrol)
324{
325 struct soc_mixer_control *mc =
326 (struct soc_mixer_control *)kcontrol->private_value;
327
Neema Shettyfeea7742011-09-11 12:30:36 -0700328 mutex_lock(&routing_lock);
329
330 if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 ucontrol->value.integer.value[0] = 1;
332 else
333 ucontrol->value.integer.value[0] = 0;
334
Neema Shettyfeea7742011-09-11 12:30:36 -0700335 mutex_unlock(&routing_lock);
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
338 ucontrol->value.integer.value[0]);
339
340 return 0;
341}
342
343static int msm_routing_put_voice_mixer(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_value *ucontrol)
345{
Patrick Laiec2b8942011-09-01 11:01:51 -0700346 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
347 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 struct soc_mixer_control *mc =
349 (struct soc_mixer_control *)kcontrol->private_value;
350
351 if (ucontrol->value.integer.value[0]) {
Neema Shettyfeea7742011-09-11 12:30:36 -0700352 msm_pcm_routing_process_voice(mc->reg, mc->shift, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
354 } else {
Neema Shettyfeea7742011-09-11 12:30:36 -0700355 msm_pcm_routing_process_voice(mc->reg, mc->shift, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700356 snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
357 }
358
359 return 1;
360}
361
Sriranjan Srikantama4969dd2011-07-14 00:34:56 -0700362static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
363 struct snd_ctl_elem_value *ucontrol)
364{
365 ucontrol->value.integer.value[0] = fm_switch_enable;
366 pr_debug("%s: FM Switch enable %ld\n", __func__,
367 ucontrol->value.integer.value[0]);
368 return 0;
369}
370
371static int msm_routing_put_switch_mixer(struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_value *ucontrol)
373{
374 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
375
376 pr_debug("%s: FM Switch enable %ld\n", __func__,
377 ucontrol->value.integer.value[0]);
378 if (ucontrol->value.integer.value[0])
379 snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
380 else
381 snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
382 fm_switch_enable = ucontrol->value.integer.value[0];
383 return 1;
384}
385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol,
387 struct snd_ctl_elem_value *ucontrol)
388{
389 struct soc_mixer_control *mc =
390 (struct soc_mixer_control *)kcontrol->private_value;
391
392 if (test_bit(mc->shift, &audio_port_mixers[mc->reg].dai_sessions))
393 ucontrol->value.integer.value[0] = 1;
394 else
395 ucontrol->value.integer.value[0] = 0;
396
397 pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
398 ucontrol->value.integer.value[0]);
399
400 return 0;
401}
402
403static int msm_routing_put_port_mixer(struct snd_kcontrol *kcontrol,
404 struct snd_ctl_elem_value *ucontrol)
405{
406 struct soc_mixer_control *mc =
407 (struct soc_mixer_control *)kcontrol->private_value;
408
409 pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg,
410 mc->shift, ucontrol->value.integer.value[0]);
411
412 if (ucontrol->value.integer.value[0]) {
413 afe_loopback(1, audio_port_mixers[mc->reg].port_id,
414 bedai_port_map[mc->shift]);
415 set_bit(mc->shift,
416 &audio_port_mixers[mc->reg].dai_sessions);
417 } else {
418 afe_loopback(0, audio_port_mixers[mc->reg].port_id,
419 bedai_port_map[mc->shift]);
420 clear_bit(mc->shift,
421 &audio_port_mixers[mc->reg].dai_sessions);
422 }
423
424 return 1;
425}
426
Jayasena Sangaraboinacb1e22f2011-07-18 10:36:57 -0700427static int msm_routing_get_fm_vol_mixer(struct snd_kcontrol *kcontrol,
428 struct snd_ctl_elem_value *ucontrol)
429{
430 ucontrol->value.integer.value[0] = msm_route_fm_vol_control;
431 return 0;
432}
433
434static int msm_routing_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
435 struct snd_ctl_elem_value *ucontrol)
436{
437 afe_loopback_gain(INT_FM_TX , ucontrol->value.integer.value[0]);
438
439 msm_route_fm_vol_control = ucontrol->value.integer.value[0];
440
441 return 0;
442}
443
Asish Bhattacharya0ec76182011-07-29 16:58:11 +0530444static int msm_routing_get_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
445 struct snd_ctl_elem_value *ucontrol)
446{
447 ucontrol->value.integer.value[0] = msm_route_lpa_vol_control;
448 return 0;
449}
450
451static int msm_routing_set_lpa_vol_mixer(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_value *ucontrol)
453{
454 if (!lpa_set_volume(ucontrol->value.integer.value[0]))
455 msm_route_lpa_vol_control =
456 ucontrol->value.integer.value[0];
457
458 return 0;
459}
460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
462 SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_PRI_I2S_RX ,
463 MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
464 msm_routing_put_audio_mixer),
465 SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_PRI_I2S_RX,
466 MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
467 msm_routing_put_audio_mixer),
468 SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_PRI_I2S_RX,
469 MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
470 msm_routing_put_audio_mixer),
471};
472
473static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
474 SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_SLIMBUS_0_RX ,
475 MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
476 msm_routing_put_audio_mixer),
477 SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_SLIMBUS_0_RX,
478 MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
479 msm_routing_put_audio_mixer),
480 SOC_SINGLE_EXT("MultiMedia3", AUDIO_MIXER_SLIMBUS_0_RX,
481 MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
482 msm_routing_put_audio_mixer),
483};
484
485static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
486 SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_HDMI_RX,
487 MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
488 msm_routing_put_audio_mixer),
489 SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_HDMI_RX,
490 MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
491 msm_routing_put_audio_mixer),
492};
493
494static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
495 SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_INT_BT_SCO_RX,
496 MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
497 msm_routing_put_audio_mixer),
498 SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_INT_BT_SCO_RX,
499 MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
500 msm_routing_put_audio_mixer),
501};
502
503static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
504 SOC_SINGLE_EXT("MultiMedia1", AUDIO_MIXER_INT_FM_RX,
505 MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
506 msm_routing_put_audio_mixer),
507 SOC_SINGLE_EXT("MultiMedia2", AUDIO_MIXER_INT_FM_RX,
508 MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
509 msm_routing_put_audio_mixer),
510};
511
512static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
513 SOC_SINGLE_EXT("PRI_TX", AUDIO_MIXER_MM_UL1,
514 MSM_BACKEND_DAI_PRI_I2S_TX, 1, 0, msm_routing_get_audio_mixer,
515 msm_routing_put_audio_mixer),
516 SOC_SINGLE_EXT("SLIM_0_TX", AUDIO_MIXER_MM_UL1,
517 MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_audio_mixer,
518 msm_routing_put_audio_mixer),
519 SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", AUDIO_MIXER_MM_UL1,
520 MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_audio_mixer,
521 msm_routing_put_audio_mixer),
522 SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_MIXER_MM_UL1,
523 MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_audio_mixer,
524 msm_routing_put_audio_mixer),
525};
526
527static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
Neema Shettyfeea7742011-09-11 12:30:36 -0700528 SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
529 MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
530 msm_routing_put_voice_mixer),
531 SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_I2S_RX,
532 MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
533 msm_routing_put_voice_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534};
535
536static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
Neema Shettyfeea7742011-09-11 12:30:36 -0700537 SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
538 MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
539 msm_routing_put_voice_mixer),
540 SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
541 MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
542 msm_routing_put_voice_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543};
544
545static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
Neema Shettyfeea7742011-09-11 12:30:36 -0700546 SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_INT_BT_SCO_RX,
547 MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
548 msm_routing_put_voice_mixer),
549 SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
550 MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
551 msm_routing_put_voice_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552};
553
554static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
Neema Shettyfeea7742011-09-11 12:30:36 -0700555 SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
556 MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
557 msm_routing_put_voice_mixer),
558 SOC_SINGLE_EXT("SLIM_0_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_0_TX,
559 MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
560 msm_routing_put_voice_mixer),
561 SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice",
562 MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0,
Neema Shetty2c07eb52011-08-21 20:33:52 -0700563 msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564};
565
566static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
Neema Shettyfeea7742011-09-11 12:30:36 -0700567 SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
568 MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
569 msm_routing_put_voice_mixer),
570 SOC_SINGLE_EXT("SLIM_0_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_0_TX,
571 MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
572 msm_routing_put_voice_mixer),
573 SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voip", MSM_BACKEND_DAI_INT_BT_SCO_TX,
574 MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
575 msm_routing_put_voice_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576};
577
578static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
579 SOC_SINGLE_EXT("INTERNAL_FM_TX", AUDIO_PORT_MIXER_SLIM_0_RX,
580 MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
581 msm_routing_put_port_mixer),
582 SOC_SINGLE_EXT("SLIM_0_TX", AUDIO_PORT_MIXER_SLIM_0_RX,
583 MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
584 msm_routing_put_port_mixer),
585};
586
Sriranjan Srikantama4969dd2011-07-14 00:34:56 -0700587static const struct snd_kcontrol_new fm_switch_mixer_controls =
588 SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
589 0, 1, 0, msm_routing_get_switch_mixer,
590 msm_routing_put_switch_mixer);
591
Jayasena Sangaraboinacb1e22f2011-07-18 10:36:57 -0700592static const struct snd_kcontrol_new int_fm_vol_mixer_controls[] = {
593 SOC_SINGLE_EXT_TLV("Internal FM RX Volume", SND_SOC_NOPM, 0,
594 INT_FM_RX_VOL_GAIN, 0, msm_routing_get_fm_vol_mixer,
595 msm_routing_set_fm_vol_mixer, fm_rx_vol_gain),
596};
597
Asish Bhattacharya0ec76182011-07-29 16:58:11 +0530598static const struct snd_kcontrol_new lpa_vol_mixer_controls[] = {
599 SOC_SINGLE_EXT_TLV("LPA RX Volume", SND_SOC_NOPM, 0,
600 INT_LPA_RX_VOL_GAIN, 0, msm_routing_get_lpa_vol_mixer,
601 msm_routing_set_lpa_vol_mixer, lpa_rx_vol_gain),
602};
603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
605 /* Frontend AIF */
606 /* Widget name equals to Front-End DAI name<Need confirmation>,
607 * Stream name must contains substring of front-end dai name
608 */
609 SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
610 SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
611 SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
612 SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
613 SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
614 SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
615 SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
616 SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
617 SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
618 0, 0, 0, 0),
619 SND_SOC_DAPM_AIF_OUT("SLIM0_UL_HL", "SLIMBUS0_HOSTLESS Capture",
620 0, 0, 0, 0),
621 SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback",
622 0, 0, 0, 0),
623 SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
624 0, 0, 0, 0),
625 /* Backend AIF */
626 /* Stream name equals to backend dai link stream name
627 */
628 SND_SOC_DAPM_AIF_OUT("PRI_I2S_RX", "Primary I2S Playback", 0, 0, 0, 0),
629 SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
630 SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
631 SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
632 SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
633 SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
634 0, 0, 0 , 0),
635 SND_SOC_DAPM_AIF_IN("INT_BT_SCO_TX", "Internal BT-SCO Capture",
636 0, 0, 0, 0),
637 SND_SOC_DAPM_AIF_OUT("INT_FM_RX", "Internal FM Playback",
638 0, 0, 0 , 0),
639 SND_SOC_DAPM_AIF_IN("INT_FM_TX", "Internal FM Capture",
640 0, 0, 0, 0),
Sriranjan Srikantama4969dd2011-07-14 00:34:56 -0700641 /* Switch Definitions */
642 SND_SOC_DAPM_SWITCH("SBUS_0_RX", SND_SOC_NOPM, 0, 0,
643 &fm_switch_mixer_controls),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644 /* Mixer definitions */
645 SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
646 pri_i2s_rx_mixer_controls, ARRAY_SIZE(pri_i2s_rx_mixer_controls)),
647 SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
648 slimbus_rx_mixer_controls, ARRAY_SIZE(slimbus_rx_mixer_controls)),
649 SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
650 hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
651 SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
652 mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
653 /* Voice Mixer */
654 SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
655 SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
656 ARRAY_SIZE(pri_rx_voice_mixer_controls)),
657 SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
658 SND_SOC_NOPM, 0, 0,
659 slimbus_rx_voice_mixer_controls,
660 ARRAY_SIZE(slimbus_rx_voice_mixer_controls)),
661 SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX_Voice Mixer",
662 SND_SOC_NOPM, 0, 0,
663 bt_sco_rx_voice_mixer_controls,
664 ARRAY_SIZE(bt_sco_rx_voice_mixer_controls)),
665 SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
666 SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
667 ARRAY_SIZE(tx_voice_mixer_controls)),
668 SND_SOC_DAPM_MIXER("Voip_Tx Mixer",
669 SND_SOC_NOPM, 0, 0, tx_voip_mixer_controls,
670 ARRAY_SIZE(tx_voip_mixer_controls)),
671 SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
672 int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
673 SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
674 int_fm_rx_mixer_controls, ARRAY_SIZE(int_fm_rx_mixer_controls)),
675 SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
676 SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
677 ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
678};
679
680static const struct snd_soc_dapm_route intercon[] = {
681 {"PRI_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
682 {"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
683 {"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
684 {"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
685
686 {"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
687 {"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
688 {"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
689 {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
690
691 {"HDMI Mixer", "MultiMedia1", "MM_DL1"},
692 {"HDMI Mixer", "MultiMedia2", "MM_DL2"},
693 {"HDMI", NULL, "HDMI Mixer"},
694
695 {"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
696 {"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
697
698 {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
699 {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
700 {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
701
702 {"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
703 {"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
704 {"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
705
706 {"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
707 {"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
708 {"MM_UL1", NULL, "MultiMedia1 Mixer"},
709
710 {"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
711 {"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
712 {"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
713
714 {"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
715 {"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
716 {"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
717
718 {"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
719 {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
720 {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
721
722 {"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
723 {"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
724 {"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
725 {"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
726 {"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
727 {"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
728 {"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
729 {"VOIP_UL", NULL, "Voip_Tx Mixer"},
Sriranjan Srikantama4969dd2011-07-14 00:34:56 -0700730 {"SLIMBUS_0_RX", "Switch", "SLIM0_DL_HL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 {"SLIM0_UL_HL", NULL, "SLIMBUS_0_TX"},
732 {"INT_FM_RX", NULL, "INTFM_DL_HL"},
733 {"INTFM_UL_HL", NULL, "INT_FM_TX"},
734 {"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
735 {"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
736 {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
737};
738
739static struct snd_pcm_ops msm_routing_pcm_ops = {};
740
741static unsigned int msm_routing_read(struct snd_soc_platform *platform,
742 unsigned int reg)
743{
744 dev_dbg(platform->dev, "reg %x\n", reg);
745 return 0;
746}
747
748/* Not used but frame seems to require it */
749static int msm_routing_write(struct snd_soc_platform *platform,
750 unsigned int reg, unsigned int val)
751{
752 dev_dbg(platform->dev, "reg %x val %x\n", reg, val);
753 return 0;
754}
755
756/* Not used but frame seems to require it */
757static int msm_routing_probe(struct snd_soc_platform *platform)
758{
759 snd_soc_dapm_new_controls(&platform->dapm, msm_qdsp6_widgets,
760 ARRAY_SIZE(msm_qdsp6_widgets));
761 snd_soc_dapm_add_routes(&platform->dapm, intercon,
762 ARRAY_SIZE(intercon));
763
764 snd_soc_dapm_new_widgets(&platform->dapm);
765
Jayasena Sangaraboinacb1e22f2011-07-18 10:36:57 -0700766 snd_soc_add_platform_controls(platform,
767 int_fm_vol_mixer_controls,
768 ARRAY_SIZE(int_fm_vol_mixer_controls));
Asish Bhattacharya0ec76182011-07-29 16:58:11 +0530769
770 snd_soc_add_platform_controls(platform,
771 lpa_vol_mixer_controls,
772 ARRAY_SIZE(lpa_vol_mixer_controls));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 return 0;
774}
775
776static struct snd_soc_platform_driver msm_soc_routing_platform = {
777 .ops = &msm_routing_pcm_ops,
778 .probe = msm_routing_probe,
779 .read = msm_routing_read,
780 .write = msm_routing_write,
781};
782
783static __devinit int msm_routing_pcm_probe(struct platform_device *pdev)
784{
785 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
786 return snd_soc_register_platform(&pdev->dev,
787 &msm_soc_routing_platform);
788}
789
790static int msm_routing_pcm_remove(struct platform_device *pdev)
791{
792 snd_soc_unregister_platform(&pdev->dev);
793 return 0;
794}
795
796static struct platform_driver msm_routing_pcm_driver = {
797 .driver = {
798 .name = "msm-pcm-routing",
799 .owner = THIS_MODULE,
800 },
801 .probe = msm_routing_pcm_probe,
802 .remove = __devexit_p(msm_routing_pcm_remove),
803};
804
805static int __init msm_soc_routing_platform_init(void)
806{
Neema Shettyfeea7742011-09-11 12:30:36 -0700807 mutex_init(&routing_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808 return platform_driver_register(&msm_routing_pcm_driver);
809}
810module_init(msm_soc_routing_platform_init);
811
812static void __exit msm_soc_routing_platform_exit(void)
813{
814 platform_driver_unregister(&msm_routing_pcm_driver);
815}
816module_exit(msm_soc_routing_platform_exit);
817
818MODULE_DESCRIPTION("MSM routing platform driver");
819MODULE_LICENSE("GPL v2");