blob: 1e856e5d9247f9feddab77701e311b62351e4ca2 [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/module.h>
14#include <linux/wait.h>
15#include <linux/sched.h>
16#include <linux/jiffies.h>
17#include <linux/debugfs.h>
18#include <asm/uaccess.h>
19#include <mach/qdsp5v2/qdsp5afecmdi.h>
20#include <mach/qdsp5v2/qdsp5afemsg.h>
21#include <mach/qdsp5v2/afe.h>
22#include <mach/msm_adsp.h>
23#include <mach/debug_mm.h>
24
25#define AFE_MAX_TIMEOUT 500 /* 500 ms */
26#define AFE_MAX_CLNT 6 /* 6 HW path defined so far */
27#define GETDEVICEID(x) ((x) - 1)
28
29struct msm_afe_state {
30 struct msm_adsp_module *mod;
31 struct msm_adsp_ops adsp_ops;
32 struct mutex lock;
33 u8 in_use;
34 u8 codec_config[AFE_MAX_CLNT];
35 wait_queue_head_t wait;
36 u8 aux_conf_flag;
37};
38
39#ifdef CONFIG_DEBUG_FS
40static struct dentry *debugfs_afelb;
41#endif
42
43
44static struct msm_afe_state the_afe_state;
45
46#define afe_send_queue(afe, cmd, len) \
47 msm_adsp_write(afe->mod, QDSP_apuAfeQueue, \
48 cmd, len)
49
50static void afe_dsp_event(void *data, unsigned id, size_t len,
51 void (*getevent)(void *ptr, size_t len))
52{
53 struct msm_afe_state *afe = data;
54
55 MM_DBG("msg_id %d \n", id);
56
57 switch (id) {
58 case AFE_APU_MSG_CODEC_CONFIG_ACK: {
59 struct afe_msg_codec_config_ack afe_ack;
60 getevent(&afe_ack, AFE_APU_MSG_CODEC_CONFIG_ACK_LEN);
61 MM_DBG("%s: device_id: %d device activity: %d\n", __func__,
62 afe_ack.device_id, afe_ack.device_activity);
63 if (afe_ack.device_activity == AFE_MSG_CODEC_CONFIG_DISABLED)
64 afe->codec_config[GETDEVICEID(afe_ack.device_id)] = 0;
65 else
66 afe->codec_config[GETDEVICEID(afe_ack.device_id)] =
67 afe_ack.device_activity;
68
69 wake_up(&afe->wait);
70 break;
71 }
72 case AFE_APU_MSG_VOC_TIMING_SUCCESS:
73 MM_INFO("Received VOC_TIMING_SUCCESS message from AFETASK\n");
74 break;
75 case ADSP_MESSAGE_ID:
76 MM_DBG("Received ADSP event: module enable/disable(audpptask)");
77 break;
78 default:
79 MM_ERR("unexpected message from afe \n");
80 }
81
82 return;
83}
84
85static void afe_dsp_codec_config(struct msm_afe_state *afe,
86 u8 path_id, u8 enable, struct msm_afe_config *config)
87{
88 struct afe_cmd_codec_config cmd;
89
90 MM_DBG("%s() %p\n", __func__, config);
91 memset(&cmd, 0, sizeof(cmd));
92 cmd.cmd_id = AFE_CMD_CODEC_CONFIG_CMD;
93 cmd.device_id = path_id;
94 cmd.activity = enable;
95 if (config) {
96 MM_DBG("%s: sample_rate %x ch mode %x vol %x\n",
97 __func__, config->sample_rate,
98 config->channel_mode, config->volume);
99 cmd.sample_rate = config->sample_rate;
100 cmd.channel_mode = config->channel_mode;
101 cmd.volume = config->volume;
102 }
103 afe_send_queue(afe, &cmd, sizeof(cmd));
104}
105/* Function is called after afe module been enabled */
106void afe_loopback(int enable)
107{
108 struct afe_cmd_loopback cmd;
109 struct msm_afe_state *afe;
110
111 afe = &the_afe_state;
112 MM_DBG("enable %d\n", enable);
113 memset(&cmd, 0, sizeof(cmd));
114 cmd.cmd_id = AFE_CMD_LOOPBACK;
115 if (enable)
116 cmd.enable_flag = AFE_LOOPBACK_ENABLE_COMMAND;
117
118 afe_send_queue(afe, &cmd, sizeof(cmd));
119}
120EXPORT_SYMBOL(afe_loopback);
121
122void afe_ext_loopback(int enable, int rx_copp_id, int tx_copp_id)
123{
124 struct afe_cmd_ext_loopback cmd;
125 struct msm_afe_state *afe;
126
127 afe = &the_afe_state;
128 MM_DBG("enable %d\n", enable);
129 if ((rx_copp_id == 0) && (tx_copp_id == 0)) {
130 afe_loopback(enable);
131 } else {
132 memset(&cmd, 0, sizeof(cmd));
133 cmd.cmd_id = AFE_CMD_EXT_LOOPBACK;
134 cmd.source_id = tx_copp_id;
135 cmd.dst_id = rx_copp_id;
136 if (enable)
137 cmd.enable_flag = AFE_LOOPBACK_ENABLE_COMMAND;
138
139 afe_send_queue(afe, &cmd, sizeof(cmd));
140 }
141}
142EXPORT_SYMBOL(afe_ext_loopback);
143
144void afe_device_volume_ctrl(u16 device_id, u16 device_volume)
145{
146 struct afe_cmd_device_volume_ctrl cmd;
147 struct msm_afe_state *afe;
148
149 afe = &the_afe_state;
150 MM_DBG("device 0x%4x volume 0x%4x\n", device_id, device_volume);
151 memset(&cmd, 0, sizeof(cmd));
152 cmd.cmd_id = AFE_CMD_DEVICE_VOLUME_CTRL;
153 cmd.device_id = device_id;
154 cmd.device_volume = device_volume;
155 afe_send_queue(afe, &cmd, sizeof(cmd));
156}
157EXPORT_SYMBOL(afe_device_volume_ctrl);
158
159int afe_enable(u8 path_id, struct msm_afe_config *config)
160{
161 struct msm_afe_state *afe = &the_afe_state;
162 int rc;
163
164 MM_DBG("%s: path %d\n", __func__, path_id);
165 if ((GETDEVICEID(path_id) < 0) || (GETDEVICEID(path_id) > 5)) {
166 MM_ERR("Invalid path_id: %d\n", path_id);
167 return -EINVAL;
168 }
169 mutex_lock(&afe->lock);
170 if (!afe->in_use && !afe->aux_conf_flag) {
171 /* enable afe */
172 rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
173 if (rc < 0) {
174 MM_ERR("%s: failed to get AFETASK module\n", __func__);
175 goto error_adsp_get;
176 }
177 rc = msm_adsp_enable(afe->mod);
178 if (rc < 0)
179 goto error_adsp_enable;
180 }
181 /* Issue codec config command */
182 afe_dsp_codec_config(afe, path_id, 1, config);
183 rc = wait_event_timeout(afe->wait,
184 afe->codec_config[GETDEVICEID(path_id)],
185 msecs_to_jiffies(AFE_MAX_TIMEOUT));
186 if (!rc) {
187 MM_ERR("AFE failed to respond within %d ms\n", AFE_MAX_TIMEOUT);
188 rc = -ENODEV;
189 if (!afe->in_use) {
190 if (!afe->aux_conf_flag ||
191 (afe->aux_conf_flag &&
192 (path_id == AFE_HW_PATH_AUXPCM_RX ||
193 path_id == AFE_HW_PATH_AUXPCM_TX))) {
194 /* clean up if there is no client */
195 msm_adsp_disable(afe->mod);
196 msm_adsp_put(afe->mod);
197 afe->aux_conf_flag = 0;
198 afe->mod = NULL;
199 }
200 }
201
202 } else {
203 rc = 0;
204 afe->in_use++;
205 }
206
207 mutex_unlock(&afe->lock);
208 return rc;
209
210error_adsp_enable:
211 msm_adsp_put(afe->mod);
212 afe->mod = NULL;
213error_adsp_get:
214 mutex_unlock(&afe->lock);
215 return rc;
216}
217EXPORT_SYMBOL(afe_enable);
218
219int afe_config_fm_codec(int fm_enable, uint16_t source)
220{
221 struct afe_cmd_fm_codec_config cmd;
222 struct msm_afe_state *afe = &the_afe_state;
223 int rc = 0;
224 int i = 0;
225 unsigned short *ptrmem = (unsigned short *)&cmd;
226
227 MM_INFO(" configure fm codec\n");
228 mutex_lock(&afe->lock);
229 if (!afe->in_use) {
230 /* enable afe */
231 rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
232 if (rc < 0) {
233 MM_ERR("%s: failed to get AFETASK module\n", __func__);
234 goto error_adsp_get;
235 }
236 rc = msm_adsp_enable(afe->mod);
237 if (rc < 0)
238 goto error_adsp_enable;
239 }
240 memset(&cmd, 0, sizeof(cmd));
241 cmd.cmd_id = AFE_CMD_FM_RX_ROUTING_CMD;
242 cmd.enable = fm_enable;
243 cmd.device_id = source;
244
245 for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
246 MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
247 afe_send_queue(afe, &cmd, sizeof(cmd));
248
249 mutex_unlock(&afe->lock);
250 return rc;
251error_adsp_enable:
252 msm_adsp_put(afe->mod);
253 afe->mod = NULL;
254error_adsp_get:
255 mutex_unlock(&afe->lock);
256 return rc;
257}
258EXPORT_SYMBOL(afe_config_fm_codec);
259
260int afe_config_fm_volume(uint16_t volume)
261{
262 struct afe_cmd_fm_volume_config cmd;
263 struct msm_afe_state *afe = &the_afe_state;
264 int rc = 0;
265
266 MM_INFO(" configure fm volume\n");
267 mutex_lock(&afe->lock);
268 if (!afe->in_use) {
269 /* enable afe */
270 rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
271 if (rc < 0) {
272 MM_ERR("%s: failed to get AFETASK module\n", __func__);
273 goto error_adsp_get;
274 }
275 rc = msm_adsp_enable(afe->mod);
276 if (rc < 0)
277 goto error_adsp_enable;
278 }
279 memset(&cmd, 0, sizeof(cmd));
280 cmd.cmd_id = AFE_CMD_FM_PLAYBACK_VOLUME_CMD;
281 cmd.volume = volume;
282
283 afe_send_queue(afe, &cmd, sizeof(cmd));
284
285 mutex_unlock(&afe->lock);
286 return rc;
287error_adsp_enable:
288 msm_adsp_put(afe->mod);
289 afe->mod = NULL;
290error_adsp_get:
291 mutex_unlock(&afe->lock);
292 return rc;
293}
294EXPORT_SYMBOL(afe_config_fm_volume);
295
296int afe_config_fm_calibration_gain(uint16_t device_id,
297 uint16_t calibration_gain)
298{
299 struct afe_cmd_fm_calibgain_config cmd;
300 struct msm_afe_state *afe = &the_afe_state;
301 int rc = 0;
302
303 MM_INFO("Configure for rx device = 0x%4x, gain = 0x%4x\n", device_id,
304 calibration_gain);
305 mutex_lock(&afe->lock);
306 if (!afe->in_use) {
307 /* enable afe */
308 rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
309 if (rc < 0) {
310 MM_ERR("%s: failed to get AFETASK module\n", __func__);
311 goto error_adsp_get;
312 }
313 rc = msm_adsp_enable(afe->mod);
314 if (rc < 0)
315 goto error_adsp_enable;
316 }
317 memset(&cmd, 0, sizeof(cmd));
318 cmd.cmd_id = AFE_CMD_FM_CALIBRATION_GAIN_CMD;
319 cmd.device_id = device_id;
320 cmd.calibration_gain = calibration_gain;
321
322 afe_send_queue(afe, &cmd, sizeof(cmd));
323
324 mutex_unlock(&afe->lock);
325 return rc;
326error_adsp_enable:
327 msm_adsp_put(afe->mod);
328 afe->mod = NULL;
329error_adsp_get:
330 mutex_unlock(&afe->lock);
331 return rc;
332}
333EXPORT_SYMBOL(afe_config_fm_calibration_gain);
334
335int afe_config_aux_codec(int pcm_ctl_value, int aux_codec_intf_value,
336 int data_format_pad)
337{
338 struct afe_cmd_aux_codec_config cmd;
339 struct msm_afe_state *afe = &the_afe_state;
340 int rc = 0;
341
342 MM_DBG(" configure aux codec \n");
343 mutex_lock(&afe->lock);
344 if (!afe->in_use && !afe->aux_conf_flag) {
345 /* enable afe */
346 rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
347 if (rc < 0) {
348 MM_ERR("%s: failed to get AFETASK module\n", __func__);
349 goto error_adsp_get;
350 }
351 rc = msm_adsp_enable(afe->mod);
352 if (rc < 0)
353 goto error_adsp_enable;
354 }
355 afe->aux_conf_flag = 1;
356 memset(&cmd, 0, sizeof(cmd));
357 cmd.cmd_id = AFE_CMD_AUX_CODEC_CONFIG_CMD;
358 cmd.dma_path_ctl = 0;
359 cmd.pcm_ctl = pcm_ctl_value;
360 cmd.eight_khz_int_mode = 0;
361 cmd.aux_codec_intf_ctl = aux_codec_intf_value;
362 cmd.data_format_padding_info = data_format_pad;
363
364 afe_send_queue(afe, &cmd, sizeof(cmd));
365
366 mutex_unlock(&afe->lock);
367 return rc;
368error_adsp_enable:
369 msm_adsp_put(afe->mod);
370 afe->mod = NULL;
371error_adsp_get:
372 mutex_unlock(&afe->lock);
373 return rc;
374}
375EXPORT_SYMBOL(afe_config_aux_codec);
376
377int afe_config_rmc_block(struct acdb_rmc_block *acdb_rmc)
378{
379 struct afe_cmd_cfg_rmc cmd;
380 struct msm_afe_state *afe = &the_afe_state;
381 int rc = 0;
382 int i = 0;
383 unsigned short *ptrmem = (unsigned short *)&cmd;
384
385 MM_DBG(" configure rmc block\n");
386 mutex_lock(&afe->lock);
387 if (!afe->in_use && !afe->mod) {
388 /* enable afe */
389 rc = msm_adsp_get("AFETASK", &afe->mod, &afe->adsp_ops, afe);
390 if (rc < 0) {
391 MM_DBG("%s: failed to get AFETASK module\n", __func__);
392 goto error_adsp_get;
393 }
394 rc = msm_adsp_enable(afe->mod);
395 if (rc < 0)
396 goto error_adsp_enable;
397 }
398 memset(&cmd, 0, sizeof(cmd));
399 cmd.cmd_id = AFE_CMD_CFG_RMC_PARAMS;
400
401 cmd.rmc_mode = acdb_rmc->rmc_enable;
402 cmd.rmc_ipw_length_ms = acdb_rmc->rmc_ipw_length_ms;
403 cmd.rmc_peak_length_ms = acdb_rmc->rmc_peak_length_ms;
404 cmd.rmc_init_pulse_length_ms = acdb_rmc->rmc_init_pulse_length_ms;
405 cmd.rmc_total_int_length_ms = acdb_rmc->rmc_total_int_length_ms;
406 cmd.rmc_rampupdn_length_ms = acdb_rmc->rmc_rampupdn_length_ms;
407 cmd.rmc_delay_length_ms = acdb_rmc->rmc_delay_length_ms;
408 cmd.rmc_detect_start_threshdb = acdb_rmc->rmc_detect_start_threshdb;
409 cmd.rmc_init_pulse_threshdb = acdb_rmc->rmc_init_pulse_threshdb;
410
411 for (i = 0; i < sizeof(cmd)/2; i++, ++ptrmem)
412 MM_DBG("cmd[%d]=0x%04x\n", i, *ptrmem);
413 afe_send_queue(afe, &cmd, sizeof(cmd));
414
415 mutex_unlock(&afe->lock);
416 return rc;
417error_adsp_enable:
418 msm_adsp_put(afe->mod);
419 afe->mod = NULL;
420error_adsp_get:
421 mutex_unlock(&afe->lock);
422 return rc;
423}
424EXPORT_SYMBOL(afe_config_rmc_block);
425
426int afe_disable(u8 path_id)
427{
428 struct msm_afe_state *afe = &the_afe_state;
429 int rc;
430
431 mutex_lock(&afe->lock);
432
433 BUG_ON(!afe->in_use);
434 MM_DBG("%s() path_id:%d codec state:%d\n", __func__, path_id,
435 afe->codec_config[GETDEVICEID(path_id)]);
436 afe_dsp_codec_config(afe, path_id, 0, NULL);
437 rc = wait_event_timeout(afe->wait,
438 !afe->codec_config[GETDEVICEID(path_id)],
439 msecs_to_jiffies(AFE_MAX_TIMEOUT));
440 if (!rc) {
441 MM_ERR("AFE failed to respond within %d ms\n", AFE_MAX_TIMEOUT);
442 rc = -1;
443 } else
444 rc = 0;
445 afe->in_use--;
446 MM_DBG("%s() in_use:%d \n", __func__, afe->in_use);
447 if (!afe->in_use) {
448 msm_adsp_disable(afe->mod);
449 msm_adsp_put(afe->mod);
450 afe->aux_conf_flag = 0;
451 afe->mod = NULL;
452 }
453 mutex_unlock(&afe->lock);
454 return rc;
455}
456EXPORT_SYMBOL(afe_disable);
457
458
459#ifdef CONFIG_DEBUG_FS
460static int afe_debug_open(struct inode *inode, struct file *file)
461{
462 file->private_data = inode->i_private;
463 MM_INFO("debug intf %s\n", (char *) file->private_data);
464 return 0;
465}
466
467static ssize_t afe_debug_write(struct file *filp,
468 const char __user *ubuf, size_t cnt, loff_t *ppos)
469{
470 char *lb_str = filp->private_data;
471 char cmd;
472
473 if (get_user(cmd, ubuf))
474 return -EFAULT;
475
476 MM_INFO("%s %c\n", lb_str, cmd);
477
478 if (!strcmp(lb_str, "afe_loopback")) {
479 switch (cmd) {
480 case '1':
481 afe_loopback(1);
482 break;
483 case '0':
484 afe_loopback(0);
485 break;
486 }
487 }
488
489 return cnt;
490}
491
492static const struct file_operations afe_debug_fops = {
493 .open = afe_debug_open,
494 .write = afe_debug_write
495};
496#endif
497
498static int __init afe_init(void)
499{
500 struct msm_afe_state *afe = &the_afe_state;
501
502 MM_INFO("AFE driver init\n");
503
504 memset(afe, 0, sizeof(struct msm_afe_state));
505 afe->adsp_ops.event = afe_dsp_event;
506 mutex_init(&afe->lock);
507 init_waitqueue_head(&afe->wait);
508
509#ifdef CONFIG_DEBUG_FS
510 debugfs_afelb = debugfs_create_file("afe_loopback",
511 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
512 &afe_debug_fops);
513#endif
514
515 return 0;
516}
517
518static void __exit afe_exit(void)
519{
520 MM_INFO("AFE driver exit\n");
521#ifdef CONFIG_DEBUG_FS
522 if (debugfs_afelb)
523 debugfs_remove(debugfs_afelb);
524#endif
525 if (the_afe_state.mod)
526 msm_adsp_put(the_afe_state.mod);
527 return;
528}
529
530module_init(afe_init);
531module_exit(afe_exit);
532
533MODULE_DESCRIPTION("MSM AFE driver");
534MODULE_LICENSE("GPL v2");