blob: 5f40f1e28015283f305fd5fc9d19f9c52e9cc79c [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-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/debugfs.h>
14#include <linux/kernel.h>
15#include <linux/kthread.h>
16#include <linux/uaccess.h>
17#include <linux/wait.h>
18#include <linux/jiffies.h>
19#include <linux/sched.h>
20#include <sound/apr_audio.h>
21#include <sound/q6afe.h>
22
23struct afe_ctl {
24 void *apr;
25 atomic_t state;
26 atomic_t status;
27 wait_queue_head_t wait;
28 struct task_struct *task;
29};
30
31static struct afe_ctl this_afe;
32
33#define TIMEOUT_MS 1000
34#define Q6AFE_MAX_VOLUME 0x3FFF
35
36#define SIZEOF_CFG_CMD(y) \
37 (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
38
39static int32_t afe_callback(struct apr_client_data *data, void *priv)
40{
41 if (data->opcode == RESET_EVENTS) {
42 pr_debug("q6afe: reset event = %d %d apr[%p]\n",
43 data->reset_event, data->reset_proc, this_afe.apr);
44 if (this_afe.apr) {
45 apr_reset(this_afe.apr);
46 atomic_set(&this_afe.state, 0);
47 this_afe.apr = NULL;
48 }
49 /* send info to user */
50 pr_debug("task_name = %s pid = %d\n",
51 this_afe.task->comm, this_afe.task->pid);
52 send_sig(SIGUSR1, this_afe.task, 0);
53 }
54 if (data->payload_size) {
55 uint32_t *payload;
56 payload = data->payload;
57 pr_debug("%s: cmd = 0x%x status = 0x%x\n", __func__,
58 payload[0], payload[1]);
59 /* payload[1] contains the error status for response */
60 if (payload[1] != 0) {
61 atomic_set(&this_afe.status, -1);
62 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
63 __func__, payload[0], payload[1]);
64 }
65 if (data->opcode == APR_BASIC_RSP_RESULT) {
66 switch (payload[0]) {
67 case AFE_PORT_AUDIO_IF_CONFIG:
68 case AFE_PORT_CMD_STOP:
69 case AFE_PORT_CMD_START:
70 case AFE_PORT_CMD_LOOPBACK:
71 case AFE_PORT_CMD_SIDETONE_CTL:
72 case AFE_PORT_CMD_SET_PARAM:
73 case AFE_PSEUDOPORT_CMD_START:
74 case AFE_PSEUDOPORT_CMD_STOP:
Laxminath Kasam885f5102011-07-14 10:20:21 +053075 case AFE_PORT_CMD_APPLY_GAIN:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076 atomic_set(&this_afe.state, 0);
77 wake_up(&this_afe.wait);
78 break;
79 default:
80 pr_err("Unknown cmd 0x%x\n",
81 payload[0]);
82 break;
83 }
84 }
85 }
86 return 0;
87}
88
Neema Shettyfeea7742011-09-11 12:30:36 -070089int afe_get_port_type(u16 port_id)
90{
91 int ret;
92
93 switch (port_id) {
94 case PRIMARY_I2S_RX:
95 case PCM_RX:
96 case SECONDARY_I2S_RX:
97 case MI2S_RX:
98 case HDMI_RX:
99 case SLIMBUS_0_RX:
100 case INT_BT_SCO_RX:
101 case INT_BT_A2DP_RX:
102 case INT_FM_RX:
103 case VOICE_PLAYBACK_TX:
104 ret = MSM_AFE_PORT_TYPE_RX;
105 break;
106
107 case PRIMARY_I2S_TX:
108 case PCM_TX:
109 case SECONDARY_I2S_TX:
110 case MI2S_TX:
111 case DIGI_MIC_TX:
112 case VOICE_RECORD_TX:
113 case SLIMBUS_0_TX:
114 case INT_FM_TX:
115 case VOICE_RECORD_RX:
116 case INT_BT_SCO_TX:
117 ret = MSM_AFE_PORT_TYPE_TX;
118 break;
119
120 default:
121 pr_err("%s: invalid port id\n", __func__);
122 ret = -EINVAL;
123 }
124
125 return ret;
126}
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128int afe_validate_port(u16 port_id)
129{
130 int ret;
131
132 switch (port_id) {
133 case PRIMARY_I2S_RX:
134 case PRIMARY_I2S_TX:
135 case PCM_RX:
136 case PCM_TX:
137 case SECONDARY_I2S_RX:
138 case SECONDARY_I2S_TX:
139 case MI2S_RX:
140 case MI2S_TX:
141 case HDMI_RX:
142 case RSVD_2:
143 case RSVD_3:
144 case DIGI_MIC_TX:
145 case VOICE_RECORD_RX:
146 case VOICE_RECORD_TX:
147 case VOICE_PLAYBACK_TX:
148 case SLIMBUS_0_RX:
149 case SLIMBUS_0_TX:
150 case INT_BT_SCO_RX:
151 case INT_BT_SCO_TX:
152 case INT_BT_A2DP_RX:
153 case INT_FM_RX:
154 case INT_FM_TX:
155 {
156 ret = 0;
157 break;
158 }
159
160 default:
161 ret = -EINVAL;
162 }
163
164 return ret;
165}
166
167int afe_get_port_index(u16 port_id)
168{
169 switch (port_id) {
170 case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
171 case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
172 case PCM_RX: return IDX_PCM_RX;
173 case PCM_TX: return IDX_PCM_TX;
174 case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
175 case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
176 case MI2S_RX: return IDX_MI2S_RX;
177 case MI2S_TX: return IDX_MI2S_TX;
178 case HDMI_RX: return IDX_HDMI_RX;
179 case RSVD_2: return IDX_RSVD_2;
180 case RSVD_3: return IDX_RSVD_3;
181 case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
182 case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
183 case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
184 case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
185 case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
186 case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
187 case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
188 case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
189 case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
190 case INT_FM_RX: return IDX_INT_FM_RX;
191 case INT_FM_TX: return IDX_INT_FM_TX;
192
193 default: return -EINVAL;
194 }
195}
196
197int afe_sizeof_cfg_cmd(u16 port_id)
198{
199 int ret_size;
200 switch (port_id) {
201 case PRIMARY_I2S_RX:
202 case PRIMARY_I2S_TX:
203 case SECONDARY_I2S_RX:
204 case SECONDARY_I2S_TX:
205 case MI2S_RX:
206 case MI2S_TX:
207 ret_size = SIZEOF_CFG_CMD(afe_port_mi2s_cfg);
208 break;
209 case HDMI_RX:
210 ret_size = SIZEOF_CFG_CMD(afe_port_hdmi_cfg);
211 break;
212 case SLIMBUS_0_RX:
213 case SLIMBUS_0_TX:
214 ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_cfg);
215 break;
216 case PCM_RX:
217 case PCM_TX:
218 default:
219 ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
220 break;
221 }
222 return ret_size;
223}
224
Jay Wang6a305432011-08-05 16:01:54 -0700225int afe_q6_interface_prepare(void)
226{
227 int ret = 0;
228
229 pr_debug("%s:", __func__);
230
231 if (this_afe.apr == NULL) {
232 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
233 0xFFFFFFFF, &this_afe);
234 pr_debug("%s: Register AFE\n", __func__);
235 if (this_afe.apr == NULL) {
236 pr_err("%s: Unable to register AFE\n", __func__);
237 ret = -ENODEV;
238 }
239 }
240 return ret;
241}
242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
244 u32 rate) /* This function is no blocking */
245{
246 struct afe_port_start_command start;
247 struct afe_audioif_config_command config;
248 int ret;
249
250 if (!afe_config) {
251 pr_err("%s: Error, no configuration data\n", __func__);
252 ret = -EINVAL;
253 return ret;
254 }
255
256 pr_info("%s: %d %d\n", __func__, port_id, rate);
257
258 if (this_afe.apr == NULL) {
Jay Wang6a305432011-08-05 16:01:54 -0700259 pr_err("%s: AFE APR is not registered\n", __func__);
260 ret = -ENODEV;
261 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 }
263
264 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
265 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
266 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
267 config.hdr.src_port = 0;
268 config.hdr.dest_port = 0;
269 config.hdr.token = 0;
270 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
271
272 if (afe_validate_port(port_id) < 0) {
273
274 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
275 port_id);
276 ret = -EINVAL;
277 goto fail_cmd;
278 }
279
280 config.port_id = port_id;
281 config.port = *afe_config;
282
283 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
284 if (ret < 0) {
285 pr_err("%s: AFE enable for port %d failed\n", __func__,
286 port_id);
287 ret = -EINVAL;
288 goto fail_cmd;
289 }
290
291 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
292 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
293 start.hdr.pkt_size = sizeof(start);
294 start.hdr.src_port = 0;
295 start.hdr.dest_port = 0;
296 start.hdr.token = 0;
297 start.hdr.opcode = AFE_PORT_CMD_START;
298 start.port_id = port_id;
299 start.gain = 0x2000;
300 start.sample_rate = rate;
301
302 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
303
304 if (IS_ERR_VALUE(ret)) {
305 pr_err("%s: AFE enable for port %d failed\n", __func__,
306 port_id);
307 ret = -EINVAL;
308 goto fail_cmd;
309 }
310
311 if (this_afe.task != current)
312 this_afe.task = current;
313
314 pr_debug("task_name = %s pid = %d\n",
315 this_afe.task->comm, this_afe.task->pid);
316 return 0;
317
318fail_cmd:
319 return ret;
320}
321
322int afe_open(u16 port_id, union afe_port_config *afe_config, int rate)
323{
324 struct afe_port_start_command start;
325 struct afe_audioif_config_command config;
326 int ret = 0;
327
328 if (!afe_config) {
329 pr_err("%s: Error, no configuration data\n", __func__);
330 ret = -EINVAL;
331 return ret;
332 }
333
334 pr_info("%s: %d %d\n", __func__, port_id, rate);
335
Jay Wang6a305432011-08-05 16:01:54 -0700336 ret = afe_q6_interface_prepare();
337 if (ret != 0)
338 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339
340 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
341 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
342 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
343 config.hdr.src_port = 0;
344 config.hdr.dest_port = 0;
345 config.hdr.token = 0;
346 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
347
348 if (afe_validate_port(port_id) < 0) {
349
350 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
351 port_id);
352 ret = -EINVAL;
353 goto fail_cmd;
354 }
355
356 config.port_id = port_id;
357 config.port = *afe_config;
358
359 atomic_set(&this_afe.state, 1);
360 atomic_set(&this_afe.status, 0);
361 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
362 if (ret < 0) {
363 pr_err("%s: AFE enable for port %d failed\n", __func__,
364 port_id);
365 ret = -EINVAL;
366 goto fail_cmd;
367 }
368
369 ret = wait_event_timeout(this_afe.wait,
370 (atomic_read(&this_afe.state) == 0),
371 msecs_to_jiffies(TIMEOUT_MS));
372 if (!ret) {
373 pr_err("%s: wait_event timeout\n", __func__);
374 ret = -EINVAL;
375 goto fail_cmd;
376 }
377 if (atomic_read(&this_afe.status) != 0) {
378 pr_err("%s: config cmd failed\n", __func__);
379 ret = -EINVAL;
380 goto fail_cmd;
381 }
382 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
383 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
384 start.hdr.pkt_size = sizeof(start);
385 start.hdr.src_port = 0;
386 start.hdr.dest_port = 0;
387 start.hdr.token = 0;
388 start.hdr.opcode = AFE_PORT_CMD_START;
389 start.port_id = port_id;
390 start.gain = 0x2000;
391 start.sample_rate = rate;
392
393 atomic_set(&this_afe.state, 1);
394 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
395 if (ret < 0) {
396 pr_err("%s: AFE enable for port %d failed\n", __func__,
397 port_id);
398 ret = -EINVAL;
399 goto fail_cmd;
400 }
401 ret = wait_event_timeout(this_afe.wait,
402 (atomic_read(&this_afe.state) == 0),
403 msecs_to_jiffies(TIMEOUT_MS));
404 if (!ret) {
405 pr_err("%s: wait_event timeout\n", __func__);
406 ret = -EINVAL;
407 goto fail_cmd;
408 }
409
410 if (this_afe.task != current)
411 this_afe.task = current;
412
413 pr_debug("task_name = %s pid = %d\n",
414 this_afe.task->comm, this_afe.task->pid);
415 return 0;
416fail_cmd:
417 return ret;
418}
419
420int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
421{
422 struct afe_loopback_command lb_cmd;
423 int ret = 0;
Jay Wang6a305432011-08-05 16:01:54 -0700424
425 ret = afe_q6_interface_prepare();
426 if (ret != 0)
427 return ret;
428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
430 APR_HDR_LEN(20), APR_PKT_VER);
431 lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
432 sizeof(lb_cmd) - APR_HDR_SIZE);
433 lb_cmd.hdr.src_port = 0;
434 lb_cmd.hdr.dest_port = 0;
435 lb_cmd.hdr.token = 0;
436 lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
437 lb_cmd.tx_port_id = tx_port;
438 lb_cmd.rx_port_id = rx_port;
439 lb_cmd.mode = 0xFFFF;
440 lb_cmd.enable = (enable ? 1 : 0);
441 atomic_set(&this_afe.state, 1);
442
443 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
444 if (ret < 0) {
445 pr_err("%s: AFE loopback failed\n", __func__);
446 ret = -EINVAL;
447 goto done;
448 }
449 ret = wait_event_timeout(this_afe.wait,
450 (atomic_read(&this_afe.state) == 0),
451 msecs_to_jiffies(TIMEOUT_MS));
452 if (!ret) {
453 pr_err("%s: wait_event timeout\n", __func__);
454 ret = -EINVAL;
455 }
456done:
457 return ret;
458}
459
460
461int afe_loopback_gain(u16 port_id, u16 volume)
462{
463 struct afe_port_cmd_set_param set_param;
464 int ret = 0;
465
466 if (this_afe.apr == NULL) {
Jayasena Sangaraboina82435032011-07-26 15:23:00 -0700467 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
468 0xFFFFFFFF, &this_afe);
469 pr_debug("%s: Register AFE\n", __func__);
470 if (this_afe.apr == NULL) {
471 pr_err("%s: Unable to register AFE\n", __func__);
472 ret = -ENODEV;
473 return ret;
474 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 }
476
477 if (afe_validate_port(port_id) < 0) {
478
479 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
480 port_id);
481 ret = -EINVAL;
482 goto fail_cmd;
483 }
484
485 /* RX ports numbers are even .TX ports numbers are odd. */
486 if (port_id % 2 == 0) {
487 pr_err("%s: Failed : afe loopback gain only for TX ports."
488 " port_id %d\n", __func__, port_id);
489 ret = -EINVAL;
490 goto fail_cmd;
491 }
492
493 pr_debug("%s: %d %hX\n", __func__, port_id, volume);
494
495 set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
496 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
497 set_param.hdr.pkt_size = sizeof(set_param);
498 set_param.hdr.src_port = 0;
499 set_param.hdr.dest_port = 0;
500 set_param.hdr.token = 0;
501 set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
502
503 set_param.port_id = port_id;
504 set_param.payload_size = sizeof(struct afe_param_payload);
505 set_param.payload_address = 0;
506
507 set_param.payload.module_id = AFE_MODULE_ID_PORT_INFO;
508 set_param.payload.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
509 set_param.payload.param_size = sizeof(struct afe_param_loopback_gain);
510 set_param.payload.reserved = 0;
511
512 set_param.payload.param.loopback_gain.gain = volume;
513 set_param.payload.param.loopback_gain.reserved = 0;
514
515 atomic_set(&this_afe.state, 1);
516 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
517 if (ret < 0) {
518 pr_err("%s: AFE param set failed for port %d\n",
519 __func__, port_id);
520 ret = -EINVAL;
521 goto fail_cmd;
522 }
523
524 ret = wait_event_timeout(this_afe.wait,
525 (atomic_read(&this_afe.state) == 0),
526 msecs_to_jiffies(TIMEOUT_MS));
527 if (ret < 0) {
528 pr_err("%s: wait_event timeout\n", __func__);
529 ret = -EINVAL;
530 goto fail_cmd;
531 }
532 return 0;
533fail_cmd:
534 return ret;
535}
536
Laxminath Kasam885f5102011-07-14 10:20:21 +0530537int afe_apply_gain(u16 port_id, u16 gain)
538{
539 struct afe_port_gain_command set_gain;
540 int ret = 0;
541
542 if (this_afe.apr == NULL) {
543 pr_err("%s: AFE is not opened\n", __func__);
544 ret = -EPERM;
545 goto fail_cmd;
546 }
547
548 if (afe_validate_port(port_id) < 0) {
549 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
550 port_id);
551 ret = -EINVAL;
552 goto fail_cmd;
553 }
554
555 /* RX ports numbers are even .TX ports numbers are odd. */
556 if (port_id % 2 == 0) {
557 pr_err("%s: Failed : afe apply gain only for TX ports."
558 " port_id %d\n", __func__, port_id);
559 ret = -EINVAL;
560 goto fail_cmd;
561 }
562
563 pr_debug("%s: %d %hX\n", __func__, port_id, gain);
564
565 set_gain.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
566 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
567 set_gain.hdr.pkt_size = sizeof(set_gain);
568 set_gain.hdr.src_port = 0;
569 set_gain.hdr.dest_port = 0;
570 set_gain.hdr.token = 0;
571 set_gain.hdr.opcode = AFE_PORT_CMD_APPLY_GAIN;
572
573 set_gain.port_id = port_id;
574 set_gain.gain = gain;
575
576 atomic_set(&this_afe.state, 1);
577 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_gain);
578 if (ret < 0) {
579 pr_err("%s: AFE Gain set failed for port %d\n",
580 __func__, port_id);
581 ret = -EINVAL;
582 goto fail_cmd;
583 }
584
585 ret = wait_event_timeout(this_afe.wait,
586 (atomic_read(&this_afe.state) == 0),
587 msecs_to_jiffies(TIMEOUT_MS));
588 if (ret < 0) {
589 pr_err("%s: wait_event timeout\n", __func__);
590 ret = -EINVAL;
591 goto fail_cmd;
592 }
593 return 0;
594fail_cmd:
595 return ret;
596}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597int afe_start_pseudo_port(u16 port_id)
598{
599 int ret = 0;
600 struct afe_pseudoport_start_command start;
601
602 pr_info("%s: port_id=%d\n", __func__, port_id);
603
Jay Wang6a305432011-08-05 16:01:54 -0700604 ret = afe_q6_interface_prepare();
605 if (ret != 0)
606 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607
608 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
609 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
610 start.hdr.pkt_size = sizeof(start);
611 start.hdr.src_port = 0;
612 start.hdr.dest_port = 0;
613 start.hdr.token = 0;
614 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
615 start.port_id = port_id;
616 start.timing = 1;
617
618 atomic_set(&this_afe.state, 1);
619 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
620 if (ret < 0) {
621 pr_err("%s: AFE enable for port %d failed %d\n",
622 __func__, port_id, ret);
623 ret = -EINVAL;
624 return ret;
625 }
626
627 ret = wait_event_timeout(this_afe.wait,
628 (atomic_read(&this_afe.state) == 0),
629 msecs_to_jiffies(TIMEOUT_MS));
630 if (!ret) {
631 pr_err("%s: wait_event timeout\n", __func__);
632 ret = -EINVAL;
633 return ret;
634 }
635
636 return 0;
637}
638
639int afe_stop_pseudo_port(u16 port_id)
640{
641 int ret = 0;
642 struct afe_pseudoport_stop_command stop;
643
644 pr_info("%s: port_id=%d\n", __func__, port_id);
645
646 if (this_afe.apr == NULL) {
647 pr_err("%s: AFE is already closed\n", __func__);
648 ret = -EINVAL;
649 return ret;
650 }
651
652 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
653 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
654 stop.hdr.pkt_size = sizeof(stop);
655 stop.hdr.src_port = 0;
656 stop.hdr.dest_port = 0;
657 stop.hdr.token = 0;
658 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
659 stop.port_id = port_id;
660 stop.reserved = 0;
661
662 atomic_set(&this_afe.state, 1);
663 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
664 if (ret < 0) {
665 pr_err("%s: AFE close failed %d\n", __func__, ret);
666 ret = -EINVAL;
667 return ret;
668 }
669
670 ret = wait_event_timeout(this_afe.wait,
671 (atomic_read(&this_afe.state) == 0),
672 msecs_to_jiffies(TIMEOUT_MS));
673 if (!ret) {
674 pr_err("%s: wait_event timeout\n", __func__);
675 ret = -EINVAL;
676 return ret;
677 }
678
679 return 0;
680}
681
682#ifdef CONFIG_DEBUG_FS
683static struct dentry *debugfs_afelb;
684static struct dentry *debugfs_afelb_gain;
685
686static int afe_debug_open(struct inode *inode, struct file *file)
687{
688 file->private_data = inode->i_private;
689 pr_info("debug intf %s\n", (char *) file->private_data);
690 return 0;
691}
692
693static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
694{
695 char *token;
696 int base, cnt;
697
698 token = strsep(&buf, " ");
699
700 for (cnt = 0; cnt < num_of_par; cnt++) {
701 if (token != NULL) {
702 if ((token[1] == 'x') || (token[1] == 'X'))
703 base = 16;
704 else
705 base = 10;
706
707 if (strict_strtoul(token, base, &param1[cnt]) != 0)
708 return -EINVAL;
709
710 token = strsep(&buf, " ");
711 } else
712 return -EINVAL;
713 }
714 return 0;
715}
716#define AFE_LOOPBACK_ON (1)
717#define AFE_LOOPBACK_OFF (0)
718static ssize_t afe_debug_write(struct file *filp,
719 const char __user *ubuf, size_t cnt, loff_t *ppos)
720{
721 char *lb_str = filp->private_data;
722 char lbuf[32];
723 int rc;
724 unsigned long param[5];
725
726 if (cnt > sizeof(lbuf) - 1)
727 return -EINVAL;
728
729 rc = copy_from_user(lbuf, ubuf, cnt);
730 if (rc)
731 return -EFAULT;
732
733 lbuf[cnt] = '\0';
734
735 if (!strcmp(lb_str, "afe_loopback")) {
736 rc = afe_get_parameters(lbuf, param, 3);
737 if (!rc) {
738 pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
739 param[2]);
740
741 if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
742 AFE_LOOPBACK_OFF)) {
743 pr_err("%s: Error, parameter 0 incorrect\n",
744 __func__);
745 rc = -EINVAL;
746 goto afe_error;
747 }
748 if ((afe_validate_port(param[1]) < 0) ||
749 (afe_validate_port(param[2])) < 0) {
750 pr_err("%s: Error, invalid afe port\n",
751 __func__);
752 }
753 if (this_afe.apr == NULL) {
754 pr_err("%s: Error, AFE not opened\n", __func__);
755 rc = -EINVAL;
756 } else {
757 rc = afe_loopback(param[0], param[1], param[2]);
758 }
759 } else {
760 pr_err("%s: Error, invalid parameters\n", __func__);
761 rc = -EINVAL;
762 }
763
764 } else if (!strcmp(lb_str, "afe_loopback_gain")) {
765 rc = afe_get_parameters(lbuf, param, 2);
766 if (!rc) {
767 pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
768
769 if (afe_validate_port(param[0]) < 0) {
770 pr_err("%s: Error, invalid afe port\n",
771 __func__);
772 rc = -EINVAL;
773 goto afe_error;
774 }
775
776 if (param[1] < 0 || param[1] > 100) {
777 pr_err("%s: Error, volume shoud be 0 to 100"
778 " percentage param = %lu\n",
779 __func__, param[1]);
780 rc = -EINVAL;
781 goto afe_error;
782 }
783
784 param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
785
786 if (this_afe.apr == NULL) {
787 pr_err("%s: Error, AFE not opened\n", __func__);
788 rc = -EINVAL;
789 } else {
790 rc = afe_loopback_gain(param[0], param[1]);
791 }
792 } else {
793 pr_err("%s: Error, invalid parameters\n", __func__);
794 rc = -EINVAL;
795 }
796 }
797
798afe_error:
799 if (rc == 0)
800 rc = cnt;
801 else
802 pr_err("%s: rc = %d\n", __func__, rc);
803
804 return rc;
805}
806
807static const struct file_operations afe_debug_fops = {
808 .open = afe_debug_open,
809 .write = afe_debug_write
810};
811#endif
812int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
813{
814 struct afe_port_sidetone_command cmd_sidetone;
815 int ret = 0;
816
817 pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
818 tx_port_id, rx_port_id, enable, gain);
819 cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
820 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
821 cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
822 cmd_sidetone.hdr.src_port = 0;
823 cmd_sidetone.hdr.dest_port = 0;
824 cmd_sidetone.hdr.token = 0;
825 cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SIDETONE_CTL;
826 cmd_sidetone.tx_port_id = tx_port_id;
827 cmd_sidetone.rx_port_id = rx_port_id;
828 cmd_sidetone.gain = gain;
829 cmd_sidetone.enable = enable;
830
831 atomic_set(&this_afe.state, 1);
832 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
833 if (ret < 0) {
834 pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
835 __func__, tx_port_id, rx_port_id);
836 ret = -EINVAL;
837 goto fail_cmd;
838 }
839
840 ret = wait_event_timeout(this_afe.wait,
841 (atomic_read(&this_afe.state) == 0),
842 msecs_to_jiffies(TIMEOUT_MS));
843 if (ret < 0) {
844 pr_err("%s: wait_event timeout\n", __func__);
845 ret = -EINVAL;
846 goto fail_cmd;
847 }
848 return 0;
849fail_cmd:
850 return ret;
851}
852
853int afe_port_stop_nowait(int port_id)
854{
855 struct afe_port_stop_command stop;
856 int ret = 0;
857
858 if (this_afe.apr == NULL) {
859 pr_err("AFE is already closed\n");
860 ret = -EINVAL;
861 goto fail_cmd;
862 }
863 pr_info("%s: port_id=%d\n", __func__, port_id);
864 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
865 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
866 stop.hdr.pkt_size = sizeof(stop);
867 stop.hdr.src_port = 0;
868 stop.hdr.dest_port = 0;
869 stop.hdr.token = 0;
870 stop.hdr.opcode = AFE_PORT_CMD_STOP;
871 stop.port_id = port_id;
872 stop.reserved = 0;
873
874 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
875
876 if (ret == -ENETRESET) {
877 pr_info("%s: Need to reset, calling APR deregister", __func__);
878 return apr_deregister(this_afe.apr);
879 } else if (IS_ERR_VALUE(ret)) {
880 pr_err("%s: AFE close failed\n", __func__);
881 ret = -EINVAL;
882 }
883
884fail_cmd:
885 return ret;
886
887}
888
889int afe_close(int port_id)
890{
891 struct afe_port_stop_command stop;
892 int ret = 0;
893
894 if (this_afe.apr == NULL) {
895 pr_err("AFE is already closed\n");
896 ret = -EINVAL;
897 goto fail_cmd;
898 }
899 pr_info("%s: port_id=%d\n", __func__, port_id);
900 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
901 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
902 stop.hdr.pkt_size = sizeof(stop);
903 stop.hdr.src_port = 0;
904 stop.hdr.dest_port = 0;
905 stop.hdr.token = 0;
906 stop.hdr.opcode = AFE_PORT_CMD_STOP;
907 stop.port_id = port_id;
908 stop.reserved = 0;
909
910 atomic_set(&this_afe.state, 1);
911 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
912
913 if (ret == -ENETRESET) {
914 pr_info("%s: Need to reset, calling APR deregister", __func__);
915 return apr_deregister(this_afe.apr);
916 }
917
918 if (ret < 0) {
919 pr_err("%s: AFE close failed\n", __func__);
920 ret = -EINVAL;
921 goto fail_cmd;
922 }
923
924 ret = wait_event_timeout(this_afe.wait,
925 (atomic_read(&this_afe.state) == 0),
926 msecs_to_jiffies(TIMEOUT_MS));
927 if (!ret) {
928 pr_err("%s: wait_event timeout\n", __func__);
929 ret = -EINVAL;
930 goto fail_cmd;
931 }
932fail_cmd:
933 return ret;
934}
935
936static int __init afe_init(void)
937{
938 init_waitqueue_head(&this_afe.wait);
939 atomic_set(&this_afe.state, 0);
940 atomic_set(&this_afe.status, 0);
941 this_afe.apr = NULL;
942#ifdef CONFIG_DEBUG_FS
943 debugfs_afelb = debugfs_create_file("afe_loopback",
944 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
945 &afe_debug_fops);
946
947 debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
948 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
949 &afe_debug_fops);
950
951
952#endif
953 return 0;
954}
955
956static void __exit afe_exit(void)
957{
958#ifdef CONFIG_DEBUG_FS
959 if (debugfs_afelb)
960 debugfs_remove(debugfs_afelb);
961 if (debugfs_afelb_gain)
962 debugfs_remove(debugfs_afelb_gain);
963#endif
964}
965
966device_initcall(afe_init);
967__exitcall(afe_exit);