blob: 7b16adb5cd84119efaa441718e207b6ee933e8b6 [file] [log] [blame]
Ben Rombergerb7603232011-11-23 17:16:27 -08001/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/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>
Ben Rombergerb7603232011-11-23 17:16:27 -080020#include <mach/qdsp6v2/audio_acdb.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <sound/apr_audio.h>
22#include <sound/q6afe.h>
23
24struct afe_ctl {
25 void *apr;
26 atomic_t state;
27 atomic_t status;
28 wait_queue_head_t wait;
29 struct task_struct *task;
Laxminath Kasam32657ec2011-08-01 19:26:57 +053030 void (*tx_cb) (uint32_t opcode,
31 uint32_t token, uint32_t *payload, void *priv);
32 void (*rx_cb) (uint32_t opcode,
33 uint32_t token, uint32_t *payload, void *priv);
34 void *tx_private_data;
35 void *rx_private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036};
37
38static struct afe_ctl this_afe;
39
Ben Romberger9e792562012-02-24 12:29:01 -080040static struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
Ben Rombergerb7603232011-11-23 17:16:27 -080041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#define TIMEOUT_MS 1000
43#define Q6AFE_MAX_VOLUME 0x3FFF
44
45#define SIZEOF_CFG_CMD(y) \
46 (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
47
48static int32_t afe_callback(struct apr_client_data *data, void *priv)
49{
50 if (data->opcode == RESET_EVENTS) {
51 pr_debug("q6afe: reset event = %d %d apr[%p]\n",
52 data->reset_event, data->reset_proc, this_afe.apr);
53 if (this_afe.apr) {
54 apr_reset(this_afe.apr);
55 atomic_set(&this_afe.state, 0);
56 this_afe.apr = NULL;
57 }
58 /* send info to user */
59 pr_debug("task_name = %s pid = %d\n",
60 this_afe.task->comm, this_afe.task->pid);
61 send_sig(SIGUSR1, this_afe.task, 0);
Laxminath Kasam9bb28c62012-01-18 21:55:37 +053062 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063 }
64 if (data->payload_size) {
65 uint32_t *payload;
Laxminath Kasam32657ec2011-08-01 19:26:57 +053066 uint16_t port_id = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067 payload = data->payload;
Laxminath Kasam32657ec2011-08-01 19:26:57 +053068 pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
69 __func__, data->opcode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070 payload[0], payload[1]);
71 /* payload[1] contains the error status for response */
72 if (payload[1] != 0) {
73 atomic_set(&this_afe.status, -1);
74 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
75 __func__, payload[0], payload[1]);
76 }
77 if (data->opcode == APR_BASIC_RSP_RESULT) {
78 switch (payload[0]) {
79 case AFE_PORT_AUDIO_IF_CONFIG:
Kuirong Wanga36f2882012-04-02 19:45:26 -070080 case AFE_PORT_CMD_I2S_CONFIG:
Kiran Kandi5e809b02012-01-31 00:24:33 -080081 case AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080082 case AFE_PORT_AUDIO_SLIM_SCH_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083 case AFE_PORT_CMD_STOP:
84 case AFE_PORT_CMD_START:
85 case AFE_PORT_CMD_LOOPBACK:
86 case AFE_PORT_CMD_SIDETONE_CTL:
87 case AFE_PORT_CMD_SET_PARAM:
88 case AFE_PSEUDOPORT_CMD_START:
89 case AFE_PSEUDOPORT_CMD_STOP:
Laxminath Kasam885f5102011-07-14 10:20:21 +053090 case AFE_PORT_CMD_APPLY_GAIN:
Laxminath Kasam32657ec2011-08-01 19:26:57 +053091 case AFE_SERVICE_CMD_MEMORY_MAP:
92 case AFE_SERVICE_CMD_MEMORY_UNMAP:
93 case AFE_SERVICE_CMD_UNREG_RTPORT:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094 atomic_set(&this_afe.state, 0);
95 wake_up(&this_afe.wait);
96 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +053097 case AFE_SERVICE_CMD_REG_RTPORT:
98 break;
99 case AFE_SERVICE_CMD_RTPORT_WR:
100 port_id = RT_PROXY_PORT_001_TX;
101 break;
102 case AFE_SERVICE_CMD_RTPORT_RD:
103 port_id = RT_PROXY_PORT_001_RX;
104 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 default:
106 pr_err("Unknown cmd 0x%x\n",
107 payload[0]);
108 break;
109 }
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530110 } 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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 }
134 }
135 return 0;
136}
137
Neema Shettyfeea7742011-09-11 12:30:36 -0700138int afe_get_port_type(u16 port_id)
139{
140 int ret;
141
142 switch (port_id) {
143 case PRIMARY_I2S_RX:
144 case PCM_RX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700145 case SECONDARY_PCM_RX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700146 case SECONDARY_I2S_RX:
147 case MI2S_RX:
148 case HDMI_RX:
149 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800150 case SLIMBUS_1_RX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700151 case SLIMBUS_2_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700152 case SLIMBUS_3_RX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700153 case INT_BT_SCO_RX:
154 case INT_BT_A2DP_RX:
155 case INT_FM_RX:
156 case VOICE_PLAYBACK_TX:
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530157 case RT_PROXY_PORT_001_RX:
Helen Zeng8f925502012-03-05 16:50:17 -0800158 case SLIMBUS_4_RX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700159 ret = MSM_AFE_PORT_TYPE_RX;
160 break;
161
162 case PRIMARY_I2S_TX:
163 case PCM_TX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700164 case SECONDARY_PCM_TX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700165 case SECONDARY_I2S_TX:
166 case MI2S_TX:
167 case DIGI_MIC_TX:
168 case VOICE_RECORD_TX:
169 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800170 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700171 case SLIMBUS_2_TX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700172 case SLIMBUS_3_TX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700173 case INT_FM_TX:
174 case VOICE_RECORD_RX:
175 case INT_BT_SCO_TX:
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530176 case RT_PROXY_PORT_001_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800177 case SLIMBUS_4_TX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700178 ret = MSM_AFE_PORT_TYPE_TX;
179 break;
180
181 default:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800182 pr_err("%s: invalid port id %d\n", __func__, port_id);
Neema Shettyfeea7742011-09-11 12:30:36 -0700183 ret = -EINVAL;
184 }
185
186 return ret;
187}
188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189int afe_validate_port(u16 port_id)
190{
191 int ret;
192
193 switch (port_id) {
194 case PRIMARY_I2S_RX:
195 case PRIMARY_I2S_TX:
196 case PCM_RX:
197 case PCM_TX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700198 case SECONDARY_PCM_RX:
199 case SECONDARY_PCM_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 case SECONDARY_I2S_RX:
201 case SECONDARY_I2S_TX:
202 case MI2S_RX:
203 case MI2S_TX:
204 case HDMI_RX:
205 case RSVD_2:
206 case RSVD_3:
207 case DIGI_MIC_TX:
208 case VOICE_RECORD_RX:
209 case VOICE_RECORD_TX:
210 case VOICE_PLAYBACK_TX:
211 case SLIMBUS_0_RX:
212 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800213 case SLIMBUS_1_RX:
214 case SLIMBUS_1_TX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700215 case SLIMBUS_2_RX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700216 case SLIMBUS_2_TX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700217 case SLIMBUS_3_RX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700218 case SLIMBUS_3_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 case INT_BT_SCO_RX:
220 case INT_BT_SCO_TX:
221 case INT_BT_A2DP_RX:
222 case INT_FM_RX:
223 case INT_FM_TX:
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530224 case RT_PROXY_PORT_001_RX:
225 case RT_PROXY_PORT_001_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800226 case SLIMBUS_4_RX:
227 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 {
229 ret = 0;
230 break;
231 }
232
233 default:
234 ret = -EINVAL;
235 }
236
237 return ret;
238}
239
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530240int afe_convert_virtual_to_portid(u16 port_id)
241{
242 int ret;
243
244 /* if port_id is virtual, convert to physical..
245 * if port_id is already physical, return physical
246 */
247 if (afe_validate_port(port_id) < 0) {
248 if (port_id == RT_PROXY_DAI_001_RX ||
249 port_id == RT_PROXY_DAI_001_TX ||
250 port_id == RT_PROXY_DAI_002_RX ||
251 port_id == RT_PROXY_DAI_002_TX)
252 ret = VIRTUAL_ID_TO_PORTID(port_id);
253 else
254 ret = -EINVAL;
255 } else
256 ret = port_id;
257
258 return ret;
259}
260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261int afe_get_port_index(u16 port_id)
262{
263 switch (port_id) {
264 case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
265 case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
266 case PCM_RX: return IDX_PCM_RX;
267 case PCM_TX: return IDX_PCM_TX;
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700268 case SECONDARY_PCM_RX: return IDX_SECONDARY_PCM_RX;
269 case SECONDARY_PCM_TX: return IDX_SECONDARY_PCM_TX;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
271 case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
272 case MI2S_RX: return IDX_MI2S_RX;
273 case MI2S_TX: return IDX_MI2S_TX;
274 case HDMI_RX: return IDX_HDMI_RX;
275 case RSVD_2: return IDX_RSVD_2;
276 case RSVD_3: return IDX_RSVD_3;
277 case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
278 case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
279 case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
280 case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
281 case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
282 case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
Neema Shetty3c9d2862012-03-11 01:25:32 -0800283 case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
284 case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
Kiran Kandifd30c892012-05-21 23:03:26 -0700285 case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700286 case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
Neema Shetty74131ac2012-05-09 13:35:26 -0700287 case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
Helen Zeng38c3c962012-05-17 14:56:20 -0700288 case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
290 case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
291 case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
292 case INT_FM_RX: return IDX_INT_FM_RX;
293 case INT_FM_TX: return IDX_INT_FM_TX;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530294 case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
295 case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
Helen Zeng8f925502012-03-05 16:50:17 -0800296 case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
297 case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298
299 default: return -EINVAL;
300 }
301}
302
303int afe_sizeof_cfg_cmd(u16 port_id)
304{
305 int ret_size;
306 switch (port_id) {
307 case PRIMARY_I2S_RX:
308 case PRIMARY_I2S_TX:
309 case SECONDARY_I2S_RX:
310 case SECONDARY_I2S_TX:
311 case MI2S_RX:
312 case MI2S_TX:
313 ret_size = SIZEOF_CFG_CMD(afe_port_mi2s_cfg);
314 break;
315 case HDMI_RX:
Kiran Kandi5e809b02012-01-31 00:24:33 -0800316 ret_size = SIZEOF_CFG_CMD(afe_port_hdmi_multi_ch_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317 break;
318 case SLIMBUS_0_RX:
319 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800320 case SLIMBUS_1_RX:
321 case SLIMBUS_1_TX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700322 case SLIMBUS_2_RX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700323 case SLIMBUS_2_TX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700324 case SLIMBUS_3_RX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700325 case SLIMBUS_3_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800326 case SLIMBUS_4_RX:
327 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800328 ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530330 case RT_PROXY_PORT_001_RX:
331 case RT_PROXY_PORT_001_TX:
332 ret_size = SIZEOF_CFG_CMD(afe_port_rtproxy_cfg);
333 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 case PCM_RX:
335 case PCM_TX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700336 case SECONDARY_PCM_RX:
337 case SECONDARY_PCM_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338 default:
339 ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
340 break;
341 }
342 return ret_size;
343}
344
Jay Wang6a305432011-08-05 16:01:54 -0700345int afe_q6_interface_prepare(void)
346{
347 int ret = 0;
348
349 pr_debug("%s:", __func__);
350
351 if (this_afe.apr == NULL) {
352 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
353 0xFFFFFFFF, &this_afe);
354 pr_debug("%s: Register AFE\n", __func__);
355 if (this_afe.apr == NULL) {
356 pr_err("%s: Unable to register AFE\n", __func__);
357 ret = -ENODEV;
358 }
359 }
360 return ret;
361}
362
Ben Rombergerb7603232011-11-23 17:16:27 -0800363static void afe_send_cal_block(int32_t path, u16 port_id)
364{
365 int result = 0;
366 struct acdb_cal_block cal_block;
367 struct afe_port_cmd_set_param_no_payload afe_cal;
368 pr_debug("%s: path %d\n", __func__, path);
369
370 get_afe_cal(path, &cal_block);
371 if (cal_block.cal_size <= 0) {
372 pr_debug("%s: No AFE cal to send!\n", __func__);
373 goto done;
374 }
375
Ben Romberger9e792562012-02-24 12:29:01 -0800376 if ((afe_cal_addr[path].cal_paddr != cal_block.cal_paddr) ||
377 (cal_block.cal_size > afe_cal_addr[path].cal_size)) {
378 if (afe_cal_addr[path].cal_paddr != 0)
379 afe_cmd_memory_unmap_nowait(
380 afe_cal_addr[path].cal_paddr);
381
Ben Rombergerb7603232011-11-23 17:16:27 -0800382 afe_cmd_memory_map_nowait(cal_block.cal_paddr,
383 cal_block.cal_size);
Ben Romberger9e792562012-02-24 12:29:01 -0800384 afe_cal_addr[path].cal_paddr = cal_block.cal_paddr;
385 afe_cal_addr[path].cal_size = cal_block.cal_size;
Ben Rombergerb7603232011-11-23 17:16:27 -0800386 }
387
388 afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
389 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
390 afe_cal.hdr.pkt_size = sizeof(afe_cal);
391 afe_cal.hdr.src_port = 0;
392 afe_cal.hdr.dest_port = 0;
393 afe_cal.hdr.token = 0;
394 afe_cal.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
395 afe_cal.port_id = port_id;
396 afe_cal.payload_size = cal_block.cal_size;
397 afe_cal.payload_address = cal_block.cal_paddr;
398
399 pr_debug("%s: AFE cal sent for device port = %d, path = %d, "
400 "cal size = %d, cal addr = 0x%x\n", __func__,
401 port_id, path, cal_block.cal_size, cal_block.cal_paddr);
402
403 result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
404 if (result < 0) {
405 pr_err("%s: AFE cal for port %d failed\n",
406 __func__, port_id);
407 }
408
409 pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
410done:
411 return;
412}
413
414void afe_send_cal(u16 port_id)
415{
416 pr_debug("%s\n", __func__);
417
418 if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
419 afe_send_cal_block(TX_CAL, port_id);
420 else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
421 afe_send_cal_block(RX_CAL, port_id);
422}
423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
425 u32 rate) /* This function is no blocking */
426{
427 struct afe_port_start_command start;
428 struct afe_audioif_config_command config;
429 int ret;
430
431 if (!afe_config) {
432 pr_err("%s: Error, no configuration data\n", __func__);
433 ret = -EINVAL;
434 return ret;
435 }
Jeff Ohlstein293b91f2011-12-16 13:22:46 -0800436 pr_debug("%s: %d %d\n", __func__, port_id, rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530438 if ((port_id == RT_PROXY_DAI_001_RX) ||
439 (port_id == RT_PROXY_DAI_002_TX))
440 return -EINVAL;
441 if ((port_id == RT_PROXY_DAI_002_RX) ||
442 (port_id == RT_PROXY_DAI_001_TX))
443 port_id = VIRTUAL_ID_TO_PORTID(port_id);
444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 if (this_afe.apr == NULL) {
Jay Wang6a305432011-08-05 16:01:54 -0700446 pr_err("%s: AFE APR is not registered\n", __func__);
447 ret = -ENODEV;
448 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 }
Kiran Kandi5e809b02012-01-31 00:24:33 -0800450
451 if (port_id == HDMI_RX) {
452 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700453 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
Kiran Kandi5e809b02012-01-31 00:24:33 -0800454 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
455 config.hdr.src_port = 0;
456 config.hdr.dest_port = 0;
457 config.hdr.token = 0;
458 config.hdr.opcode = AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG;
459 } else {
460
461 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
462 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
463 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
464 config.hdr.src_port = 0;
465 config.hdr.dest_port = 0;
466 config.hdr.token = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800467 switch (port_id) {
468 case SLIMBUS_0_RX:
469 case SLIMBUS_0_TX:
470 case SLIMBUS_1_RX:
471 case SLIMBUS_1_TX:
472 case SLIMBUS_2_RX:
473 case SLIMBUS_2_TX:
474 case SLIMBUS_3_RX:
475 case SLIMBUS_3_TX:
476 case SLIMBUS_4_RX:
477 case SLIMBUS_4_TX:
478 config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
479 break;
Kuirong Wanga36f2882012-04-02 19:45:26 -0700480 case MI2S_TX:
481 case MI2S_RX:
482 case SECONDARY_I2S_RX:
483 case SECONDARY_I2S_TX:
484 case PRIMARY_I2S_RX:
485 case PRIMARY_I2S_TX:
486 /* AFE_PORT_CMD_I2S_CONFIG command is not supported
487 * in the LPASS EL 1.0. So we have to distiguish
488 * which AFE command, AFE_PORT_CMD_I2S_CONFIG or
489 * AFE_PORT_AUDIO_IF_CONFIG to use. If the format
490 * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used
491 * to make the backward compatible.
492 */
493 pr_debug("%s: afe_config->mi2s.format = %d\n", __func__,
494 afe_config->mi2s.format);
495 if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM)
496 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
497 else
498 config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
499 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800500 default:
501 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
502 break;
503 }
Kiran Kandi5e809b02012-01-31 00:24:33 -0800504 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505
506 if (afe_validate_port(port_id) < 0) {
507
508 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
509 port_id);
510 ret = -EINVAL;
511 goto fail_cmd;
512 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 config.port_id = port_id;
514 config.port = *afe_config;
515
516 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
517 if (ret < 0) {
518 pr_err("%s: AFE enable for port %d failed\n", __func__,
519 port_id);
520 ret = -EINVAL;
521 goto fail_cmd;
522 }
Ben Rombergerb7603232011-11-23 17:16:27 -0800523
524 /* send AFE cal */
525 afe_send_cal(port_id);
526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
528 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
529 start.hdr.pkt_size = sizeof(start);
530 start.hdr.src_port = 0;
531 start.hdr.dest_port = 0;
532 start.hdr.token = 0;
533 start.hdr.opcode = AFE_PORT_CMD_START;
534 start.port_id = port_id;
535 start.gain = 0x2000;
536 start.sample_rate = rate;
537
538 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
539
540 if (IS_ERR_VALUE(ret)) {
541 pr_err("%s: AFE enable for port %d failed\n", __func__,
542 port_id);
543 ret = -EINVAL;
544 goto fail_cmd;
545 }
546
547 if (this_afe.task != current)
548 this_afe.task = current;
549
550 pr_debug("task_name = %s pid = %d\n",
551 this_afe.task->comm, this_afe.task->pid);
552 return 0;
553
554fail_cmd:
555 return ret;
556}
557
558int afe_open(u16 port_id, union afe_port_config *afe_config, int rate)
559{
560 struct afe_port_start_command start;
561 struct afe_audioif_config_command config;
562 int ret = 0;
563
564 if (!afe_config) {
565 pr_err("%s: Error, no configuration data\n", __func__);
566 ret = -EINVAL;
567 return ret;
568 }
569
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800570 pr_debug("%s: %d %d\n", __func__, port_id, rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530572 if ((port_id == RT_PROXY_DAI_001_RX) ||
573 (port_id == RT_PROXY_DAI_002_TX))
574 return -EINVAL;
575 if ((port_id == RT_PROXY_DAI_002_RX) ||
576 (port_id == RT_PROXY_DAI_001_TX))
577 port_id = VIRTUAL_ID_TO_PORTID(port_id);
578
Jay Wang6a305432011-08-05 16:01:54 -0700579 ret = afe_q6_interface_prepare();
580 if (ret != 0)
581 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582
583 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
584 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
585 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
586 config.hdr.src_port = 0;
587 config.hdr.dest_port = 0;
588 config.hdr.token = 0;
Kuirong Wanga36f2882012-04-02 19:45:26 -0700589 switch (port_id) {
590 case SLIMBUS_0_RX:
591 case SLIMBUS_0_TX:
592 case SLIMBUS_1_RX:
593 case SLIMBUS_1_TX:
594 case SLIMBUS_2_RX:
595 case SLIMBUS_2_TX:
596 case SLIMBUS_3_RX:
597 case SLIMBUS_3_TX:
598 case SLIMBUS_4_RX:
599 case SLIMBUS_4_TX:
600 config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
601 break;
602 case MI2S_TX:
603 case MI2S_RX:
604 case SECONDARY_I2S_RX:
605 case SECONDARY_I2S_TX:
606 case PRIMARY_I2S_RX:
607 case PRIMARY_I2S_TX:
608 /* AFE_PORT_CMD_I2S_CONFIG command is not supported
609 * in the LPASS EL 1.0. So we have to distiguish
610 * which AFE command, AFE_PORT_CMD_I2S_CONFIG or
611 * AFE_PORT_AUDIO_IF_CONFIG to use. If the format
612 * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used
613 * to make the backward compatible.
614 */
615 pr_debug("%s: afe_config->mi2s.format = %d\n", __func__,
616 afe_config->mi2s.format);
617 if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM)
618 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
619 else
620 config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
621 break;
622 default:
623 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
624 break;
625 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626
627 if (afe_validate_port(port_id) < 0) {
628
629 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
630 port_id);
631 ret = -EINVAL;
632 goto fail_cmd;
633 }
634
635 config.port_id = port_id;
636 config.port = *afe_config;
637
638 atomic_set(&this_afe.state, 1);
639 atomic_set(&this_afe.status, 0);
640 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
641 if (ret < 0) {
642 pr_err("%s: AFE enable for port %d failed\n", __func__,
643 port_id);
644 ret = -EINVAL;
645 goto fail_cmd;
646 }
647
648 ret = wait_event_timeout(this_afe.wait,
649 (atomic_read(&this_afe.state) == 0),
650 msecs_to_jiffies(TIMEOUT_MS));
651 if (!ret) {
652 pr_err("%s: wait_event timeout\n", __func__);
653 ret = -EINVAL;
654 goto fail_cmd;
655 }
656 if (atomic_read(&this_afe.status) != 0) {
657 pr_err("%s: config cmd failed\n", __func__);
658 ret = -EINVAL;
659 goto fail_cmd;
660 }
661 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
662 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
663 start.hdr.pkt_size = sizeof(start);
664 start.hdr.src_port = 0;
665 start.hdr.dest_port = 0;
666 start.hdr.token = 0;
667 start.hdr.opcode = AFE_PORT_CMD_START;
668 start.port_id = port_id;
669 start.gain = 0x2000;
670 start.sample_rate = rate;
671
672 atomic_set(&this_afe.state, 1);
673 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
674 if (ret < 0) {
675 pr_err("%s: AFE enable for port %d failed\n", __func__,
676 port_id);
677 ret = -EINVAL;
678 goto fail_cmd;
679 }
680 ret = wait_event_timeout(this_afe.wait,
681 (atomic_read(&this_afe.state) == 0),
682 msecs_to_jiffies(TIMEOUT_MS));
683 if (!ret) {
684 pr_err("%s: wait_event timeout\n", __func__);
685 ret = -EINVAL;
686 goto fail_cmd;
687 }
688
689 if (this_afe.task != current)
690 this_afe.task = current;
691
692 pr_debug("task_name = %s pid = %d\n",
693 this_afe.task->comm, this_afe.task->pid);
694 return 0;
695fail_cmd:
696 return ret;
697}
698
Neema Shetty74131ac2012-05-09 13:35:26 -0700699int afe_loopback(u16 enable, u16 dst_port, u16 src_port)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700{
701 struct afe_loopback_command lb_cmd;
702 int ret = 0;
Jay Wang6a305432011-08-05 16:01:54 -0700703
704 ret = afe_q6_interface_prepare();
705 if (ret != 0)
706 return ret;
707
Neema Shetty74131ac2012-05-09 13:35:26 -0700708 if ((afe_get_port_type(dst_port) == MSM_AFE_PORT_TYPE_RX) &&
709 (afe_get_port_type(src_port) == MSM_AFE_PORT_TYPE_RX))
710 return afe_loopback_cfg(enable, dst_port, src_port,
711 LB_MODE_EC_REF_VOICE_AUDIO);
712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
714 APR_HDR_LEN(20), APR_PKT_VER);
715 lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
716 sizeof(lb_cmd) - APR_HDR_SIZE);
717 lb_cmd.hdr.src_port = 0;
718 lb_cmd.hdr.dest_port = 0;
719 lb_cmd.hdr.token = 0;
720 lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
Neema Shetty74131ac2012-05-09 13:35:26 -0700721 lb_cmd.tx_port_id = src_port;
722 lb_cmd.rx_port_id = dst_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 lb_cmd.mode = 0xFFFF;
724 lb_cmd.enable = (enable ? 1 : 0);
725 atomic_set(&this_afe.state, 1);
726
727 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
728 if (ret < 0) {
729 pr_err("%s: AFE loopback failed\n", __func__);
730 ret = -EINVAL;
731 goto done;
732 }
733 ret = wait_event_timeout(this_afe.wait,
734 (atomic_read(&this_afe.state) == 0),
735 msecs_to_jiffies(TIMEOUT_MS));
736 if (!ret) {
737 pr_err("%s: wait_event timeout\n", __func__);
738 ret = -EINVAL;
739 }
740done:
741 return ret;
742}
743
Neema Shetty74131ac2012-05-09 13:35:26 -0700744int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode)
745{
746 struct afe_port_cmd_set_param lp_cfg;
747 int ret = 0;
748
749 ret = afe_q6_interface_prepare();
750 if (ret != 0)
751 return ret;
752
753 pr_debug("%s: src_port %d, dst_port %d\n",
754 __func__, src_port, dst_port);
755
756 lp_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
757 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
758 lp_cfg.hdr.pkt_size = sizeof(lp_cfg);
759 lp_cfg.hdr.src_port = 0;
760 lp_cfg.hdr.dest_port = 0;
761 lp_cfg.hdr.token = 0;
762 lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
763
764 lp_cfg.port_id = src_port;
765 lp_cfg.payload_size = sizeof(struct afe_param_payload);
766 lp_cfg.payload_address = 0;
767
768 lp_cfg.payload.module_id = AFE_MODULE_LOOPBACK;
769 lp_cfg.payload.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
770 lp_cfg.payload.param_size = sizeof(struct afe_param_loopback_cfg);
771 lp_cfg.payload.reserved = 0;
772
773 lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
774 AFE_API_VERSION_LOOPBACK_CONFIG;
775 lp_cfg.payload.param.loopback_cfg.dst_port_id = dst_port;
776 lp_cfg.payload.param.loopback_cfg.routing_mode = mode;
777 lp_cfg.payload.param.loopback_cfg.enable = enable;
778 lp_cfg.payload.param.loopback_cfg.reserved = 0;
779
780 atomic_set(&this_afe.state, 1);
781 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lp_cfg);
782 if (ret < 0) {
783 pr_err("%s: AFE loopback config failed for src_port %d, dst_port %d\n",
784 __func__, src_port, dst_port);
785 ret = -EINVAL;
786 goto fail_cmd;
787 }
788
789 ret = wait_event_timeout(this_afe.wait,
790 (atomic_read(&this_afe.state) == 0),
791 msecs_to_jiffies(TIMEOUT_MS));
792 if (ret < 0) {
793 pr_err("%s: wait_event timeout\n", __func__);
794 ret = -EINVAL;
795 goto fail_cmd;
796 }
797 return 0;
798fail_cmd:
799 return ret;
800}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801
802int afe_loopback_gain(u16 port_id, u16 volume)
803{
804 struct afe_port_cmd_set_param set_param;
805 int ret = 0;
806
807 if (this_afe.apr == NULL) {
Jayasena Sangaraboina82435032011-07-26 15:23:00 -0700808 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
809 0xFFFFFFFF, &this_afe);
810 pr_debug("%s: Register AFE\n", __func__);
811 if (this_afe.apr == NULL) {
812 pr_err("%s: Unable to register AFE\n", __func__);
813 ret = -ENODEV;
814 return ret;
815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 }
817
818 if (afe_validate_port(port_id) < 0) {
819
820 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
821 port_id);
822 ret = -EINVAL;
823 goto fail_cmd;
824 }
825
826 /* RX ports numbers are even .TX ports numbers are odd. */
827 if (port_id % 2 == 0) {
828 pr_err("%s: Failed : afe loopback gain only for TX ports."
829 " port_id %d\n", __func__, port_id);
830 ret = -EINVAL;
831 goto fail_cmd;
832 }
833
834 pr_debug("%s: %d %hX\n", __func__, port_id, volume);
835
836 set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
837 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
838 set_param.hdr.pkt_size = sizeof(set_param);
839 set_param.hdr.src_port = 0;
840 set_param.hdr.dest_port = 0;
841 set_param.hdr.token = 0;
842 set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
843
844 set_param.port_id = port_id;
845 set_param.payload_size = sizeof(struct afe_param_payload);
846 set_param.payload_address = 0;
847
848 set_param.payload.module_id = AFE_MODULE_ID_PORT_INFO;
849 set_param.payload.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
850 set_param.payload.param_size = sizeof(struct afe_param_loopback_gain);
851 set_param.payload.reserved = 0;
852
853 set_param.payload.param.loopback_gain.gain = volume;
854 set_param.payload.param.loopback_gain.reserved = 0;
855
856 atomic_set(&this_afe.state, 1);
857 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
858 if (ret < 0) {
859 pr_err("%s: AFE param set failed for port %d\n",
860 __func__, port_id);
861 ret = -EINVAL;
862 goto fail_cmd;
863 }
864
865 ret = wait_event_timeout(this_afe.wait,
866 (atomic_read(&this_afe.state) == 0),
867 msecs_to_jiffies(TIMEOUT_MS));
868 if (ret < 0) {
869 pr_err("%s: wait_event timeout\n", __func__);
870 ret = -EINVAL;
871 goto fail_cmd;
872 }
873 return 0;
874fail_cmd:
875 return ret;
876}
877
Laxminath Kasam885f5102011-07-14 10:20:21 +0530878int afe_apply_gain(u16 port_id, u16 gain)
879{
880 struct afe_port_gain_command set_gain;
881 int ret = 0;
882
883 if (this_afe.apr == NULL) {
884 pr_err("%s: AFE is not opened\n", __func__);
885 ret = -EPERM;
886 goto fail_cmd;
887 }
888
889 if (afe_validate_port(port_id) < 0) {
890 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
891 port_id);
892 ret = -EINVAL;
893 goto fail_cmd;
894 }
895
896 /* RX ports numbers are even .TX ports numbers are odd. */
897 if (port_id % 2 == 0) {
898 pr_err("%s: Failed : afe apply gain only for TX ports."
899 " port_id %d\n", __func__, port_id);
900 ret = -EINVAL;
901 goto fail_cmd;
902 }
903
904 pr_debug("%s: %d %hX\n", __func__, port_id, gain);
905
906 set_gain.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
907 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
908 set_gain.hdr.pkt_size = sizeof(set_gain);
909 set_gain.hdr.src_port = 0;
910 set_gain.hdr.dest_port = 0;
911 set_gain.hdr.token = 0;
912 set_gain.hdr.opcode = AFE_PORT_CMD_APPLY_GAIN;
913
914 set_gain.port_id = port_id;
915 set_gain.gain = gain;
916
917 atomic_set(&this_afe.state, 1);
918 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_gain);
919 if (ret < 0) {
920 pr_err("%s: AFE Gain set failed for port %d\n",
921 __func__, port_id);
922 ret = -EINVAL;
923 goto fail_cmd;
924 }
925
926 ret = wait_event_timeout(this_afe.wait,
927 (atomic_read(&this_afe.state) == 0),
928 msecs_to_jiffies(TIMEOUT_MS));
929 if (ret < 0) {
930 pr_err("%s: wait_event timeout\n", __func__);
931 ret = -EINVAL;
932 goto fail_cmd;
933 }
934 return 0;
935fail_cmd:
936 return ret;
937}
Helen Zeng0705a5f2011-10-14 15:29:52 -0700938
939int afe_pseudo_port_start_nowait(u16 port_id)
940{
941 int ret = 0;
942 struct afe_pseudoport_start_command start;
943
944 pr_debug("%s: port_id=%d\n", __func__, port_id);
945 if (this_afe.apr == NULL) {
946 pr_err("%s: AFE APR is not registered\n", __func__);
947 return -ENODEV;
948 }
949
950
951 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
952 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
953 start.hdr.pkt_size = sizeof(start);
954 start.hdr.src_port = 0;
955 start.hdr.dest_port = 0;
956 start.hdr.token = 0;
957 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
958 start.port_id = port_id;
959 start.timing = 1;
960
961 atomic_set(&this_afe.state, 1);
962 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
963 if (ret < 0) {
964 pr_err("%s: AFE enable for port %d failed %d\n",
965 __func__, port_id, ret);
966 return -EINVAL;
967 }
968 return 0;
969}
970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971int afe_start_pseudo_port(u16 port_id)
972{
973 int ret = 0;
974 struct afe_pseudoport_start_command start;
975
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800976 pr_debug("%s: port_id=%d\n", __func__, port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977
Jay Wang6a305432011-08-05 16:01:54 -0700978 ret = afe_q6_interface_prepare();
979 if (ret != 0)
980 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700981
982 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
983 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
984 start.hdr.pkt_size = sizeof(start);
985 start.hdr.src_port = 0;
986 start.hdr.dest_port = 0;
987 start.hdr.token = 0;
988 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
989 start.port_id = port_id;
990 start.timing = 1;
991
992 atomic_set(&this_afe.state, 1);
993 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
994 if (ret < 0) {
995 pr_err("%s: AFE enable for port %d failed %d\n",
996 __func__, port_id, ret);
Helen Zeng0705a5f2011-10-14 15:29:52 -0700997 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 }
999
1000 ret = wait_event_timeout(this_afe.wait,
1001 (atomic_read(&this_afe.state) == 0),
1002 msecs_to_jiffies(TIMEOUT_MS));
1003 if (!ret) {
1004 pr_err("%s: wait_event timeout\n", __func__);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001005 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 }
1007
1008 return 0;
1009}
1010
Helen Zeng0705a5f2011-10-14 15:29:52 -07001011int afe_pseudo_port_stop_nowait(u16 port_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012{
1013 int ret = 0;
1014 struct afe_pseudoport_stop_command stop;
1015
Helen Zeng0705a5f2011-10-14 15:29:52 -07001016 pr_debug("%s: port_id=%d\n", __func__, port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017
1018 if (this_afe.apr == NULL) {
1019 pr_err("%s: AFE is already closed\n", __func__);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001020 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 }
1022
1023 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1024 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1025 stop.hdr.pkt_size = sizeof(stop);
1026 stop.hdr.src_port = 0;
1027 stop.hdr.dest_port = 0;
1028 stop.hdr.token = 0;
1029 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
1030 stop.port_id = port_id;
1031 stop.reserved = 0;
1032
1033 atomic_set(&this_afe.state, 1);
1034 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1035 if (ret < 0) {
1036 pr_err("%s: AFE close failed %d\n", __func__, ret);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001037 return -EINVAL;
1038 }
1039
1040 return 0;
1041
1042}
1043
1044int afe_stop_pseudo_port(u16 port_id)
1045{
1046 int ret = 0;
1047 struct afe_pseudoport_stop_command stop;
1048
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001049 pr_debug("%s: port_id=%d\n", __func__, port_id);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001050
1051 if (this_afe.apr == NULL) {
1052 pr_err("%s: AFE is already closed\n", __func__);
1053 return -EINVAL;
1054 }
1055
1056 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1057 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1058 stop.hdr.pkt_size = sizeof(stop);
1059 stop.hdr.src_port = 0;
1060 stop.hdr.dest_port = 0;
1061 stop.hdr.token = 0;
1062 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
1063 stop.port_id = port_id;
1064 stop.reserved = 0;
1065
1066 atomic_set(&this_afe.state, 1);
1067 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1068 if (ret < 0) {
1069 pr_err("%s: AFE close failed %d\n", __func__, ret);
1070 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 }
1072
1073 ret = wait_event_timeout(this_afe.wait,
1074 (atomic_read(&this_afe.state) == 0),
1075 msecs_to_jiffies(TIMEOUT_MS));
1076 if (!ret) {
1077 pr_err("%s: wait_event timeout\n", __func__);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001078 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 }
1080
1081 return 0;
1082}
1083
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301084int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
1085{
1086 int ret = 0;
1087 struct afe_cmd_memory_map mregion;
1088
1089 pr_debug("%s:\n", __func__);
1090
1091 if (this_afe.apr == NULL) {
1092 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1093 0xFFFFFFFF, &this_afe);
1094 pr_debug("%s: Register AFE\n", __func__);
1095 if (this_afe.apr == NULL) {
1096 pr_err("%s: Unable to register AFE\n", __func__);
1097 ret = -ENODEV;
1098 return ret;
1099 }
1100 }
1101
1102 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1103 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1104 mregion.hdr.pkt_size = sizeof(mregion);
1105 mregion.hdr.src_port = 0;
1106 mregion.hdr.dest_port = 0;
1107 mregion.hdr.token = 0;
1108 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
1109 mregion.phy_addr = dma_addr_p;
1110 mregion.mem_sz = dma_buf_sz;
1111 mregion.mem_id = 0;
1112 mregion.rsvd = 0;
1113
1114 atomic_set(&this_afe.state, 1);
1115 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1116 if (ret < 0) {
1117 pr_err("%s: AFE memory map cmd failed %d\n",
1118 __func__, ret);
1119 ret = -EINVAL;
1120 return ret;
1121 }
1122
1123 ret = wait_event_timeout(this_afe.wait,
1124 (atomic_read(&this_afe.state) == 0),
1125 msecs_to_jiffies(TIMEOUT_MS));
1126 if (!ret) {
1127 pr_err("%s: wait_event timeout\n", __func__);
1128 ret = -EINVAL;
1129 return ret;
1130 }
1131
1132 return 0;
1133}
1134
Ben Rombergerb7603232011-11-23 17:16:27 -08001135int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz)
1136{
1137 int ret = 0;
1138 struct afe_cmd_memory_map mregion;
1139
1140 pr_debug("%s:\n", __func__);
1141
1142 if (this_afe.apr == NULL) {
1143 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1144 0xFFFFFFFF, &this_afe);
1145 pr_debug("%s: Register AFE\n", __func__);
1146 if (this_afe.apr == NULL) {
1147 pr_err("%s: Unable to register AFE\n", __func__);
1148 ret = -ENODEV;
1149 return ret;
1150 }
1151 }
1152
1153 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1154 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1155 mregion.hdr.pkt_size = sizeof(mregion);
1156 mregion.hdr.src_port = 0;
1157 mregion.hdr.dest_port = 0;
1158 mregion.hdr.token = 0;
1159 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
1160 mregion.phy_addr = dma_addr_p;
1161 mregion.mem_sz = dma_buf_sz;
1162 mregion.mem_id = 0;
1163 mregion.rsvd = 0;
1164
1165 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1166 if (ret < 0) {
1167 pr_err("%s: AFE memory map cmd failed %d\n",
1168 __func__, ret);
1169 ret = -EINVAL;
1170 }
1171 return 0;
1172}
1173
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301174int afe_cmd_memory_unmap(u32 dma_addr_p)
1175{
1176 int ret = 0;
1177 struct afe_cmd_memory_unmap mregion;
1178
1179 pr_debug("%s:\n", __func__);
1180
1181 if (this_afe.apr == NULL) {
1182 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1183 0xFFFFFFFF, &this_afe);
1184 pr_debug("%s: Register AFE\n", __func__);
1185 if (this_afe.apr == NULL) {
1186 pr_err("%s: Unable to register AFE\n", __func__);
1187 ret = -ENODEV;
1188 return ret;
1189 }
1190 }
1191
1192 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1193 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1194 mregion.hdr.pkt_size = sizeof(mregion);
1195 mregion.hdr.src_port = 0;
1196 mregion.hdr.dest_port = 0;
1197 mregion.hdr.token = 0;
1198 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
1199 mregion.phy_addr = dma_addr_p;
1200
1201 atomic_set(&this_afe.state, 1);
1202 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1203 if (ret < 0) {
Ben Rombergerb7603232011-11-23 17:16:27 -08001204 pr_err("%s: AFE memory unmap cmd failed %d\n",
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301205 __func__, ret);
1206 ret = -EINVAL;
1207 return ret;
1208 }
1209
1210 ret = wait_event_timeout(this_afe.wait,
1211 (atomic_read(&this_afe.state) == 0),
1212 msecs_to_jiffies(TIMEOUT_MS));
1213 if (!ret) {
1214 pr_err("%s: wait_event timeout\n", __func__);
1215 ret = -EINVAL;
1216 return ret;
1217 }
Ben Rombergerb7603232011-11-23 17:16:27 -08001218 return 0;
1219}
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301220
Ben Rombergerb7603232011-11-23 17:16:27 -08001221int afe_cmd_memory_unmap_nowait(u32 dma_addr_p)
1222{
1223 int ret = 0;
1224 struct afe_cmd_memory_unmap mregion;
1225
1226 pr_debug("%s:\n", __func__);
1227
1228 if (this_afe.apr == NULL) {
1229 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1230 0xFFFFFFFF, &this_afe);
1231 pr_debug("%s: Register AFE\n", __func__);
1232 if (this_afe.apr == NULL) {
1233 pr_err("%s: Unable to register AFE\n", __func__);
1234 ret = -ENODEV;
1235 return ret;
1236 }
1237 }
1238
1239 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1240 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1241 mregion.hdr.pkt_size = sizeof(mregion);
1242 mregion.hdr.src_port = 0;
1243 mregion.hdr.dest_port = 0;
1244 mregion.hdr.token = 0;
1245 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
1246 mregion.phy_addr = dma_addr_p;
1247
1248 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1249 if (ret < 0) {
1250 pr_err("%s: AFE memory unmap cmd failed %d\n",
1251 __func__, ret);
1252 ret = -EINVAL;
1253 }
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301254 return 0;
1255}
1256
1257int afe_register_get_events(u16 port_id,
1258 void (*cb) (uint32_t opcode,
1259 uint32_t token, uint32_t *payload, void *priv),
1260 void *private_data)
1261{
1262 int ret = 0;
1263 struct afe_cmd_reg_rtport rtproxy;
1264
1265 pr_debug("%s:\n", __func__);
1266
1267 if (this_afe.apr == NULL) {
1268 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1269 0xFFFFFFFF, &this_afe);
1270 pr_debug("%s: Register AFE\n", __func__);
1271 if (this_afe.apr == NULL) {
1272 pr_err("%s: Unable to register AFE\n", __func__);
1273 ret = -ENODEV;
1274 return ret;
1275 }
1276 }
1277 if ((port_id == RT_PROXY_DAI_002_RX) ||
1278 (port_id == RT_PROXY_DAI_001_TX))
1279 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1280 else
1281 return -EINVAL;
1282
1283 if (port_id == RT_PROXY_PORT_001_TX) {
1284 this_afe.tx_cb = cb;
1285 this_afe.tx_private_data = private_data;
1286 } else if (port_id == RT_PROXY_PORT_001_RX) {
1287 this_afe.rx_cb = cb;
1288 this_afe.rx_private_data = private_data;
1289 }
1290
1291 rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1292 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1293 rtproxy.hdr.pkt_size = sizeof(rtproxy);
1294 rtproxy.hdr.src_port = 1;
1295 rtproxy.hdr.dest_port = 1;
1296 rtproxy.hdr.token = 0;
1297 rtproxy.hdr.opcode = AFE_SERVICE_CMD_REG_RTPORT;
1298 rtproxy.port_id = port_id;
1299 rtproxy.rsvd = 0;
1300
1301 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
1302 if (ret < 0) {
1303 pr_err("%s: AFE reg. rtproxy_event failed %d\n",
1304 __func__, ret);
1305 ret = -EINVAL;
1306 return ret;
1307 }
1308 return 0;
1309}
1310
1311int afe_unregister_get_events(u16 port_id)
1312{
1313 int ret = 0;
1314 struct afe_cmd_unreg_rtport rtproxy;
1315
1316 pr_debug("%s:\n", __func__);
1317
1318 if (this_afe.apr == NULL) {
1319 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1320 0xFFFFFFFF, &this_afe);
1321 pr_debug("%s: Register AFE\n", __func__);
1322 if (this_afe.apr == NULL) {
1323 pr_err("%s: Unable to register AFE\n", __func__);
1324 ret = -ENODEV;
1325 return ret;
1326 }
1327 }
1328 if ((port_id == RT_PROXY_DAI_002_RX) ||
1329 (port_id == RT_PROXY_DAI_001_TX))
1330 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1331 else
1332 return -EINVAL;
1333
1334 rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1335 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1336 rtproxy.hdr.pkt_size = sizeof(rtproxy);
1337 rtproxy.hdr.src_port = 0;
1338 rtproxy.hdr.dest_port = 0;
1339 rtproxy.hdr.token = 0;
1340 rtproxy.hdr.opcode = AFE_SERVICE_CMD_UNREG_RTPORT;
1341 rtproxy.port_id = port_id;
1342 rtproxy.rsvd = 0;
1343
1344 if (port_id == RT_PROXY_PORT_001_TX) {
1345 this_afe.tx_cb = NULL;
1346 this_afe.tx_private_data = NULL;
1347 } else if (port_id == RT_PROXY_PORT_001_RX) {
1348 this_afe.rx_cb = NULL;
1349 this_afe.rx_private_data = NULL;
1350 }
1351
1352 atomic_set(&this_afe.state, 1);
1353 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
1354 if (ret < 0) {
1355 pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
1356 __func__, ret);
1357 ret = -EINVAL;
1358 return ret;
1359 }
1360
1361 ret = wait_event_timeout(this_afe.wait,
1362 (atomic_read(&this_afe.state) == 0),
1363 msecs_to_jiffies(TIMEOUT_MS));
1364 if (!ret) {
1365 pr_err("%s: wait_event timeout\n", __func__);
1366 ret = -EINVAL;
1367 return ret;
1368 }
1369 return 0;
1370}
1371
1372int afe_rt_proxy_port_write(u32 buf_addr_p, int bytes)
1373{
1374 int ret = 0;
1375 struct afe_cmd_rtport_wr afecmd_wr;
1376
1377 if (this_afe.apr == NULL) {
1378 pr_err("%s:register to AFE is not done\n", __func__);
1379 ret = -ENODEV;
1380 return ret;
1381 }
1382 pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
1383 buf_addr_p, bytes);
1384
1385 afecmd_wr.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1386 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1387 afecmd_wr.hdr.pkt_size = sizeof(afecmd_wr);
1388 afecmd_wr.hdr.src_port = 0;
1389 afecmd_wr.hdr.dest_port = 0;
1390 afecmd_wr.hdr.token = 0;
1391 afecmd_wr.hdr.opcode = AFE_SERVICE_CMD_RTPORT_WR;
1392 afecmd_wr.buf_addr = (uint32_t)buf_addr_p;
1393 afecmd_wr.port_id = RT_PROXY_PORT_001_TX;
1394 afecmd_wr.bytes_avail = bytes;
1395 afecmd_wr.rsvd = 0;
1396
1397 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
1398 if (ret < 0) {
1399 pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
1400 __func__, afecmd_wr.port_id, ret);
1401 ret = -EINVAL;
1402 return ret;
1403 }
1404 return 0;
1405
1406}
1407
1408int afe_rt_proxy_port_read(u32 buf_addr_p, int bytes)
1409{
1410 int ret = 0;
1411 struct afe_cmd_rtport_rd afecmd_rd;
1412
1413 if (this_afe.apr == NULL) {
1414 pr_err("%s: register to AFE is not done\n", __func__);
1415 ret = -ENODEV;
1416 return ret;
1417 }
1418 pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
1419 buf_addr_p, bytes);
1420
1421 afecmd_rd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1422 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1423 afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
1424 afecmd_rd.hdr.src_port = 0;
1425 afecmd_rd.hdr.dest_port = 0;
1426 afecmd_rd.hdr.token = 0;
1427 afecmd_rd.hdr.opcode = AFE_SERVICE_CMD_RTPORT_RD;
1428 afecmd_rd.buf_addr = (uint32_t)buf_addr_p;
1429 afecmd_rd.port_id = RT_PROXY_PORT_001_RX;
1430 afecmd_rd.bytes_avail = bytes;
1431 afecmd_rd.rsvd = 0;
1432
1433 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
1434 if (ret < 0) {
1435 pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
1436 __func__, afecmd_rd.port_id, ret);
1437 ret = -EINVAL;
1438 return ret;
1439 }
1440 return 0;
1441}
1442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443#ifdef CONFIG_DEBUG_FS
1444static struct dentry *debugfs_afelb;
1445static struct dentry *debugfs_afelb_gain;
1446
1447static int afe_debug_open(struct inode *inode, struct file *file)
1448{
1449 file->private_data = inode->i_private;
1450 pr_info("debug intf %s\n", (char *) file->private_data);
1451 return 0;
1452}
1453
1454static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
1455{
1456 char *token;
1457 int base, cnt;
1458
1459 token = strsep(&buf, " ");
1460
1461 for (cnt = 0; cnt < num_of_par; cnt++) {
1462 if (token != NULL) {
1463 if ((token[1] == 'x') || (token[1] == 'X'))
1464 base = 16;
1465 else
1466 base = 10;
1467
1468 if (strict_strtoul(token, base, &param1[cnt]) != 0)
1469 return -EINVAL;
1470
1471 token = strsep(&buf, " ");
1472 } else
1473 return -EINVAL;
1474 }
1475 return 0;
1476}
1477#define AFE_LOOPBACK_ON (1)
1478#define AFE_LOOPBACK_OFF (0)
1479static ssize_t afe_debug_write(struct file *filp,
1480 const char __user *ubuf, size_t cnt, loff_t *ppos)
1481{
1482 char *lb_str = filp->private_data;
1483 char lbuf[32];
1484 int rc;
1485 unsigned long param[5];
1486
1487 if (cnt > sizeof(lbuf) - 1)
1488 return -EINVAL;
1489
1490 rc = copy_from_user(lbuf, ubuf, cnt);
1491 if (rc)
1492 return -EFAULT;
1493
1494 lbuf[cnt] = '\0';
1495
1496 if (!strcmp(lb_str, "afe_loopback")) {
1497 rc = afe_get_parameters(lbuf, param, 3);
1498 if (!rc) {
1499 pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
1500 param[2]);
1501
1502 if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
1503 AFE_LOOPBACK_OFF)) {
1504 pr_err("%s: Error, parameter 0 incorrect\n",
1505 __func__);
1506 rc = -EINVAL;
1507 goto afe_error;
1508 }
1509 if ((afe_validate_port(param[1]) < 0) ||
1510 (afe_validate_port(param[2])) < 0) {
1511 pr_err("%s: Error, invalid afe port\n",
1512 __func__);
1513 }
1514 if (this_afe.apr == NULL) {
1515 pr_err("%s: Error, AFE not opened\n", __func__);
1516 rc = -EINVAL;
1517 } else {
1518 rc = afe_loopback(param[0], param[1], param[2]);
1519 }
1520 } else {
1521 pr_err("%s: Error, invalid parameters\n", __func__);
1522 rc = -EINVAL;
1523 }
1524
1525 } else if (!strcmp(lb_str, "afe_loopback_gain")) {
1526 rc = afe_get_parameters(lbuf, param, 2);
1527 if (!rc) {
1528 pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
1529
1530 if (afe_validate_port(param[0]) < 0) {
1531 pr_err("%s: Error, invalid afe port\n",
1532 __func__);
1533 rc = -EINVAL;
1534 goto afe_error;
1535 }
1536
1537 if (param[1] < 0 || param[1] > 100) {
1538 pr_err("%s: Error, volume shoud be 0 to 100"
1539 " percentage param = %lu\n",
1540 __func__, param[1]);
1541 rc = -EINVAL;
1542 goto afe_error;
1543 }
1544
1545 param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
1546
1547 if (this_afe.apr == NULL) {
1548 pr_err("%s: Error, AFE not opened\n", __func__);
1549 rc = -EINVAL;
1550 } else {
1551 rc = afe_loopback_gain(param[0], param[1]);
1552 }
1553 } else {
1554 pr_err("%s: Error, invalid parameters\n", __func__);
1555 rc = -EINVAL;
1556 }
1557 }
1558
1559afe_error:
1560 if (rc == 0)
1561 rc = cnt;
1562 else
1563 pr_err("%s: rc = %d\n", __func__, rc);
1564
1565 return rc;
1566}
1567
1568static const struct file_operations afe_debug_fops = {
1569 .open = afe_debug_open,
1570 .write = afe_debug_write
1571};
1572#endif
1573int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
1574{
1575 struct afe_port_sidetone_command cmd_sidetone;
1576 int ret = 0;
1577
1578 pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
1579 tx_port_id, rx_port_id, enable, gain);
1580 cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1581 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1582 cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
1583 cmd_sidetone.hdr.src_port = 0;
1584 cmd_sidetone.hdr.dest_port = 0;
1585 cmd_sidetone.hdr.token = 0;
1586 cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SIDETONE_CTL;
1587 cmd_sidetone.tx_port_id = tx_port_id;
1588 cmd_sidetone.rx_port_id = rx_port_id;
1589 cmd_sidetone.gain = gain;
1590 cmd_sidetone.enable = enable;
1591
1592 atomic_set(&this_afe.state, 1);
1593 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
1594 if (ret < 0) {
1595 pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
1596 __func__, tx_port_id, rx_port_id);
1597 ret = -EINVAL;
1598 goto fail_cmd;
1599 }
1600
1601 ret = wait_event_timeout(this_afe.wait,
1602 (atomic_read(&this_afe.state) == 0),
1603 msecs_to_jiffies(TIMEOUT_MS));
1604 if (ret < 0) {
1605 pr_err("%s: wait_event timeout\n", __func__);
1606 ret = -EINVAL;
1607 goto fail_cmd;
1608 }
1609 return 0;
1610fail_cmd:
1611 return ret;
1612}
1613
1614int afe_port_stop_nowait(int port_id)
1615{
1616 struct afe_port_stop_command stop;
1617 int ret = 0;
1618
1619 if (this_afe.apr == NULL) {
1620 pr_err("AFE is already closed\n");
1621 ret = -EINVAL;
1622 goto fail_cmd;
1623 }
Jeff Ohlstein293b91f2011-12-16 13:22:46 -08001624 pr_debug("%s: port_id=%d\n", __func__, port_id);
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301625 port_id = afe_convert_virtual_to_portid(port_id);
1626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1628 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1629 stop.hdr.pkt_size = sizeof(stop);
1630 stop.hdr.src_port = 0;
1631 stop.hdr.dest_port = 0;
1632 stop.hdr.token = 0;
1633 stop.hdr.opcode = AFE_PORT_CMD_STOP;
1634 stop.port_id = port_id;
1635 stop.reserved = 0;
1636
1637 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1638
1639 if (ret == -ENETRESET) {
1640 pr_info("%s: Need to reset, calling APR deregister", __func__);
1641 return apr_deregister(this_afe.apr);
1642 } else if (IS_ERR_VALUE(ret)) {
1643 pr_err("%s: AFE close failed\n", __func__);
1644 ret = -EINVAL;
1645 }
1646
1647fail_cmd:
1648 return ret;
1649
1650}
1651
1652int afe_close(int port_id)
1653{
1654 struct afe_port_stop_command stop;
1655 int ret = 0;
1656
1657 if (this_afe.apr == NULL) {
1658 pr_err("AFE is already closed\n");
1659 ret = -EINVAL;
1660 goto fail_cmd;
1661 }
Jeff Ohlstein293b91f2011-12-16 13:22:46 -08001662 pr_debug("%s: port_id=%d\n", __func__, port_id);
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301663 port_id = afe_convert_virtual_to_portid(port_id);
1664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1666 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1667 stop.hdr.pkt_size = sizeof(stop);
1668 stop.hdr.src_port = 0;
1669 stop.hdr.dest_port = 0;
1670 stop.hdr.token = 0;
1671 stop.hdr.opcode = AFE_PORT_CMD_STOP;
1672 stop.port_id = port_id;
1673 stop.reserved = 0;
1674
1675 atomic_set(&this_afe.state, 1);
1676 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1677
1678 if (ret == -ENETRESET) {
1679 pr_info("%s: Need to reset, calling APR deregister", __func__);
1680 return apr_deregister(this_afe.apr);
1681 }
1682
1683 if (ret < 0) {
1684 pr_err("%s: AFE close failed\n", __func__);
1685 ret = -EINVAL;
1686 goto fail_cmd;
1687 }
1688
1689 ret = wait_event_timeout(this_afe.wait,
1690 (atomic_read(&this_afe.state) == 0),
1691 msecs_to_jiffies(TIMEOUT_MS));
1692 if (!ret) {
1693 pr_err("%s: wait_event timeout\n", __func__);
1694 ret = -EINVAL;
1695 goto fail_cmd;
1696 }
1697fail_cmd:
1698 return ret;
1699}
1700
1701static int __init afe_init(void)
1702{
1703 init_waitqueue_head(&this_afe.wait);
1704 atomic_set(&this_afe.state, 0);
1705 atomic_set(&this_afe.status, 0);
1706 this_afe.apr = NULL;
1707#ifdef CONFIG_DEBUG_FS
1708 debugfs_afelb = debugfs_create_file("afe_loopback",
1709 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
1710 &afe_debug_fops);
1711
1712 debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
1713 S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
1714 &afe_debug_fops);
1715
1716
1717#endif
1718 return 0;
1719}
1720
1721static void __exit afe_exit(void)
1722{
Ben Rombergerb7603232011-11-23 17:16:27 -08001723 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724#ifdef CONFIG_DEBUG_FS
1725 if (debugfs_afelb)
1726 debugfs_remove(debugfs_afelb);
1727 if (debugfs_afelb_gain)
1728 debugfs_remove(debugfs_afelb_gain);
1729#endif
Ben Rombergerb7603232011-11-23 17:16:27 -08001730 for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
Ben Romberger9e792562012-02-24 12:29:01 -08001731 if (afe_cal_addr[i].cal_paddr != 0)
1732 afe_cmd_memory_unmap_nowait(
1733 afe_cal_addr[i].cal_paddr);
Ben Rombergerb7603232011-11-23 17:16:27 -08001734 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735}
1736
1737device_initcall(afe_init);
1738__exitcall(afe_exit);