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