blob: f56b3d675b2940b836b49f9eab5c7705b243c51b [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -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/slab.h>
14#include <linux/debugfs.h>
15#include <linux/kernel.h>
16#include <linux/kthread.h>
17#include <linux/uaccess.h>
18#include <linux/wait.h>
19#include <linux/jiffies.h>
20#include <linux/sched.h>
21#include <mach/qdsp6v2/audio_acdb.h>
22#include <sound/apr_audio-v2.h>
23#include <sound/q6afe-v2.h>
24
25#include <sound/q6audio-v2.h>
26
27
28struct afe_ctl {
29 void *apr;
30 atomic_t state;
31 atomic_t status;
32 wait_queue_head_t wait[AFE_MAX_PORTS];
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -070033 struct task_struct *task;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -070034 void (*tx_cb) (uint32_t opcode,
35 uint32_t token, uint32_t *payload, void *priv);
36 void (*rx_cb) (uint32_t opcode,
37 uint32_t token, uint32_t *payload, void *priv);
38 void *tx_private_data;
39 void *rx_private_data;
40};
41
42static struct afe_ctl this_afe;
43
44static struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
45
46#define TIMEOUT_MS 1000
47#define Q6AFE_MAX_VOLUME 0x3FFF
48
49#define SIZEOF_CFG_CMD(y) \
50 (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
51
52static int32_t afe_callback(struct apr_client_data *data, void *priv)
53{
54 if (data->opcode == RESET_EVENTS) {
55 pr_debug("q6afe: reset event = %d %d apr[%p]\n",
56 data->reset_event, data->reset_proc, this_afe.apr);
57 if (this_afe.apr) {
58 apr_reset(this_afe.apr);
59 atomic_set(&this_afe.state, 0);
60 this_afe.apr = NULL;
61 }
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -070062 /* send info to user */
63 pr_debug("task_name = %s pid = %d\n",
64 this_afe.task->comm, this_afe.task->pid);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -070065 return 0;
66 }
67 pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
68 __func__, data->opcode,
69 ((uint32_t *)(data->payload))[0],
70 ((uint32_t *)(data->payload))[1]);
71 if (data->payload_size) {
72 uint32_t *payload;
73 uint16_t port_id = 0;
74 payload = data->payload;
75 pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
76 __func__, data->opcode,
77 payload[0], payload[1], data->token);
78 /* payload[1] contains the error status for response */
79 if (payload[1] != 0) {
80 atomic_set(&this_afe.status, -1);
81 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
82 __func__, payload[0], payload[1]);
83 }
84 if (data->opcode == APR_BASIC_RSP_RESULT) {
85 switch (payload[0]) {
86 case AFE_PORT_CMD_DEVICE_STOP:
87 case AFE_PORT_CMD_DEVICE_START:
88 case AFE_PORT_CMD_SET_PARAM_V2:
89 case AFE_PSEUDOPORT_CMD_START:
90 case AFE_PSEUDOPORT_CMD_STOP:
91 case AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS:
92 case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
93 case AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER:
94 atomic_set(&this_afe.state, 0);
95 wake_up(&this_afe.wait[data->token]);
96 break;
97 case AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER:
98 break;
99 case AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2:
100 port_id = RT_PROXY_PORT_001_TX;
101 break;
102 case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
103 port_id = RT_PROXY_PORT_001_RX;
104 break;
105 default:
106 pr_err("%s:Unknown cmd 0x%x\n", __func__,
107 payload[0]);
108 break;
109 }
110 } else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
111 port_id = (uint16_t)(0x0000FFFF & payload[0]);
112 }
113 pr_debug("%s:port_id = %x\n", __func__, port_id);
114 switch (port_id) {
115 case RT_PROXY_PORT_001_TX: {
116 if (this_afe.tx_cb) {
117 this_afe.tx_cb(data->opcode, data->token,
118 data->payload,
119 this_afe.tx_private_data);
120 }
121 break;
122 }
123 case RT_PROXY_PORT_001_RX: {
124 if (this_afe.rx_cb) {
125 this_afe.rx_cb(data->opcode, data->token,
126 data->payload,
127 this_afe.rx_private_data);
128 }
129 break;
130 }
131 default:
132 break;
133 }
134 }
135 return 0;
136}
137
138
139int afe_get_port_type(u16 port_id)
140{
141 int ret;
142
143 switch (port_id) {
144 case PRIMARY_I2S_RX:
145 case PCM_RX:
146 case SECONDARY_I2S_RX:
147 case MI2S_RX:
148 case HDMI_RX:
149 case SLIMBUS_0_RX:
150 case SLIMBUS_1_RX:
Joonwoo Park6572ac52012-07-10 17:17:00 -0700151 case SLIMBUS_2_RX:
152 case SLIMBUS_3_RX:
153 case SLIMBUS_4_RX:
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700154 case INT_BT_SCO_RX:
155 case INT_BT_A2DP_RX:
156 case INT_FM_RX:
157 case VOICE_PLAYBACK_TX:
158 case RT_PROXY_PORT_001_RX:
159 ret = MSM_AFE_PORT_TYPE_RX;
160 break;
161
162 case PRIMARY_I2S_TX:
163 case PCM_TX:
164 case SECONDARY_I2S_TX:
165 case MI2S_TX:
166 case DIGI_MIC_TX:
167 case VOICE_RECORD_TX:
168 case SLIMBUS_0_TX:
169 case SLIMBUS_1_TX:
Joonwoo Park6572ac52012-07-10 17:17:00 -0700170 case SLIMBUS_2_TX:
171 case SLIMBUS_3_TX:
172 case SLIMBUS_4_TX:
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700173 case INT_FM_TX:
174 case VOICE_RECORD_RX:
175 case INT_BT_SCO_TX:
176 case RT_PROXY_PORT_001_TX:
177 ret = MSM_AFE_PORT_TYPE_TX;
178 break;
179
180 default:
Joonwoo Park6572ac52012-07-10 17:17:00 -0700181 WARN_ON(1);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700182 pr_err("%s: invalid port id %d\n", __func__, port_id);
183 ret = -EINVAL;
184 }
185
186 return ret;
187}
188
189int afe_sizeof_cfg_cmd(u16 port_id)
190{
191 int ret_size;
192 switch (port_id) {
193 case PRIMARY_I2S_RX:
194 case PRIMARY_I2S_TX:
195 case SECONDARY_I2S_RX:
196 case SECONDARY_I2S_TX:
197 case MI2S_RX:
198 case MI2S_TX:
199 ret_size = SIZEOF_CFG_CMD(afe_param_id_i2s_cfg);
200 break;
201 case HDMI_RX:
202 ret_size =
203 SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg);
204 break;
205 case SLIMBUS_0_RX:
206 case SLIMBUS_0_TX:
207 case SLIMBUS_1_RX:
208 case SLIMBUS_1_TX:
209 ret_size = SIZEOF_CFG_CMD(afe_param_id_slimbus_cfg);
210 break;
211 case RT_PROXY_PORT_001_RX:
212 case RT_PROXY_PORT_001_TX:
213 ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
214 break;
215 case PCM_RX:
216 case PCM_TX:
217 default:
218 ret_size = SIZEOF_CFG_CMD(afe_param_id_pcm_cfg);
219 break;
220 }
221 return ret_size;
222}
223
224int afe_q6_interface_prepare(void)
225{
226 int ret = 0;
227
228 pr_debug("%s:", __func__);
229
230 if (this_afe.apr == NULL) {
231 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
232 0xFFFFFFFF, &this_afe);
233 if (this_afe.apr == NULL) {
234 pr_err("%s: Unable to register AFE\n", __func__);
235 ret = -ENODEV;
236 }
237 }
238 return ret;
239}
240static void afe_send_cal_block(int32_t path, u16 port_id)
241{
242 /* To come back */
243}
244
245void afe_send_cal(u16 port_id)
246{
247 pr_debug("%s\n", __func__);
248
249 if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
250 afe_send_cal_block(TX_CAL, port_id);
251 else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
252 afe_send_cal_block(RX_CAL, port_id);
253}
254
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700255int afe_port_start(u16 port_id, union afe_port_config *afe_config,
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700256 u32 rate) /* This function is no blocking */
257{
258 struct afe_port_cmd_device_start start;
259 struct afe_audioif_config_command config;
260 int ret;
261 int cfg_type;
262 int index = 0;
263
264 if (!afe_config) {
265 pr_err("%s: Error, no configuration data\n", __func__);
266 ret = -EINVAL;
267 return ret;
268 }
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700269 index = q6audio_get_port_index(port_id);
270 if (q6audio_validate_port(port_id) < 0)
271 return -EINVAL;
272
273 if ((port_id == RT_PROXY_DAI_001_RX) ||
274 (port_id == RT_PROXY_DAI_002_TX))
275 return -EINVAL;
276 if ((port_id == RT_PROXY_DAI_002_RX) ||
277 (port_id == RT_PROXY_DAI_001_TX))
278 port_id = VIRTUAL_ID_TO_PORTID(port_id);
279
280 ret = afe_q6_interface_prepare();
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700281 if (IS_ERR_VALUE(ret))
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700282 return ret;
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700283
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700284 if (q6audio_validate_port(port_id) < 0) {
285 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
286 port_id);
287 ret = -EINVAL;
288 goto fail_cmd;
289 }
290
291 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
292 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
Joonwoo Park6572ac52012-07-10 17:17:00 -0700293 config.hdr.pkt_size = sizeof(config);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700294 config.hdr.src_port = 0;
295 config.hdr.dest_port = 0;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700296 config.hdr.token = index;
Joonwoo Park6572ac52012-07-10 17:17:00 -0700297
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700298 switch (port_id) {
299 case PRIMARY_I2S_RX:
300 case PRIMARY_I2S_TX:
301 cfg_type = AFE_PARAM_ID_PCM_CONFIG;
302 break;
303 case PCM_RX:
304 case PCM_TX:
305 cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
306 break;
307 case SECONDARY_I2S_RX:
308 case SECONDARY_I2S_TX:
309 case MI2S_RX:
310 case MI2S_TX:
311 cfg_type = AFE_PARAM_ID_I2S_CONFIG;
312 break;
313 case HDMI_RX:
314 cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
315 break;
316 case SLIMBUS_0_RX:
317 case SLIMBUS_0_TX:
318 case SLIMBUS_1_RX:
319 case SLIMBUS_1_TX:
320 case SLIMBUS_2_RX:
321 case SLIMBUS_2_TX:
322 case SLIMBUS_3_RX:
323 case SLIMBUS_3_TX:
324 case SLIMBUS_4_RX:
325 case SLIMBUS_4_TX:
326 cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
327 break;
328 default:
329 pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
330 ret = -EINVAL;
331 goto fail_cmd;
332 }
333 config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
Joonwoo Park6572ac52012-07-10 17:17:00 -0700334 config.param.port_id = q6audio_get_port_id(port_id);
335 config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
336 sizeof(config.param);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700337 config.param.payload_address_lsw = 0x00;
338 config.param.payload_address_msw = 0x00;
339 config.param.mem_map_handle = 0x00;
340 config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
341 config.pdata.param_id = cfg_type;
Joonwoo Park6572ac52012-07-10 17:17:00 -0700342 config.pdata.param_size = sizeof(config.port);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700343
344 config.port = *afe_config;
345
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700346 atomic_set(&this_afe.state, 1);
347 atomic_set(&this_afe.status, 0);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700348 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
349 if (ret < 0) {
350 pr_err("%s: AFE enable for port %d failed\n", __func__,
351 port_id);
352 ret = -EINVAL;
353 goto fail_cmd;
354 }
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700355 ret = wait_event_timeout(this_afe.wait[index],
356 (atomic_read(&this_afe.state) == 0),
357 msecs_to_jiffies(TIMEOUT_MS));
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700358
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700359 if (!ret) {
360 pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
361 ret = -EINVAL;
362 goto fail_cmd;
363 }
364 if (atomic_read(&this_afe.status) != 0) {
365 pr_err("%s: config cmd failed\n", __func__);
366 ret = -EINVAL;
367 goto fail_cmd;
368 }
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700369 /* send AFE cal */
370 afe_send_cal(port_id);
371
372 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
373 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
374 start.hdr.pkt_size = sizeof(start);
375 start.hdr.src_port = 0;
376 start.hdr.dest_port = 0;
Joonwoo Park6572ac52012-07-10 17:17:00 -0700377 start.hdr.token = index;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700378 start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
Joonwoo Park6572ac52012-07-10 17:17:00 -0700379 start.port_id = q6audio_get_port_id(port_id);
380 pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
381 __func__, start.hdr.opcode, start.port_id);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700382
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700383 atomic_set(&this_afe.state, 1);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700384 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
385
386 if (IS_ERR_VALUE(ret)) {
387 pr_err("%s: AFE enable for port %d failed\n", __func__,
388 port_id);
389 ret = -EINVAL;
390 goto fail_cmd;
391 }
392
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700393 ret = wait_event_timeout(this_afe.wait[index],
394 (atomic_read(&this_afe.state) == 0),
395 msecs_to_jiffies(TIMEOUT_MS));
396
397 if (!ret) {
398 pr_err("%s: wait_event timeout PORT START\n", __func__);
399 ret = -EINVAL;
400 goto fail_cmd;
401 }
402 if (this_afe.task != current)
403 this_afe.task = current;
404
405 pr_debug("task_name = %s pid = %d\n",
406 this_afe.task->comm, this_afe.task->pid);
407
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700408 return 0;
409
410fail_cmd:
411 return ret;
412}
413
Joonwoo Park6572ac52012-07-10 17:17:00 -0700414int afe_get_port_index(u16 port_id)
415{
416 switch (port_id) {
417 case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
418 case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
419 case PCM_RX: return IDX_PCM_RX;
420 case PCM_TX: return IDX_PCM_TX;
421 case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
422 case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
423 case MI2S_RX: return IDX_MI2S_RX;
424 case MI2S_TX: return IDX_MI2S_TX;
425 case HDMI_RX: return IDX_HDMI_RX;
426 case RSVD_2: return IDX_RSVD_2;
427 case RSVD_3: return IDX_RSVD_3;
428 case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
429 case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
430 case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
431 case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
432 case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
433 case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
434 case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
435 case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
436 case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
437 case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
438 case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
439 case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
440 case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
441 case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
442 case INT_FM_RX: return IDX_INT_FM_RX;
443 case INT_FM_TX: return IDX_INT_FM_TX;
444 case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
445 case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
446 case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
447 case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
448
449 default: return -EINVAL;
450 }
451}
452
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700453int afe_open(u16 port_id,
454 union afe_port_config *afe_config, int rate)
455{
456 struct afe_port_cmd_device_start start;
457 struct afe_audioif_config_command config;
458 int ret = 0;
459 int cfg_type;
460 int index = 0;
461
462 if (!afe_config) {
463 pr_err("%s: Error, no configuration data\n", __func__);
464 ret = -EINVAL;
465 return ret;
466 }
467
468 pr_err("%s: %d %d\n", __func__, port_id, rate);
469
470 index = q6audio_get_port_index(port_id);
471 if (q6audio_validate_port(port_id) < 0)
472 return -EINVAL;
473
474 if ((port_id == RT_PROXY_DAI_001_RX) ||
475 (port_id == RT_PROXY_DAI_002_TX))
476 return -EINVAL;
477 if ((port_id == RT_PROXY_DAI_002_RX) ||
478 (port_id == RT_PROXY_DAI_001_TX))
479 port_id = VIRTUAL_ID_TO_PORTID(port_id);
480
481 ret = afe_q6_interface_prepare();
482 if (ret != 0)
483 return ret;
484
485 if (q6audio_validate_port(port_id) < 0) {
486 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
487 port_id);
488 ret = -EINVAL;
489 goto fail_cmd;
490 }
491
492 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
493 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
494 config.hdr.pkt_size = sizeof(config);
495 config.hdr.src_port = 0;
496 config.hdr.dest_port = 0;
497 config.hdr.token = index;
498 switch (port_id) {
499 case PRIMARY_I2S_RX:
500 case PRIMARY_I2S_TX:
501 cfg_type = AFE_PARAM_ID_I2S_CONFIG;
502 break;
503 case PCM_RX:
504 case PCM_TX:
505 cfg_type = AFE_PARAM_ID_PCM_CONFIG;
506 break;
507 case SECONDARY_I2S_RX:
508 case SECONDARY_I2S_TX:
509 case MI2S_RX:
510 case MI2S_TX:
511 cfg_type = AFE_PARAM_ID_I2S_CONFIG;
512 break;
513 case HDMI_RX:
514 cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
515 break;
516 case SLIMBUS_0_RX:
517 case SLIMBUS_0_TX:
518 case SLIMBUS_1_RX:
519 case SLIMBUS_1_TX:
520 case SLIMBUS_2_RX:
521 case SLIMBUS_2_TX:
522 case SLIMBUS_3_RX:
523 case SLIMBUS_3_TX:
524 case SLIMBUS_4_RX:
525 case SLIMBUS_4_TX:
526 cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
527 break;
528 default:
529 pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
530 ret = -EINVAL;
531 goto fail_cmd;
532 }
533 config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
534 config.param.port_id = q6audio_get_port_id(port_id);
535 config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr)
536 - sizeof(config.param);
537 config.param.payload_address_lsw = 0x00;
538 config.param.payload_address_msw = 0x00;
539 config.param.mem_map_handle = 0x00;
540 config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
541 config.pdata.param_id = cfg_type;
542 config.pdata.param_size = sizeof(config.port);
543
544 config.port = *afe_config;
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700545 pr_debug("%s: param PL size=%d iparam_size[%d][%d %d %d %d] param_id[%x]\n",
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700546 __func__, config.param.payload_size, config.pdata.param_size,
547 sizeof(config), sizeof(config.param), sizeof(config.port),
548 sizeof(struct apr_hdr), config.pdata.param_id);
549 atomic_set(&this_afe.state, 1);
550 atomic_set(&this_afe.status, 0);
551 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
552 if (ret < 0) {
553 pr_err("%s: AFE enable for port %d opcode[0x%x]failed\n",
554 __func__, port_id, cfg_type);
555 ret = -EINVAL;
556 goto fail_cmd;
557 }
558
559 ret = wait_event_timeout(this_afe.wait[index],
560 (atomic_read(&this_afe.state) == 0),
561 msecs_to_jiffies(TIMEOUT_MS));
562 if (!ret) {
563 pr_err("%s: wait_event timeout\n", __func__);
564 ret = -EINVAL;
565 goto fail_cmd;
566 }
567 if (atomic_read(&this_afe.status) != 0) {
568 pr_err("%s: config cmd failed\n", __func__);
569 ret = -EINVAL;
570 goto fail_cmd;
571 }
572 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
573 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
574 start.hdr.pkt_size = sizeof(start);
575 start.hdr.src_port = 0;
576 start.hdr.dest_port = 0;
577 start.hdr.token = index;
578 start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
579 start.port_id = q6audio_get_port_id(port_id);
580 pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
581 __func__, start.hdr.opcode, start.port_id);
582 atomic_set(&this_afe.state, 1);
583 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
584 if (ret < 0) {
585 pr_err("%s: AFE enable for port %d failed\n", __func__,
586 port_id);
587 ret = -EINVAL;
588 goto fail_cmd;
589 }
590 ret = wait_event_timeout(this_afe.wait[index],
591 (atomic_read(&this_afe.state) == 0),
592 msecs_to_jiffies(TIMEOUT_MS));
593 if (!ret) {
594 pr_err("%s: wait_event timeout\n", __func__);
595 ret = -EINVAL;
596 goto fail_cmd;
597 }
598
599 return 0;
600fail_cmd:
601 return ret;
602}
603
604int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
605{
606 struct afe_loopback_cfg_v1 lb_cmd;
607 int ret = 0;
608 int index = 0;
609
610 ret = afe_q6_interface_prepare();
611 if (ret != 0)
612 return ret;
613
614 index = q6audio_get_port_index(rx_port);
615 if (q6audio_validate_port(rx_port) < 0)
616 return -EINVAL;
617
618 lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
619 APR_HDR_LEN(20), APR_PKT_VER);
620 lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
621 sizeof(lb_cmd) - APR_HDR_SIZE);
622 lb_cmd.hdr.src_port = 0;
623 lb_cmd.hdr.dest_port = 0;
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700624 lb_cmd.hdr.token = index;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700625 lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
626 lb_cmd.param.port_id = tx_port;
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700627 lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
628 sizeof(struct afe_port_cmd_set_param_v2));
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700629 lb_cmd.param.payload_address_lsw = 0x00;
630 lb_cmd.param.payload_address_msw = 0x00;
631 lb_cmd.param.mem_map_handle = 0x00;
632 lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
633 lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700634 lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
635 sizeof(struct afe_port_param_data_v2);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700636
637 lb_cmd.dst_port_id = rx_port;
638 lb_cmd.routing_mode = LB_MODE_DEFAULT;
639 lb_cmd.enable = (enable ? 1 : 0);
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700640 lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700641 atomic_set(&this_afe.state, 1);
642
643 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
644 if (ret < 0) {
645 pr_err("%s: AFE loopback failed\n", __func__);
646 ret = -EINVAL;
647 goto done;
648 }
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700649 pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700650 ret = wait_event_timeout(this_afe.wait[index],
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700651 (atomic_read(&this_afe.state) == 0),
652 msecs_to_jiffies(TIMEOUT_MS));
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700653 if (!ret) {
654 pr_err("%s: wait_event timeout\n", __func__);
655 ret = -EINVAL;
656 }
657done:
658 return ret;
659}
660
661int afe_loopback_gain(u16 port_id, u16 volume)
662{
663 struct afe_loopback_gain_per_path_param set_param;
664 int ret = 0;
665 int index = 0;
666
667 if (this_afe.apr == NULL) {
668 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
669 0xFFFFFFFF, &this_afe);
670 pr_debug("%s: Register AFE\n", __func__);
671 if (this_afe.apr == NULL) {
672 pr_err("%s: Unable to register AFE\n", __func__);
673 ret = -ENODEV;
674 return ret;
675 }
676 }
677
678 if (q6audio_validate_port(port_id) < 0) {
679
680 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
681 port_id);
682 ret = -EINVAL;
683 goto fail_cmd;
684 }
685 index = q6audio_get_port_index(port_id);
686 if (q6audio_validate_port(port_id) < 0)
687 return -EINVAL;
688
689 /* RX ports numbers are even .TX ports numbers are odd. */
690 if (port_id % 2 == 0) {
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -0700691 pr_err("%s: Failed : afe loopback gain only for TX ports. port_id %d\n",
692 __func__, port_id);
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700693 ret = -EINVAL;
694 goto fail_cmd;
695 }
696
697 pr_debug("%s: %d %hX\n", __func__, port_id, volume);
698
699 set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
700 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
701 set_param.hdr.pkt_size = sizeof(set_param);
702 set_param.hdr.src_port = 0;
703 set_param.hdr.dest_port = 0;
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700704 set_param.hdr.token = index;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700705 set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
706
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700707 set_param.param.port_id = port_id;
708 set_param.param.payload_size =
709 (sizeof(struct afe_loopback_gain_per_path_param) -
710 sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700711 set_param.param.payload_address_lsw = 0;
712 set_param.param.payload_address_msw = 0;
713 set_param.param.mem_map_handle = 0;
714
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700715 set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
716 set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
717 set_param.pdata.param_size =
718 (set_param.param.payload_size -
719 sizeof(struct afe_port_param_data_v2));
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700720 set_param.rx_port_id = port_id;
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700721 set_param.gain = volume;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700722
723 atomic_set(&this_afe.state, 1);
724 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
725 if (ret < 0) {
726 pr_err("%s: AFE param set failed for port %d\n",
727 __func__, port_id);
728 ret = -EINVAL;
729 goto fail_cmd;
730 }
731
732 ret = wait_event_timeout(this_afe.wait[index],
Joonwoo Parkc76ad882012-08-14 18:05:33 -0700733 (atomic_read(&this_afe.state) == 0),
734 msecs_to_jiffies(TIMEOUT_MS));
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700735 if (ret < 0) {
736 pr_err("%s: wait_event timeout\n", __func__);
737 ret = -EINVAL;
738 goto fail_cmd;
739 }
740 return 0;
741fail_cmd:
742 return ret;
743}
744
745int afe_pseudo_port_start_nowait(u16 port_id)
746{
747 struct afe_pseudoport_start_command start;
748 int ret = 0;
749
750 pr_debug("%s: port_id=%d\n", __func__, port_id);
751 if (this_afe.apr == NULL) {
752 pr_err("%s: AFE APR is not registered\n", __func__);
753 return -ENODEV;
754 }
755
756
757 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
758 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
759 start.hdr.pkt_size = sizeof(start);
760 start.hdr.src_port = 0;
761 start.hdr.dest_port = 0;
762 start.hdr.token = 0;
763 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
764 start.port_id = port_id;
765 start.timing = 1;
766
767 atomic_set(&this_afe.state, 1);
768 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
769 if (ret < 0) {
770 pr_err("%s: AFE enable for port %d failed %d\n",
771 __func__, port_id, ret);
772 return -EINVAL;
773 }
774 return 0;
775}
776
777int afe_start_pseudo_port(u16 port_id)
778{
779 int ret = 0;
780 struct afe_pseudoport_start_command start;
781 int index = 0;
782
783 pr_debug("%s: port_id=%d\n", __func__, port_id);
784
785 ret = afe_q6_interface_prepare();
786 if (ret != 0)
787 return ret;
788
789 index = q6audio_get_port_index(port_id);
790 if (q6audio_validate_port(port_id) < 0)
791 return -EINVAL;
792
793 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
794 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
795 start.hdr.pkt_size = sizeof(start);
796 start.hdr.src_port = 0;
797 start.hdr.dest_port = 0;
798 start.hdr.token = 0;
799 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
800 start.port_id = port_id;
801 start.timing = 1;
802
803 start.hdr.token = index;
804 atomic_set(&this_afe.state, 1);
805 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
806 if (ret < 0) {
807 pr_err("%s: AFE enable for port %d failed %d\n",
808 __func__, port_id, ret);
809 return -EINVAL;
810 }
811
812 ret = wait_event_timeout(this_afe.wait[index],
813 (atomic_read(&this_afe.state) == 0),
814 msecs_to_jiffies(TIMEOUT_MS));
815 if (!ret) {
816 pr_err("%s: wait_event timeout\n", __func__);
817 return -EINVAL;
818 }
819
820 return 0;
821}
822
823int afe_pseudo_port_stop_nowait(u16 port_id)
824{
825 int ret = 0;
826 struct afe_pseudoport_stop_command stop;
827 int index = 0;
828
829 pr_debug("%s: port_id=%d\n", __func__, port_id);
830
831 if (this_afe.apr == NULL) {
832 pr_err("%s: AFE is already closed\n", __func__);
833 return -EINVAL;
834 }
835 index = q6audio_get_port_index(port_id);
836 if (q6audio_validate_port(port_id) < 0)
837 return -EINVAL;
838
839 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
840 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
841 stop.hdr.pkt_size = sizeof(stop);
842 stop.hdr.src_port = 0;
843 stop.hdr.dest_port = 0;
844 stop.hdr.token = 0;
845 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
846 stop.port_id = port_id;
847 stop.reserved = 0;
848
849 stop.hdr.token = index;
850 atomic_set(&this_afe.state, 1);
851 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
852 if (ret < 0) {
853 pr_err("%s: AFE close failed %d\n", __func__, ret);
854 return -EINVAL;
855 }
856
857 return 0;
858
859}
860
861int afe_stop_pseudo_port(u16 port_id)
862{
863 int ret = 0;
864 struct afe_pseudoport_stop_command stop;
865 int index = 0;
866
867 pr_debug("%s: port_id=%d\n", __func__, port_id);
868
869 if (this_afe.apr == NULL) {
870 pr_err("%s: AFE is already closed\n", __func__);
871 return -EINVAL;
872 }
873
874 index = q6audio_get_port_index(port_id);
875 if (q6audio_validate_port(port_id) < 0)
876 return -EINVAL;
877
878 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
879 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
880 stop.hdr.pkt_size = sizeof(stop);
881 stop.hdr.src_port = 0;
882 stop.hdr.dest_port = 0;
883 stop.hdr.token = 0;
884 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
885 stop.port_id = port_id;
886 stop.reserved = 0;
887
888 stop.hdr.token = index;
889 atomic_set(&this_afe.state, 1);
890 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
891 if (ret < 0) {
892 pr_err("%s: AFE close failed %d\n", __func__, ret);
893 return -EINVAL;
894 }
895
896 ret = wait_event_timeout(this_afe.wait[index],
897 (atomic_read(&this_afe.state) == 0),
898 msecs_to_jiffies(TIMEOUT_MS));
899 if (!ret) {
900 pr_err("%s: wait_event timeout\n", __func__);
901 return -EINVAL;
902 }
903
904 return 0;
905}
906
907/*bharath, memory map handle needs to be stored by AFE client */
908int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
909{
910 int ret = 0;
911 int cmd_size = 0;
912 void *payload = NULL;
913 void *mmap_region_cmd = NULL;
914 struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
915 struct afe_service_shared_map_region_payload *mregion_pl = NULL;
916 int index = 0;
917
918 pr_debug("%s:\n", __func__);
919
920 if (this_afe.apr == NULL) {
921 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
922 0xFFFFFFFF, &this_afe);
923 pr_debug("%s: Register AFE\n", __func__);
924 if (this_afe.apr == NULL) {
925 pr_err("%s: Unable to register AFE\n", __func__);
926 ret = -ENODEV;
927 return ret;
928 }
929 }
930
931 cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions) \
932 + sizeof(struct afe_service_shared_map_region_payload);
933
934 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
935 if (!mmap_region_cmd) {
936 pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
937 return -ENOMEM;
938 }
939
940 mregion = (struct afe_service_cmd_shared_mem_map_regions *)
941 mmap_region_cmd;
942 mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
943 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
944 mregion->hdr.pkt_size = sizeof(mregion);
945 mregion->hdr.src_port = 0;
946 mregion->hdr.dest_port = 0;
947 mregion->hdr.token = 0;
948 mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
Harmandeep Singhac1671b2012-06-22 15:34:45 -0700949 mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -0700950 mregion->num_regions = 1;
951 mregion->property_flag = 0x00;
952 /* Todo */
953 index = mregion->hdr.token = IDX_RSVD_2;
954
955 payload = ((u8 *) mmap_region_cmd +
956 sizeof(struct afe_service_cmd_shared_mem_map_regions));
957
958 mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
959
960 mregion_pl->shm_addr_lsw = dma_addr_p;
961 mregion_pl->shm_addr_msw = 0x00;
962 mregion_pl->mem_size_bytes = dma_buf_sz;
963
964 atomic_set(&this_afe.state, 1);
965 ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
966 if (ret < 0) {
967 pr_err("%s: AFE memory map cmd failed %d\n",
968 __func__, ret);
969 ret = -EINVAL;
970 return ret;
971 }
972
973 ret = wait_event_timeout(this_afe.wait[index],
974 (atomic_read(&this_afe.state) == 0),
975 msecs_to_jiffies(TIMEOUT_MS));
976 if (!ret) {
977 pr_err("%s: wait_event timeout\n", __func__);
978 ret = -EINVAL;
979 return ret;
980 }
981
982 return 0;
983}
984
985int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz)
986{
987 int ret = 0;
988 int cmd_size = 0;
989 void *payload = NULL;
990 void *mmap_region_cmd = NULL;
991 struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
992 struct afe_service_shared_map_region_payload *mregion_pl = NULL;
993 int index = 0;
994
995 pr_debug("%s:\n", __func__);
996
997 if (this_afe.apr == NULL) {
998 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
999 0xFFFFFFFF, &this_afe);
1000 pr_debug("%s: Register AFE\n", __func__);
1001 if (this_afe.apr == NULL) {
1002 pr_err("%s: Unable to register AFE\n", __func__);
1003 ret = -ENODEV;
1004 return ret;
1005 }
1006 }
1007 index = q6audio_get_port_index(port_id);
1008 if (q6audio_validate_port(port_id) < 0)
1009 return -EINVAL;
1010
1011 cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions)
1012 + sizeof(struct afe_service_shared_map_region_payload);
1013
1014 mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
1015 if (!mmap_region_cmd) {
1016 pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
1017 return -ENOMEM;
1018 }
1019 mregion = (struct afe_service_cmd_shared_mem_map_regions *)
1020 mmap_region_cmd;
1021 mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1022 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1023 mregion->hdr.pkt_size = sizeof(mregion);
1024 mregion->hdr.src_port = 0;
1025 mregion->hdr.dest_port = 0;
1026 mregion->hdr.token = 0;
1027 mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
Harmandeep Singhac1671b2012-06-22 15:34:45 -07001028 mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -07001029 mregion->num_regions = 1;
1030 mregion->property_flag = 0x00;
1031
1032 payload = ((u8 *) mmap_region_cmd +
1033 sizeof(struct afe_service_cmd_shared_mem_map_regions));
1034 mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
1035
1036 mregion_pl->shm_addr_lsw = dma_addr_p;
1037 mregion_pl->shm_addr_msw = 0x00;
1038 mregion_pl->mem_size_bytes = dma_buf_sz;
1039
1040 atomic_set(&this_afe.state, 1);
1041 ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
1042 if (ret < 0) {
1043 pr_err("%s: AFE memory map cmd failed %d\n",
1044 __func__, ret);
1045 ret = -EINVAL;
1046 return ret;
1047 }
1048 return 0;
1049}
1050
1051int afe_cmd_memory_unmap(u32 mem_map_handle)
1052{
1053 int ret = 0;
1054 struct afe_service_cmd_shared_mem_unmap_regions mregion;
1055 int index = 0;
1056
1057 pr_debug("%s:\n", __func__);
1058
1059 if (this_afe.apr == NULL) {
1060 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1061 0xFFFFFFFF, &this_afe);
1062 pr_debug("%s: Register AFE\n", __func__);
1063 if (this_afe.apr == NULL) {
1064 pr_err("%s: Unable to register AFE\n", __func__);
1065 ret = -ENODEV;
1066 return ret;
1067 }
1068 }
1069
1070 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1071 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1072 mregion.hdr.pkt_size = sizeof(mregion);
1073 mregion.hdr.src_port = 0;
1074 mregion.hdr.dest_port = 0;
1075 mregion.hdr.token = 0;
1076 mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
1077 mregion.mem_map_handle = mem_map_handle;
1078
1079 /* Todo */
1080 index = mregion.hdr.token = IDX_RSVD_2;
1081
1082 atomic_set(&this_afe.state, 1);
1083 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1084 if (ret < 0) {
1085 pr_err("%s: AFE memory unmap cmd failed %d\n",
1086 __func__, ret);
1087 ret = -EINVAL;
1088 return ret;
1089 }
1090
1091 ret = wait_event_timeout(this_afe.wait[index],
1092 (atomic_read(&this_afe.state) == 0),
1093 msecs_to_jiffies(TIMEOUT_MS));
1094 if (!ret) {
1095 pr_err("%s: wait_event timeout\n", __func__);
1096 ret = -EINVAL;
1097 return ret;
1098 }
1099 return 0;
1100}
1101
1102int afe_cmd_memory_unmap_nowait(u32 mem_map_handle)
1103{
1104 int ret = 0;
1105 struct afe_service_cmd_shared_mem_unmap_regions mregion;
1106
1107 pr_debug("%s:\n", __func__);
1108
1109 if (this_afe.apr == NULL) {
1110 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1111 0xFFFFFFFF, &this_afe);
1112 pr_debug("%s: Register AFE\n", __func__);
1113 if (this_afe.apr == NULL) {
1114 pr_err("%s: Unable to register AFE\n", __func__);
1115 ret = -ENODEV;
1116 return ret;
1117 }
1118 }
1119
1120 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1121 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1122 mregion.hdr.pkt_size = sizeof(mregion);
1123 mregion.hdr.src_port = 0;
1124 mregion.hdr.dest_port = 0;
1125 mregion.hdr.token = 0;
1126 mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
1127 mregion.mem_map_handle = mem_map_handle;
1128
1129 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1130 if (ret < 0) {
1131 pr_err("%s: AFE memory unmap cmd failed %d\n",
1132 __func__, ret);
1133 ret = -EINVAL;
1134 }
1135 return 0;
1136}
1137
1138int afe_register_get_events(u16 port_id,
1139 void (*cb) (uint32_t opcode,
1140 uint32_t token, uint32_t *payload, void *priv),
1141 void *private_data)
1142{
1143 int ret = 0;
1144 struct afe_service_cmd_register_rt_port_driver rtproxy;
1145
1146 pr_debug("%s:\n", __func__);
1147
1148 if (this_afe.apr == NULL) {
1149 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1150 0xFFFFFFFF, &this_afe);
1151 pr_debug("%s: Register AFE\n", __func__);
1152 if (this_afe.apr == NULL) {
1153 pr_err("%s: Unable to register AFE\n", __func__);
1154 ret = -ENODEV;
1155 return ret;
1156 }
1157 }
1158 if ((port_id == RT_PROXY_DAI_002_RX) ||
1159 (port_id == RT_PROXY_DAI_001_TX))
1160 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1161 else
1162 return -EINVAL;
1163
1164 if (port_id == RT_PROXY_PORT_001_TX) {
1165 this_afe.tx_cb = cb;
1166 this_afe.tx_private_data = private_data;
1167 } else if (port_id == RT_PROXY_PORT_001_RX) {
1168 this_afe.rx_cb = cb;
1169 this_afe.rx_private_data = private_data;
1170 }
1171
1172 rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1173 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1174 rtproxy.hdr.pkt_size = sizeof(rtproxy);
1175 rtproxy.hdr.src_port = 1;
1176 rtproxy.hdr.dest_port = 1;
1177 rtproxy.hdr.opcode = AFE_SERVICE_CMD_REGISTER_RT_PORT_DRIVER;
1178 rtproxy.port_id = port_id;
1179 rtproxy.reserved = 0;
1180
1181 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
1182 if (ret < 0) {
1183 pr_err("%s: AFE reg. rtproxy_event failed %d\n",
1184 __func__, ret);
1185 ret = -EINVAL;
1186 return ret;
1187 }
1188 return 0;
1189}
1190
1191int afe_unregister_get_events(u16 port_id)
1192{
1193 int ret = 0;
1194 struct afe_service_cmd_unregister_rt_port_driver rtproxy;
1195 int index = 0;
1196
1197 pr_debug("%s:\n", __func__);
1198
1199 if (this_afe.apr == NULL) {
1200 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1201 0xFFFFFFFF, &this_afe);
1202 pr_debug("%s: Register AFE\n", __func__);
1203 if (this_afe.apr == NULL) {
1204 pr_err("%s: Unable to register AFE\n", __func__);
1205 ret = -ENODEV;
1206 return ret;
1207 }
1208 }
1209 index = q6audio_get_port_index(port_id);
1210 if (q6audio_validate_port(port_id) < 0)
1211 return -EINVAL;
1212
1213 if ((port_id == RT_PROXY_DAI_002_RX) ||
1214 (port_id == RT_PROXY_DAI_001_TX))
1215 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1216 else
1217 return -EINVAL;
1218
1219 rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1220 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1221 rtproxy.hdr.pkt_size = sizeof(rtproxy);
1222 rtproxy.hdr.src_port = 0;
1223 rtproxy.hdr.dest_port = 0;
1224 rtproxy.hdr.token = 0;
1225 rtproxy.hdr.opcode = AFE_SERVICE_CMD_UNREGISTER_RT_PORT_DRIVER;
1226 rtproxy.port_id = port_id;
1227 rtproxy.reserved = 0;
1228
1229 rtproxy.hdr.token = index;
1230
1231 if (port_id == RT_PROXY_PORT_001_TX) {
1232 this_afe.tx_cb = NULL;
1233 this_afe.tx_private_data = NULL;
1234 } else if (port_id == RT_PROXY_PORT_001_RX) {
1235 this_afe.rx_cb = NULL;
1236 this_afe.rx_private_data = NULL;
1237 }
1238
1239 atomic_set(&this_afe.state, 1);
1240 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
1241 if (ret < 0) {
1242 pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
1243 __func__, ret);
1244 ret = -EINVAL;
1245 return ret;
1246 }
1247
1248 ret = wait_event_timeout(this_afe.wait[index],
1249 (atomic_read(&this_afe.state) == 0),
1250 msecs_to_jiffies(TIMEOUT_MS));
1251 if (!ret) {
1252 pr_err("%s: wait_event timeout\n", __func__);
1253 ret = -EINVAL;
1254 return ret;
1255 }
1256 return 0;
1257}
1258
1259int afe_rt_proxy_port_write(u32 buf_addr_p, u32 mem_map_handle, int bytes)
1260{
1261 int ret = 0;
1262 struct afe_port_data_cmd_rt_proxy_port_write_v2 afecmd_wr;
1263
1264 if (this_afe.apr == NULL) {
1265 pr_err("%s:register to AFE is not done\n", __func__);
1266 ret = -ENODEV;
1267 return ret;
1268 }
1269 pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
1270 buf_addr_p, bytes);
1271
1272 afecmd_wr.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1273 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1274 afecmd_wr.hdr.pkt_size = sizeof(afecmd_wr);
1275 afecmd_wr.hdr.src_port = 0;
1276 afecmd_wr.hdr.dest_port = 0;
1277 afecmd_wr.hdr.token = 0;
1278 afecmd_wr.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_WRITE_V2;
1279 afecmd_wr.port_id = RT_PROXY_PORT_001_TX;
1280 afecmd_wr.buffer_address_lsw = (uint32_t)buf_addr_p;
1281 afecmd_wr.buffer_address_msw = 0x00;
1282 afecmd_wr.mem_map_handle = mem_map_handle;
1283 afecmd_wr.available_bytes = bytes;
1284 afecmd_wr.reserved = 0;
1285
1286 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
1287 if (ret < 0) {
1288 pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
1289 __func__, afecmd_wr.port_id, ret);
1290 ret = -EINVAL;
1291 return ret;
1292 }
1293 return 0;
1294
1295}
1296
1297int afe_rt_proxy_port_read(u32 buf_addr_p, u32 mem_map_handle, int bytes)
1298{
1299 int ret = 0;
1300 struct afe_port_data_cmd_rt_proxy_port_read_v2 afecmd_rd;
1301
1302 if (this_afe.apr == NULL) {
1303 pr_err("%s: register to AFE is not done\n", __func__);
1304 ret = -ENODEV;
1305 return ret;
1306 }
1307 pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
1308 buf_addr_p, bytes);
1309
1310 afecmd_rd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1311 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1312 afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
1313 afecmd_rd.hdr.src_port = 0;
1314 afecmd_rd.hdr.dest_port = 0;
1315 afecmd_rd.hdr.token = 0;
1316 afecmd_rd.hdr.opcode = AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2;
1317 afecmd_rd.port_id = RT_PROXY_PORT_001_RX;
1318 afecmd_rd.buffer_address_lsw = (uint32_t)buf_addr_p;
1319 afecmd_rd.buffer_address_msw = 0x00;
1320 afecmd_rd.available_bytes = bytes;
1321
1322 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
1323 if (ret < 0) {
1324 pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
1325 __func__, afecmd_rd.port_id, ret);
1326 ret = -EINVAL;
1327 return ret;
1328 }
1329 return 0;
1330}
1331
1332#ifdef CONFIG_DEBUG_FS
1333static struct dentry *debugfs_afelb;
1334static struct dentry *debugfs_afelb_gain;
1335
1336static int afe_debug_open(struct inode *inode, struct file *file)
1337{
1338 file->private_data = inode->i_private;
1339 pr_info("debug intf %s\n", (char *) file->private_data);
1340 return 0;
1341}
1342
1343static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
1344{
1345 char *token;
1346 int base, cnt;
1347
1348 token = strsep(&buf, " ");
1349
1350 for (cnt = 0; cnt < num_of_par; cnt++) {
1351 if (token != NULL) {
1352 if ((token[1] == 'x') || (token[1] == 'X'))
1353 base = 16;
1354 else
1355 base = 10;
1356
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -07001357 if (kstrtoul(token, base, &param1[cnt]) != 0)
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -07001358 return -EINVAL;
1359
1360 token = strsep(&buf, " ");
1361 } else
1362 return -EINVAL;
1363 }
1364 return 0;
1365}
1366#define AFE_LOOPBACK_ON (1)
1367#define AFE_LOOPBACK_OFF (0)
1368static ssize_t afe_debug_write(struct file *filp,
1369 const char __user *ubuf, size_t cnt, loff_t *ppos)
1370{
1371 char *lb_str = filp->private_data;
1372 char lbuf[32];
1373 int rc;
1374 unsigned long param[5];
1375
1376 if (cnt > sizeof(lbuf) - 1)
1377 return -EINVAL;
1378
1379 rc = copy_from_user(lbuf, ubuf, cnt);
1380 if (rc)
1381 return -EFAULT;
1382
1383 lbuf[cnt] = '\0';
1384
1385 if (!strncmp(lb_str, "afe_loopback", 12)) {
1386 rc = afe_get_parameters(lbuf, param, 3);
1387 if (!rc) {
1388 pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
1389 param[2]);
1390
1391 if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
1392 AFE_LOOPBACK_OFF)) {
1393 pr_err("%s: Error, parameter 0 incorrect\n",
1394 __func__);
1395 rc = -EINVAL;
1396 goto afe_error;
1397 }
1398 if ((q6audio_validate_port(param[1]) < 0) ||
1399 (q6audio_validate_port(param[2])) < 0) {
1400 pr_err("%s: Error, invalid afe port\n",
1401 __func__);
1402 }
1403 if (this_afe.apr == NULL) {
1404 pr_err("%s: Error, AFE not opened\n", __func__);
1405 rc = -EINVAL;
1406 } else {
1407 rc = afe_loopback(param[0], param[1], param[2]);
1408 }
1409 } else {
1410 pr_err("%s: Error, invalid parameters\n", __func__);
1411 rc = -EINVAL;
1412 }
1413
1414 } else if (!strncmp(lb_str, "afe_loopback_gain", 17)) {
1415 rc = afe_get_parameters(lbuf, param, 2);
1416 if (!rc) {
1417 pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
1418
1419 if (q6audio_validate_port(param[0]) < 0) {
1420 pr_err("%s: Error, invalid afe port\n",
1421 __func__);
1422 rc = -EINVAL;
1423 goto afe_error;
1424 }
1425
1426 if (param[1] < 0 || param[1] > 100) {
Phani Kumar Uppalapati3f7b2472012-09-11 22:31:40 -07001427 pr_err("%s: Error, volume shoud be 0 to 100 percentage param = %lu\n",
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -07001428 __func__, param[1]);
1429 rc = -EINVAL;
1430 goto afe_error;
1431 }
1432
1433 param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
1434
1435 if (this_afe.apr == NULL) {
1436 pr_err("%s: Error, AFE not opened\n", __func__);
1437 rc = -EINVAL;
1438 } else {
1439 rc = afe_loopback_gain(param[0], param[1]);
1440 }
1441 } else {
1442 pr_err("%s: Error, invalid parameters\n", __func__);
1443 rc = -EINVAL;
1444 }
1445 }
1446
1447afe_error:
1448 if (rc == 0)
1449 rc = cnt;
1450 else
1451 pr_err("%s: rc = %d\n", __func__, rc);
1452
1453 return rc;
1454}
1455
1456static const struct file_operations afe_debug_fops = {
1457 .open = afe_debug_open,
1458 .write = afe_debug_write
1459};
1460
1461static void config_debug_fs_init(void)
1462{
1463 debugfs_afelb = debugfs_create_file("afe_loopback",
1464 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
1465 &afe_debug_fops);
1466
1467 debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
1468 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
1469 &afe_debug_fops);
1470}
1471static void config_debug_fs_exit(void)
1472{
1473 if (debugfs_afelb)
1474 debugfs_remove(debugfs_afelb);
1475 if (debugfs_afelb_gain)
1476 debugfs_remove(debugfs_afelb_gain);
1477}
1478#else
1479static void config_debug_fs_init(void)
1480{
1481 return;
1482}
1483static void config_debug_fs_exit(void)
1484{
1485 return;
1486}
1487#endif
1488int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
1489{
1490 struct afe_loopback_cfg_v1 cmd_sidetone;
1491 int ret = 0;
1492 int index = 0;
1493
1494 pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
1495 tx_port_id, rx_port_id, enable, gain);
1496 index = q6audio_get_port_index(rx_port_id);
1497 if (q6audio_validate_port(rx_port_id) < 0)
1498 return -EINVAL;
1499
1500 cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1501 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1502 cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
1503 cmd_sidetone.hdr.src_port = 0;
1504 cmd_sidetone.hdr.dest_port = 0;
1505 cmd_sidetone.hdr.token = 0;
1506 cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
1507 /* should it be rx or tx port id ?? , bharath*/
1508 cmd_sidetone.param.port_id = tx_port_id;
1509 /* size of data param & payload */
1510 cmd_sidetone.param.payload_size = (sizeof(cmd_sidetone) -
1511 sizeof(struct apr_hdr) -
1512 sizeof(struct afe_port_cmd_set_param_v2));
1513 cmd_sidetone.param.payload_address_lsw = 0x00;
1514 cmd_sidetone.param.payload_address_msw = 0x00;
1515 cmd_sidetone.param.mem_map_handle = 0x00;
1516 cmd_sidetone.pdata.module_id = AFE_MODULE_LOOPBACK;
1517 cmd_sidetone.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
1518 /* size of actual payload only */
1519 cmd_sidetone.pdata.param_size = cmd_sidetone.param.payload_size -
1520 sizeof(struct afe_port_param_data_v2);
1521
1522 cmd_sidetone.loopback_cfg_minor_version =
1523 AFE_API_VERSION_LOOPBACK_CONFIG;
1524 cmd_sidetone.dst_port_id = rx_port_id;
1525 cmd_sidetone.routing_mode = LB_MODE_SIDETONE;
1526 cmd_sidetone.enable = enable;
1527
1528 atomic_set(&this_afe.state, 1);
1529 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
1530 if (ret < 0) {
1531 pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
1532 __func__, tx_port_id, rx_port_id);
1533 ret = -EINVAL;
1534 goto fail_cmd;
1535 }
1536
1537 ret = wait_event_timeout(this_afe.wait[index],
1538 (atomic_read(&this_afe.state) == 0),
1539 msecs_to_jiffies(TIMEOUT_MS));
1540 if (ret < 0) {
1541 pr_err("%s: wait_event timeout\n", __func__);
1542 ret = -EINVAL;
1543 goto fail_cmd;
1544 }
1545 return 0;
1546fail_cmd:
1547 return ret;
1548}
1549
Joonwoo Park6572ac52012-07-10 17:17:00 -07001550int afe_validate_port(u16 port_id)
1551{
1552 int ret;
1553
1554 switch (port_id) {
1555 case PRIMARY_I2S_RX:
1556 case PRIMARY_I2S_TX:
1557 case PCM_RX:
1558 case PCM_TX:
1559 case SECONDARY_I2S_RX:
1560 case SECONDARY_I2S_TX:
1561 case MI2S_RX:
1562 case MI2S_TX:
1563 case HDMI_RX:
1564 case RSVD_2:
1565 case RSVD_3:
1566 case DIGI_MIC_TX:
1567 case VOICE_RECORD_RX:
1568 case VOICE_RECORD_TX:
1569 case VOICE_PLAYBACK_TX:
1570 case SLIMBUS_0_RX:
1571 case SLIMBUS_0_TX:
1572 case SLIMBUS_1_RX:
1573 case SLIMBUS_1_TX:
1574 case SLIMBUS_2_RX:
1575 case SLIMBUS_2_TX:
1576 case SLIMBUS_3_RX:
1577 case INT_BT_SCO_RX:
1578 case INT_BT_SCO_TX:
1579 case INT_BT_A2DP_RX:
1580 case INT_FM_RX:
1581 case INT_FM_TX:
1582 case RT_PROXY_PORT_001_RX:
1583 case RT_PROXY_PORT_001_TX:
1584 case SLIMBUS_4_RX:
1585 case SLIMBUS_4_TX:
1586 {
1587 ret = 0;
1588 break;
1589 }
1590
1591 default:
1592 ret = -EINVAL;
1593 }
1594
1595 return ret;
1596}
1597
1598int afe_convert_virtual_to_portid(u16 port_id)
1599{
1600 int ret;
1601
1602 /*
1603 * if port_id is virtual, convert to physical..
1604 * if port_id is already physical, return physical
1605 */
1606 if (afe_validate_port(port_id) < 0) {
1607 if (port_id == RT_PROXY_DAI_001_RX ||
1608 port_id == RT_PROXY_DAI_001_TX ||
1609 port_id == RT_PROXY_DAI_002_RX ||
1610 port_id == RT_PROXY_DAI_002_TX)
1611 ret = VIRTUAL_ID_TO_PORTID(port_id);
1612 else
1613 ret = -EINVAL;
1614 } else
1615 ret = port_id;
1616
1617 return ret;
1618}
Bharath Ramachandramurthy2e3168f2012-05-03 16:29:09 -07001619int afe_port_stop_nowait(int port_id)
1620{
1621 struct afe_port_cmd_device_stop stop;
1622 int ret = 0;
1623
1624 if (this_afe.apr == NULL) {
1625 pr_err("AFE is already closed\n");
1626 ret = -EINVAL;
1627 goto fail_cmd;
1628 }
1629 pr_debug("%s: port_id=%d\n", __func__, port_id);
1630 port_id = q6audio_convert_virtual_to_portid(port_id);
1631
1632 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1633 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1634 stop.hdr.pkt_size = sizeof(stop);
1635 stop.hdr.src_port = 0;
1636 stop.hdr.dest_port = 0;
1637 stop.hdr.token = 0;
1638 stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
1639 stop.port_id = port_id;
1640 stop.reserved = 0;
1641
1642 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1643
1644 if (IS_ERR_VALUE(ret)) {
1645 pr_err("%s: AFE close failed\n", __func__);
1646 ret = -EINVAL;
1647 }
1648
1649fail_cmd:
1650 return ret;
1651
1652}
1653
1654int afe_close(int port_id)
1655{
1656 struct afe_port_cmd_device_stop stop;
1657 int ret = 0;
1658 int index = 0;
1659
1660
1661 if (this_afe.apr == NULL) {
1662 pr_err("AFE is already closed\n");
1663 ret = -EINVAL;
1664 goto fail_cmd;
1665 }
1666 pr_debug("%s: port_id=%d\n", __func__, port_id);
1667
1668 index = q6audio_get_port_index(port_id);
1669 if (q6audio_validate_port(port_id) < 0)
1670 return -EINVAL;
1671
1672 port_id = q6audio_convert_virtual_to_portid(port_id);
1673
1674 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1675 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1676 stop.hdr.pkt_size = sizeof(stop);
1677 stop.hdr.src_port = 0;
1678 stop.hdr.dest_port = 0;
1679 stop.hdr.token = index;
1680 stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
1681 stop.port_id = q6audio_get_port_id(port_id);
1682 stop.reserved = 0;
1683
1684 atomic_set(&this_afe.state, 1);
1685 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1686
1687 if (ret < 0) {
1688 pr_err("%s: AFE close failed\n", __func__);
1689 ret = -EINVAL;
1690 goto fail_cmd;
1691 }
1692
1693 ret = wait_event_timeout(this_afe.wait[index],
1694 (atomic_read(&this_afe.state) == 0),
1695 msecs_to_jiffies(TIMEOUT_MS));
1696 if (!ret) {
1697 pr_err("%s: wait_event timeout\n", __func__);
1698 ret = -EINVAL;
1699 goto fail_cmd;
1700 }
1701fail_cmd:
1702 return ret;
1703}
1704
1705static int __init afe_init(void)
1706{
1707 int i = 0;
1708 atomic_set(&this_afe.state, 0);
1709 atomic_set(&this_afe.status, 0);
1710 this_afe.apr = NULL;
1711 for (i = 0; i < AFE_MAX_PORTS; i++)
1712 init_waitqueue_head(&this_afe.wait[i]);
1713
1714 config_debug_fs_init();
1715 return 0;
1716}
1717
1718static void __exit afe_exit(void)
1719{
1720 int i;
1721
1722 config_debug_fs_exit();
1723 for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
1724 if (afe_cal_addr[i].cal_paddr != 0)
1725 afe_cmd_memory_unmap_nowait(
1726 afe_cal_addr[i].cal_paddr);
1727 }
1728}
1729
1730device_initcall(afe_init);
1731__exitcall(afe_exit);