blob: aaebad5f6a28759ca25a36676babd0fdeb9cf57b [file] [log] [blame]
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +05301/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/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];
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +053041static int pcm_afe_instance[2];
42static int proxy_afe_instance[2];
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +053043bool afe_close_done[2] = {true, true};
Ben Rombergerb7603232011-11-23 17:16:27 -080044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045#define TIMEOUT_MS 1000
46#define Q6AFE_MAX_VOLUME 0x3FFF
47
48#define SIZEOF_CFG_CMD(y) \
49 (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
50
51static int32_t afe_callback(struct apr_client_data *data, void *priv)
52{
53 if (data->opcode == RESET_EVENTS) {
54 pr_debug("q6afe: reset event = %d %d apr[%p]\n",
55 data->reset_event, data->reset_proc, this_afe.apr);
56 if (this_afe.apr) {
57 apr_reset(this_afe.apr);
58 atomic_set(&this_afe.state, 0);
59 this_afe.apr = NULL;
60 }
61 /* send info to user */
62 pr_debug("task_name = %s pid = %d\n",
63 this_afe.task->comm, this_afe.task->pid);
64 send_sig(SIGUSR1, this_afe.task, 0);
Laxminath Kasam9bb28c62012-01-18 21:55:37 +053065 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066 }
67 if (data->payload_size) {
68 uint32_t *payload;
Laxminath Kasam32657ec2011-08-01 19:26:57 +053069 uint16_t port_id = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070 payload = data->payload;
Laxminath Kasam32657ec2011-08-01 19:26:57 +053071 pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
72 __func__, data->opcode,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073 payload[0], payload[1]);
74 /* payload[1] contains the error status for response */
75 if (payload[1] != 0) {
76 atomic_set(&this_afe.status, -1);
77 pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
78 __func__, payload[0], payload[1]);
79 }
80 if (data->opcode == APR_BASIC_RSP_RESULT) {
81 switch (payload[0]) {
82 case AFE_PORT_AUDIO_IF_CONFIG:
Kuirong Wanga36f2882012-04-02 19:45:26 -070083 case AFE_PORT_CMD_I2S_CONFIG:
Kiran Kandi5e809b02012-01-31 00:24:33 -080084 case AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080085 case AFE_PORT_AUDIO_SLIM_SCH_CONFIG:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 case AFE_PORT_CMD_STOP:
87 case AFE_PORT_CMD_START:
88 case AFE_PORT_CMD_LOOPBACK:
89 case AFE_PORT_CMD_SIDETONE_CTL:
90 case AFE_PORT_CMD_SET_PARAM:
91 case AFE_PSEUDOPORT_CMD_START:
92 case AFE_PSEUDOPORT_CMD_STOP:
Laxminath Kasam885f5102011-07-14 10:20:21 +053093 case AFE_PORT_CMD_APPLY_GAIN:
Laxminath Kasam32657ec2011-08-01 19:26:57 +053094 case AFE_SERVICE_CMD_MEMORY_MAP:
95 case AFE_SERVICE_CMD_MEMORY_UNMAP:
96 case AFE_SERVICE_CMD_UNREG_RTPORT:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 atomic_set(&this_afe.state, 0);
98 wake_up(&this_afe.wait);
99 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530100 case AFE_SERVICE_CMD_REG_RTPORT:
101 break;
102 case AFE_SERVICE_CMD_RTPORT_WR:
103 port_id = RT_PROXY_PORT_001_TX;
104 break;
105 case AFE_SERVICE_CMD_RTPORT_RD:
106 port_id = RT_PROXY_PORT_001_RX;
107 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 default:
109 pr_err("Unknown cmd 0x%x\n",
110 payload[0]);
111 break;
112 }
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530113 } else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
114 port_id = (uint16_t)(0x0000FFFF & payload[0]);
115 }
116 pr_debug("%s:port_id = %x\n", __func__, port_id);
117 switch (port_id) {
118 case RT_PROXY_PORT_001_TX: {
119 if (this_afe.tx_cb) {
120 this_afe.tx_cb(data->opcode, data->token,
121 data->payload,
122 this_afe.tx_private_data);
123 }
124 break;
125 }
126 case RT_PROXY_PORT_001_RX: {
127 if (this_afe.rx_cb) {
128 this_afe.rx_cb(data->opcode, data->token,
129 data->payload,
130 this_afe.rx_private_data);
131 }
132 break;
133 }
134 default:
135 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 }
137 }
138 return 0;
139}
140
Neema Shettyfeea7742011-09-11 12:30:36 -0700141int afe_get_port_type(u16 port_id)
142{
143 int ret;
144
145 switch (port_id) {
146 case PRIMARY_I2S_RX:
147 case PCM_RX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700148 case SECONDARY_PCM_RX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700149 case SECONDARY_I2S_RX:
150 case MI2S_RX:
151 case HDMI_RX:
152 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800153 case SLIMBUS_1_RX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700154 case SLIMBUS_2_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700155 case SLIMBUS_3_RX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700156 case INT_BT_SCO_RX:
157 case INT_BT_A2DP_RX:
158 case INT_FM_RX:
159 case VOICE_PLAYBACK_TX:
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530160 case RT_PROXY_PORT_001_RX:
Helen Zeng8f925502012-03-05 16:50:17 -0800161 case SLIMBUS_4_RX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700162 ret = MSM_AFE_PORT_TYPE_RX;
163 break;
164
165 case PRIMARY_I2S_TX:
166 case PCM_TX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700167 case SECONDARY_PCM_TX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700168 case SECONDARY_I2S_TX:
169 case MI2S_TX:
170 case DIGI_MIC_TX:
171 case VOICE_RECORD_TX:
172 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800173 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700174 case SLIMBUS_2_TX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700175 case SLIMBUS_3_TX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700176 case INT_FM_TX:
177 case VOICE_RECORD_RX:
178 case INT_BT_SCO_TX:
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530179 case RT_PROXY_PORT_001_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800180 case SLIMBUS_4_TX:
Neema Shettyfeea7742011-09-11 12:30:36 -0700181 ret = MSM_AFE_PORT_TYPE_TX;
182 break;
183
184 default:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800185 pr_err("%s: invalid port id %d\n", __func__, port_id);
Neema Shettyfeea7742011-09-11 12:30:36 -0700186 ret = -EINVAL;
187 }
188
189 return ret;
190}
191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192int afe_validate_port(u16 port_id)
193{
194 int ret;
195
196 switch (port_id) {
197 case PRIMARY_I2S_RX:
198 case PRIMARY_I2S_TX:
199 case PCM_RX:
200 case PCM_TX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700201 case SECONDARY_PCM_RX:
202 case SECONDARY_PCM_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 case SECONDARY_I2S_RX:
204 case SECONDARY_I2S_TX:
205 case MI2S_RX:
206 case MI2S_TX:
207 case HDMI_RX:
208 case RSVD_2:
209 case RSVD_3:
210 case DIGI_MIC_TX:
211 case VOICE_RECORD_RX:
212 case VOICE_RECORD_TX:
213 case VOICE_PLAYBACK_TX:
214 case SLIMBUS_0_RX:
215 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800216 case SLIMBUS_1_RX:
217 case SLIMBUS_1_TX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700218 case SLIMBUS_2_RX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700219 case SLIMBUS_2_TX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700220 case SLIMBUS_3_RX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700221 case SLIMBUS_3_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 case INT_BT_SCO_RX:
223 case INT_BT_SCO_TX:
224 case INT_BT_A2DP_RX:
225 case INT_FM_RX:
226 case INT_FM_TX:
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530227 case RT_PROXY_PORT_001_RX:
228 case RT_PROXY_PORT_001_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800229 case SLIMBUS_4_RX:
230 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 {
232 ret = 0;
233 break;
234 }
235
236 default:
237 ret = -EINVAL;
238 }
239
240 return ret;
241}
242
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530243int afe_convert_virtual_to_portid(u16 port_id)
244{
245 int ret;
246
247 /* if port_id is virtual, convert to physical..
248 * if port_id is already physical, return physical
249 */
250 if (afe_validate_port(port_id) < 0) {
251 if (port_id == RT_PROXY_DAI_001_RX ||
252 port_id == RT_PROXY_DAI_001_TX ||
253 port_id == RT_PROXY_DAI_002_RX ||
254 port_id == RT_PROXY_DAI_002_TX)
255 ret = VIRTUAL_ID_TO_PORTID(port_id);
256 else
257 ret = -EINVAL;
258 } else
259 ret = port_id;
260
261 return ret;
262}
263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264int afe_get_port_index(u16 port_id)
265{
266 switch (port_id) {
267 case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
268 case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
269 case PCM_RX: return IDX_PCM_RX;
270 case PCM_TX: return IDX_PCM_TX;
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700271 case SECONDARY_PCM_RX: return IDX_SECONDARY_PCM_RX;
272 case SECONDARY_PCM_TX: return IDX_SECONDARY_PCM_TX;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
274 case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
275 case MI2S_RX: return IDX_MI2S_RX;
276 case MI2S_TX: return IDX_MI2S_TX;
277 case HDMI_RX: return IDX_HDMI_RX;
278 case RSVD_2: return IDX_RSVD_2;
279 case RSVD_3: return IDX_RSVD_3;
280 case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
281 case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
282 case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
283 case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
284 case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
285 case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
Neema Shetty3c9d2862012-03-11 01:25:32 -0800286 case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
287 case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
Kiran Kandifd30c892012-05-21 23:03:26 -0700288 case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700289 case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
Neema Shetty74131ac2012-05-09 13:35:26 -0700290 case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
Helen Zeng38c3c962012-05-17 14:56:20 -0700291 case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
293 case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
294 case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
295 case INT_FM_RX: return IDX_INT_FM_RX;
296 case INT_FM_TX: return IDX_INT_FM_TX;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530297 case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
298 case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
Helen Zeng8f925502012-03-05 16:50:17 -0800299 case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
300 case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301
302 default: return -EINVAL;
303 }
304}
305
306int afe_sizeof_cfg_cmd(u16 port_id)
307{
308 int ret_size;
309 switch (port_id) {
310 case PRIMARY_I2S_RX:
311 case PRIMARY_I2S_TX:
312 case SECONDARY_I2S_RX:
313 case SECONDARY_I2S_TX:
314 case MI2S_RX:
315 case MI2S_TX:
316 ret_size = SIZEOF_CFG_CMD(afe_port_mi2s_cfg);
317 break;
318 case HDMI_RX:
Kiran Kandi5e809b02012-01-31 00:24:33 -0800319 ret_size = SIZEOF_CFG_CMD(afe_port_hdmi_multi_ch_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320 break;
321 case SLIMBUS_0_RX:
322 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800323 case SLIMBUS_1_RX:
324 case SLIMBUS_1_TX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700325 case SLIMBUS_2_RX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700326 case SLIMBUS_2_TX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700327 case SLIMBUS_3_RX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700328 case SLIMBUS_3_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800329 case SLIMBUS_4_RX:
330 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800331 ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530333 case RT_PROXY_PORT_001_RX:
334 case RT_PROXY_PORT_001_TX:
335 ret_size = SIZEOF_CFG_CMD(afe_port_rtproxy_cfg);
336 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 case PCM_RX:
338 case PCM_TX:
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700339 case SECONDARY_PCM_RX:
340 case SECONDARY_PCM_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 default:
342 ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
343 break;
344 }
345 return ret_size;
346}
347
Jay Wang6a305432011-08-05 16:01:54 -0700348int afe_q6_interface_prepare(void)
349{
350 int ret = 0;
351
352 pr_debug("%s:", __func__);
353
354 if (this_afe.apr == NULL) {
355 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
356 0xFFFFFFFF, &this_afe);
357 pr_debug("%s: Register AFE\n", __func__);
358 if (this_afe.apr == NULL) {
359 pr_err("%s: Unable to register AFE\n", __func__);
360 ret = -ENODEV;
361 }
362 }
363 return ret;
364}
365
Ben Rombergerb7603232011-11-23 17:16:27 -0800366static void afe_send_cal_block(int32_t path, u16 port_id)
367{
368 int result = 0;
369 struct acdb_cal_block cal_block;
370 struct afe_port_cmd_set_param_no_payload afe_cal;
371 pr_debug("%s: path %d\n", __func__, path);
372
373 get_afe_cal(path, &cal_block);
374 if (cal_block.cal_size <= 0) {
375 pr_debug("%s: No AFE cal to send!\n", __func__);
376 goto done;
377 }
378
Ben Romberger9e792562012-02-24 12:29:01 -0800379 if ((afe_cal_addr[path].cal_paddr != cal_block.cal_paddr) ||
380 (cal_block.cal_size > afe_cal_addr[path].cal_size)) {
381 if (afe_cal_addr[path].cal_paddr != 0)
Patrick Laibf978952012-06-29 09:20:42 -0700382 afe_cmd_memory_unmap(
Ben Romberger9e792562012-02-24 12:29:01 -0800383 afe_cal_addr[path].cal_paddr);
384
Patrick Laibf978952012-06-29 09:20:42 -0700385 afe_cmd_memory_map(cal_block.cal_paddr, cal_block.cal_size);
Ben Romberger9e792562012-02-24 12:29:01 -0800386 afe_cal_addr[path].cal_paddr = cal_block.cal_paddr;
387 afe_cal_addr[path].cal_size = cal_block.cal_size;
Ben Rombergerb7603232011-11-23 17:16:27 -0800388 }
389
390 afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
391 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
392 afe_cal.hdr.pkt_size = sizeof(afe_cal);
393 afe_cal.hdr.src_port = 0;
394 afe_cal.hdr.dest_port = 0;
395 afe_cal.hdr.token = 0;
396 afe_cal.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
397 afe_cal.port_id = port_id;
398 afe_cal.payload_size = cal_block.cal_size;
399 afe_cal.payload_address = cal_block.cal_paddr;
400
401 pr_debug("%s: AFE cal sent for device port = %d, path = %d, "
402 "cal size = %d, cal addr = 0x%x\n", __func__,
403 port_id, path, cal_block.cal_size, cal_block.cal_paddr);
404
Patrick Laibf978952012-06-29 09:20:42 -0700405 atomic_set(&this_afe.state, 1);
Ben Rombergerb7603232011-11-23 17:16:27 -0800406 result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
407 if (result < 0) {
408 pr_err("%s: AFE cal for port %d failed\n",
409 __func__, port_id);
410 }
411
Patrick Laibf978952012-06-29 09:20:42 -0700412 result = wait_event_timeout(this_afe.wait,
413 (atomic_read(&this_afe.state) == 0),
414 msecs_to_jiffies(TIMEOUT_MS));
415 if (!result) {
416 pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
417 goto done;
418 }
419
Ben Rombergerb7603232011-11-23 17:16:27 -0800420 pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
421done:
422 return;
423}
424
425void afe_send_cal(u16 port_id)
426{
427 pr_debug("%s\n", __func__);
428
429 if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
430 afe_send_cal_block(TX_CAL, port_id);
431 else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
432 afe_send_cal_block(RX_CAL, port_id);
433}
434
Patrick Laibf978952012-06-29 09:20:42 -0700435/* This function sends multi-channel HDMI configuration command and AFE
436 * calibration which is only supported by QDSP6 on 8960 and onward.
437 */
438int afe_port_start(u16 port_id, union afe_port_config *afe_config,
439 u32 rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440{
441 struct afe_port_start_command start;
442 struct afe_audioif_config_command config;
443 int ret;
444
445 if (!afe_config) {
446 pr_err("%s: Error, no configuration data\n", __func__);
447 ret = -EINVAL;
448 return ret;
449 }
Jeff Ohlstein293b91f2011-12-16 13:22:46 -0800450 pr_debug("%s: %d %d\n", __func__, port_id, rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530452 if ((port_id == RT_PROXY_DAI_001_RX) ||
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +0530453 (port_id == RT_PROXY_DAI_002_TX)) {
454 pr_debug("%s: before incrementing pcm_afe_instance %d"\
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +0530455 " port_id %d\n", __func__,
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +0530456 pcm_afe_instance[port_id & 0x1], port_id);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530457 port_id = VIRTUAL_ID_TO_PORTID(port_id);
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +0530458 pcm_afe_instance[port_id & 0x1]++;
459 return 0;
460 }
461 if ((port_id == RT_PROXY_DAI_002_RX) ||
462 (port_id == RT_PROXY_DAI_001_TX)) {
463 pr_debug("%s: before incrementing proxy_afe_instance %d"\
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +0530464 " port_id %d\n", __func__,
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +0530465 proxy_afe_instance[port_id & 0x1], port_id);
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +0530466 if (!afe_close_done[port_id & 0x1]) {
467 /*close pcm dai corresponding to the proxy dai*/
468 afe_close(port_id - 0x10);
469 pcm_afe_instance[port_id & 0x1]++;
470 pr_debug("%s: reconfigure afe port again\n", __func__);
471 }
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +0530472 proxy_afe_instance[port_id & 0x1]++;
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +0530473 afe_close_done[port_id & 0x1] = false;
474 port_id = VIRTUAL_ID_TO_PORTID(port_id);
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +0530475 }
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530476
Patrick Laibf978952012-06-29 09:20:42 -0700477 ret = afe_q6_interface_prepare();
478 if (IS_ERR_VALUE(ret))
Jay Wang6a305432011-08-05 16:01:54 -0700479 return ret;
Kiran Kandi5e809b02012-01-31 00:24:33 -0800480
481 if (port_id == HDMI_RX) {
482 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
Kiran Kandi5e809b02012-01-31 00:24:33 -0800484 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
485 config.hdr.src_port = 0;
486 config.hdr.dest_port = 0;
487 config.hdr.token = 0;
488 config.hdr.opcode = AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG;
489 } else {
490
491 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
492 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
493 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
494 config.hdr.src_port = 0;
495 config.hdr.dest_port = 0;
496 config.hdr.token = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800497 switch (port_id) {
498 case SLIMBUS_0_RX:
499 case SLIMBUS_0_TX:
500 case SLIMBUS_1_RX:
501 case SLIMBUS_1_TX:
502 case SLIMBUS_2_RX:
503 case SLIMBUS_2_TX:
504 case SLIMBUS_3_RX:
505 case SLIMBUS_3_TX:
506 case SLIMBUS_4_RX:
507 case SLIMBUS_4_TX:
508 config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
509 break;
Kuirong Wanga36f2882012-04-02 19:45:26 -0700510 case MI2S_TX:
511 case MI2S_RX:
512 case SECONDARY_I2S_RX:
513 case SECONDARY_I2S_TX:
514 case PRIMARY_I2S_RX:
515 case PRIMARY_I2S_TX:
516 /* AFE_PORT_CMD_I2S_CONFIG command is not supported
517 * in the LPASS EL 1.0. So we have to distiguish
518 * which AFE command, AFE_PORT_CMD_I2S_CONFIG or
519 * AFE_PORT_AUDIO_IF_CONFIG to use. If the format
520 * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used
521 * to make the backward compatible.
522 */
523 pr_debug("%s: afe_config->mi2s.format = %d\n", __func__,
524 afe_config->mi2s.format);
525 if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM)
526 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
527 else
528 config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
529 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800530 default:
531 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
532 break;
533 }
Kiran Kandi5e809b02012-01-31 00:24:33 -0800534 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535
536 if (afe_validate_port(port_id) < 0) {
537
538 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
539 port_id);
540 ret = -EINVAL;
541 goto fail_cmd;
542 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543 config.port_id = port_id;
544 config.port = *afe_config;
545
Patrick Laibf978952012-06-29 09:20:42 -0700546 atomic_set(&this_afe.state, 1);
547 atomic_set(&this_afe.status, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
549 if (ret < 0) {
550 pr_err("%s: AFE enable for port %d failed\n", __func__,
551 port_id);
552 ret = -EINVAL;
553 goto fail_cmd;
554 }
Ben Rombergerb7603232011-11-23 17:16:27 -0800555
Patrick Laibf978952012-06-29 09:20:42 -0700556 ret = wait_event_timeout(this_afe.wait,
557 (atomic_read(&this_afe.state) == 0),
558 msecs_to_jiffies(TIMEOUT_MS));
559
560 if (!ret) {
561 pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
562 ret = -EINVAL;
563 goto fail_cmd;
564 }
565 if (atomic_read(&this_afe.status) != 0) {
566 pr_err("%s: config cmd failed\n", __func__);
567 ret = -EINVAL;
568 goto fail_cmd;
569 }
570
Ben Rombergerb7603232011-11-23 17:16:27 -0800571 /* send AFE cal */
572 afe_send_cal(port_id);
573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
575 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
576 start.hdr.pkt_size = sizeof(start);
577 start.hdr.src_port = 0;
578 start.hdr.dest_port = 0;
579 start.hdr.token = 0;
580 start.hdr.opcode = AFE_PORT_CMD_START;
581 start.port_id = port_id;
582 start.gain = 0x2000;
583 start.sample_rate = rate;
584
Patrick Laibf978952012-06-29 09:20:42 -0700585 atomic_set(&this_afe.state, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
587
588 if (IS_ERR_VALUE(ret)) {
589 pr_err("%s: AFE enable for port %d failed\n", __func__,
590 port_id);
591 ret = -EINVAL;
592 goto fail_cmd;
593 }
594
Patrick Laibf978952012-06-29 09:20:42 -0700595 ret = wait_event_timeout(this_afe.wait,
596 (atomic_read(&this_afe.state) == 0),
597 msecs_to_jiffies(TIMEOUT_MS));
598 if (!ret) {
599 pr_err("%s: wait_event timeout PORT START\n", __func__);
600 ret = -EINVAL;
601 goto fail_cmd;
602 }
603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 if (this_afe.task != current)
605 this_afe.task = current;
606
607 pr_debug("task_name = %s pid = %d\n",
608 this_afe.task->comm, this_afe.task->pid);
609 return 0;
610
611fail_cmd:
612 return ret;
613}
614
Patrick Laibf978952012-06-29 09:20:42 -0700615/* This function should be used by 8660 exclusively */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616int afe_open(u16 port_id, union afe_port_config *afe_config, int rate)
617{
618 struct afe_port_start_command start;
619 struct afe_audioif_config_command config;
620 int ret = 0;
621
622 if (!afe_config) {
623 pr_err("%s: Error, no configuration data\n", __func__);
624 ret = -EINVAL;
625 return ret;
626 }
627
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800628 pr_debug("%s: %d %d\n", __func__, port_id, rate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530630 if ((port_id == RT_PROXY_DAI_001_RX) ||
631 (port_id == RT_PROXY_DAI_002_TX))
Asish Bhattacharyad482c992012-07-31 20:58:18 +0530632 return 0;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530633 if ((port_id == RT_PROXY_DAI_002_RX) ||
634 (port_id == RT_PROXY_DAI_001_TX))
635 port_id = VIRTUAL_ID_TO_PORTID(port_id);
636
Jay Wang6a305432011-08-05 16:01:54 -0700637 ret = afe_q6_interface_prepare();
638 if (ret != 0)
639 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640
641 config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
642 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
643 config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
644 config.hdr.src_port = 0;
645 config.hdr.dest_port = 0;
646 config.hdr.token = 0;
Kuirong Wanga36f2882012-04-02 19:45:26 -0700647 switch (port_id) {
648 case SLIMBUS_0_RX:
649 case SLIMBUS_0_TX:
650 case SLIMBUS_1_RX:
651 case SLIMBUS_1_TX:
652 case SLIMBUS_2_RX:
653 case SLIMBUS_2_TX:
654 case SLIMBUS_3_RX:
655 case SLIMBUS_3_TX:
656 case SLIMBUS_4_RX:
657 case SLIMBUS_4_TX:
658 config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
659 break;
660 case MI2S_TX:
661 case MI2S_RX:
662 case SECONDARY_I2S_RX:
663 case SECONDARY_I2S_TX:
664 case PRIMARY_I2S_RX:
665 case PRIMARY_I2S_TX:
666 /* AFE_PORT_CMD_I2S_CONFIG command is not supported
667 * in the LPASS EL 1.0. So we have to distiguish
668 * which AFE command, AFE_PORT_CMD_I2S_CONFIG or
669 * AFE_PORT_AUDIO_IF_CONFIG to use. If the format
670 * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used
671 * to make the backward compatible.
672 */
673 pr_debug("%s: afe_config->mi2s.format = %d\n", __func__,
674 afe_config->mi2s.format);
675 if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM)
676 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
677 else
678 config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
679 break;
680 default:
681 config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
682 break;
683 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684
685 if (afe_validate_port(port_id) < 0) {
686
687 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
688 port_id);
689 ret = -EINVAL;
690 goto fail_cmd;
691 }
692
693 config.port_id = port_id;
694 config.port = *afe_config;
695
696 atomic_set(&this_afe.state, 1);
697 atomic_set(&this_afe.status, 0);
698 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
699 if (ret < 0) {
700 pr_err("%s: AFE enable for port %d failed\n", __func__,
701 port_id);
702 ret = -EINVAL;
703 goto fail_cmd;
704 }
705
706 ret = wait_event_timeout(this_afe.wait,
707 (atomic_read(&this_afe.state) == 0),
708 msecs_to_jiffies(TIMEOUT_MS));
709 if (!ret) {
710 pr_err("%s: wait_event timeout\n", __func__);
711 ret = -EINVAL;
712 goto fail_cmd;
713 }
714 if (atomic_read(&this_afe.status) != 0) {
715 pr_err("%s: config cmd failed\n", __func__);
716 ret = -EINVAL;
717 goto fail_cmd;
718 }
719 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
720 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
721 start.hdr.pkt_size = sizeof(start);
722 start.hdr.src_port = 0;
723 start.hdr.dest_port = 0;
724 start.hdr.token = 0;
725 start.hdr.opcode = AFE_PORT_CMD_START;
726 start.port_id = port_id;
727 start.gain = 0x2000;
728 start.sample_rate = rate;
729
730 atomic_set(&this_afe.state, 1);
731 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
732 if (ret < 0) {
733 pr_err("%s: AFE enable for port %d failed\n", __func__,
734 port_id);
735 ret = -EINVAL;
736 goto fail_cmd;
737 }
738 ret = wait_event_timeout(this_afe.wait,
739 (atomic_read(&this_afe.state) == 0),
740 msecs_to_jiffies(TIMEOUT_MS));
741 if (!ret) {
742 pr_err("%s: wait_event timeout\n", __func__);
743 ret = -EINVAL;
744 goto fail_cmd;
745 }
746
747 if (this_afe.task != current)
748 this_afe.task = current;
749
750 pr_debug("task_name = %s pid = %d\n",
751 this_afe.task->comm, this_afe.task->pid);
752 return 0;
753fail_cmd:
754 return ret;
755}
756
Neema Shetty74131ac2012-05-09 13:35:26 -0700757int afe_loopback(u16 enable, u16 dst_port, u16 src_port)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758{
759 struct afe_loopback_command lb_cmd;
760 int ret = 0;
Jay Wang6a305432011-08-05 16:01:54 -0700761
762 ret = afe_q6_interface_prepare();
763 if (ret != 0)
764 return ret;
765
Neema Shetty74131ac2012-05-09 13:35:26 -0700766 if ((afe_get_port_type(dst_port) == MSM_AFE_PORT_TYPE_RX) &&
767 (afe_get_port_type(src_port) == MSM_AFE_PORT_TYPE_RX))
768 return afe_loopback_cfg(enable, dst_port, src_port,
769 LB_MODE_EC_REF_VOICE_AUDIO);
770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771 lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
772 APR_HDR_LEN(20), APR_PKT_VER);
773 lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
774 sizeof(lb_cmd) - APR_HDR_SIZE);
775 lb_cmd.hdr.src_port = 0;
776 lb_cmd.hdr.dest_port = 0;
777 lb_cmd.hdr.token = 0;
778 lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
Neema Shetty74131ac2012-05-09 13:35:26 -0700779 lb_cmd.tx_port_id = src_port;
780 lb_cmd.rx_port_id = dst_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 lb_cmd.mode = 0xFFFF;
782 lb_cmd.enable = (enable ? 1 : 0);
783 atomic_set(&this_afe.state, 1);
784
785 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
786 if (ret < 0) {
787 pr_err("%s: AFE loopback failed\n", __func__);
788 ret = -EINVAL;
789 goto done;
790 }
791 ret = wait_event_timeout(this_afe.wait,
792 (atomic_read(&this_afe.state) == 0),
793 msecs_to_jiffies(TIMEOUT_MS));
794 if (!ret) {
795 pr_err("%s: wait_event timeout\n", __func__);
796 ret = -EINVAL;
797 }
798done:
799 return ret;
800}
801
Neema Shetty74131ac2012-05-09 13:35:26 -0700802int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode)
803{
804 struct afe_port_cmd_set_param lp_cfg;
805 int ret = 0;
806
807 ret = afe_q6_interface_prepare();
808 if (ret != 0)
809 return ret;
810
811 pr_debug("%s: src_port %d, dst_port %d\n",
812 __func__, src_port, dst_port);
813
814 lp_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
815 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
816 lp_cfg.hdr.pkt_size = sizeof(lp_cfg);
817 lp_cfg.hdr.src_port = 0;
818 lp_cfg.hdr.dest_port = 0;
819 lp_cfg.hdr.token = 0;
820 lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
821
822 lp_cfg.port_id = src_port;
Patrick Lai48da1492012-07-04 20:48:24 -0700823 lp_cfg.payload_size = sizeof(struct afe_param_payload_base) +
824 sizeof(struct afe_param_loopback_cfg);
Neema Shetty74131ac2012-05-09 13:35:26 -0700825 lp_cfg.payload_address = 0;
826
Patrick Lai48da1492012-07-04 20:48:24 -0700827 lp_cfg.payload.base.module_id = AFE_MODULE_LOOPBACK;
828 lp_cfg.payload.base.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
829 lp_cfg.payload.base.param_size = sizeof(struct afe_param_loopback_cfg);
830 lp_cfg.payload.base.reserved = 0;
Neema Shetty74131ac2012-05-09 13:35:26 -0700831
832 lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
833 AFE_API_VERSION_LOOPBACK_CONFIG;
834 lp_cfg.payload.param.loopback_cfg.dst_port_id = dst_port;
835 lp_cfg.payload.param.loopback_cfg.routing_mode = mode;
836 lp_cfg.payload.param.loopback_cfg.enable = enable;
837 lp_cfg.payload.param.loopback_cfg.reserved = 0;
838
839 atomic_set(&this_afe.state, 1);
840 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lp_cfg);
841 if (ret < 0) {
842 pr_err("%s: AFE loopback config failed for src_port %d, dst_port %d\n",
843 __func__, src_port, dst_port);
844 ret = -EINVAL;
845 goto fail_cmd;
846 }
847
848 ret = wait_event_timeout(this_afe.wait,
849 (atomic_read(&this_afe.state) == 0),
850 msecs_to_jiffies(TIMEOUT_MS));
851 if (ret < 0) {
852 pr_err("%s: wait_event timeout\n", __func__);
853 ret = -EINVAL;
854 goto fail_cmd;
855 }
856 return 0;
857fail_cmd:
858 return ret;
859}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860
861int afe_loopback_gain(u16 port_id, u16 volume)
862{
863 struct afe_port_cmd_set_param set_param;
864 int ret = 0;
865
866 if (this_afe.apr == NULL) {
Jayasena Sangaraboina82435032011-07-26 15:23:00 -0700867 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
868 0xFFFFFFFF, &this_afe);
869 pr_debug("%s: Register AFE\n", __func__);
870 if (this_afe.apr == NULL) {
871 pr_err("%s: Unable to register AFE\n", __func__);
872 ret = -ENODEV;
873 return ret;
874 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875 }
876
877 if (afe_validate_port(port_id) < 0) {
878
879 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
880 port_id);
881 ret = -EINVAL;
882 goto fail_cmd;
883 }
884
885 /* RX ports numbers are even .TX ports numbers are odd. */
886 if (port_id % 2 == 0) {
887 pr_err("%s: Failed : afe loopback gain only for TX ports."
888 " port_id %d\n", __func__, port_id);
889 ret = -EINVAL;
890 goto fail_cmd;
891 }
892
893 pr_debug("%s: %d %hX\n", __func__, port_id, volume);
894
895 set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
896 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
897 set_param.hdr.pkt_size = sizeof(set_param);
898 set_param.hdr.src_port = 0;
899 set_param.hdr.dest_port = 0;
900 set_param.hdr.token = 0;
901 set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
902
903 set_param.port_id = port_id;
Patrick Lai48da1492012-07-04 20:48:24 -0700904 set_param.payload_size = sizeof(struct afe_param_payload_base) +
905 sizeof(struct afe_param_loopback_gain);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906 set_param.payload_address = 0;
907
Patrick Lai48da1492012-07-04 20:48:24 -0700908 set_param.payload.base.module_id = AFE_MODULE_ID_PORT_INFO;
909 set_param.payload.base.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
910 set_param.payload.base.param_size =
911 sizeof(struct afe_param_loopback_gain);
912 set_param.payload.base.reserved = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913
914 set_param.payload.param.loopback_gain.gain = volume;
915 set_param.payload.param.loopback_gain.reserved = 0;
916
917 atomic_set(&this_afe.state, 1);
918 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
919 if (ret < 0) {
920 pr_err("%s: AFE param 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}
938
Laxminath Kasam885f5102011-07-14 10:20:21 +0530939int afe_apply_gain(u16 port_id, u16 gain)
940{
941 struct afe_port_gain_command set_gain;
942 int ret = 0;
943
944 if (this_afe.apr == NULL) {
945 pr_err("%s: AFE is not opened\n", __func__);
946 ret = -EPERM;
947 goto fail_cmd;
948 }
949
950 if (afe_validate_port(port_id) < 0) {
951 pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
952 port_id);
953 ret = -EINVAL;
954 goto fail_cmd;
955 }
956
957 /* RX ports numbers are even .TX ports numbers are odd. */
958 if (port_id % 2 == 0) {
959 pr_err("%s: Failed : afe apply gain only for TX ports."
960 " port_id %d\n", __func__, port_id);
961 ret = -EINVAL;
962 goto fail_cmd;
963 }
964
965 pr_debug("%s: %d %hX\n", __func__, port_id, gain);
966
967 set_gain.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
968 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
969 set_gain.hdr.pkt_size = sizeof(set_gain);
970 set_gain.hdr.src_port = 0;
971 set_gain.hdr.dest_port = 0;
972 set_gain.hdr.token = 0;
973 set_gain.hdr.opcode = AFE_PORT_CMD_APPLY_GAIN;
974
975 set_gain.port_id = port_id;
976 set_gain.gain = gain;
977
978 atomic_set(&this_afe.state, 1);
979 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_gain);
980 if (ret < 0) {
981 pr_err("%s: AFE Gain set failed for port %d\n",
982 __func__, port_id);
983 ret = -EINVAL;
984 goto fail_cmd;
985 }
986
987 ret = wait_event_timeout(this_afe.wait,
988 (atomic_read(&this_afe.state) == 0),
989 msecs_to_jiffies(TIMEOUT_MS));
990 if (ret < 0) {
991 pr_err("%s: wait_event timeout\n", __func__);
992 ret = -EINVAL;
993 goto fail_cmd;
994 }
995 return 0;
996fail_cmd:
997 return ret;
998}
Helen Zeng0705a5f2011-10-14 15:29:52 -0700999
1000int afe_pseudo_port_start_nowait(u16 port_id)
1001{
1002 int ret = 0;
1003 struct afe_pseudoport_start_command start;
1004
1005 pr_debug("%s: port_id=%d\n", __func__, port_id);
1006 if (this_afe.apr == NULL) {
1007 pr_err("%s: AFE APR is not registered\n", __func__);
1008 return -ENODEV;
1009 }
1010
1011
1012 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1013 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1014 start.hdr.pkt_size = sizeof(start);
1015 start.hdr.src_port = 0;
1016 start.hdr.dest_port = 0;
1017 start.hdr.token = 0;
1018 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
1019 start.port_id = port_id;
1020 start.timing = 1;
1021
1022 atomic_set(&this_afe.state, 1);
1023 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
1024 if (ret < 0) {
1025 pr_err("%s: AFE enable for port %d failed %d\n",
1026 __func__, port_id, ret);
1027 return -EINVAL;
1028 }
1029 return 0;
1030}
1031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032int afe_start_pseudo_port(u16 port_id)
1033{
1034 int ret = 0;
1035 struct afe_pseudoport_start_command start;
1036
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001037 pr_debug("%s: port_id=%d\n", __func__, port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038
Jay Wang6a305432011-08-05 16:01:54 -07001039 ret = afe_q6_interface_prepare();
1040 if (ret != 0)
1041 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042
1043 start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1044 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1045 start.hdr.pkt_size = sizeof(start);
1046 start.hdr.src_port = 0;
1047 start.hdr.dest_port = 0;
1048 start.hdr.token = 0;
1049 start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
1050 start.port_id = port_id;
1051 start.timing = 1;
1052
1053 atomic_set(&this_afe.state, 1);
1054 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
1055 if (ret < 0) {
1056 pr_err("%s: AFE enable for port %d failed %d\n",
1057 __func__, port_id, ret);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001058 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 }
1060
1061 ret = wait_event_timeout(this_afe.wait,
1062 (atomic_read(&this_afe.state) == 0),
1063 msecs_to_jiffies(TIMEOUT_MS));
1064 if (!ret) {
1065 pr_err("%s: wait_event timeout\n", __func__);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001066 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 }
1068
1069 return 0;
1070}
1071
Helen Zeng0705a5f2011-10-14 15:29:52 -07001072int afe_pseudo_port_stop_nowait(u16 port_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073{
1074 int ret = 0;
1075 struct afe_pseudoport_stop_command stop;
1076
Helen Zeng0705a5f2011-10-14 15:29:52 -07001077 pr_debug("%s: port_id=%d\n", __func__, port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078
1079 if (this_afe.apr == NULL) {
1080 pr_err("%s: AFE is already closed\n", __func__);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001081 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 }
1083
1084 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1085 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1086 stop.hdr.pkt_size = sizeof(stop);
1087 stop.hdr.src_port = 0;
1088 stop.hdr.dest_port = 0;
1089 stop.hdr.token = 0;
1090 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
1091 stop.port_id = port_id;
1092 stop.reserved = 0;
1093
1094 atomic_set(&this_afe.state, 1);
1095 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1096 if (ret < 0) {
1097 pr_err("%s: AFE close failed %d\n", __func__, ret);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001098 return -EINVAL;
1099 }
1100
1101 return 0;
1102
1103}
1104
1105int afe_stop_pseudo_port(u16 port_id)
1106{
1107 int ret = 0;
1108 struct afe_pseudoport_stop_command stop;
1109
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001110 pr_debug("%s: port_id=%d\n", __func__, port_id);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001111
1112 if (this_afe.apr == NULL) {
1113 pr_err("%s: AFE is already closed\n", __func__);
1114 return -EINVAL;
1115 }
1116
1117 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1118 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1119 stop.hdr.pkt_size = sizeof(stop);
1120 stop.hdr.src_port = 0;
1121 stop.hdr.dest_port = 0;
1122 stop.hdr.token = 0;
1123 stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
1124 stop.port_id = port_id;
1125 stop.reserved = 0;
1126
1127 atomic_set(&this_afe.state, 1);
1128 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1129 if (ret < 0) {
1130 pr_err("%s: AFE close failed %d\n", __func__, ret);
1131 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 }
1133
1134 ret = wait_event_timeout(this_afe.wait,
1135 (atomic_read(&this_afe.state) == 0),
1136 msecs_to_jiffies(TIMEOUT_MS));
1137 if (!ret) {
1138 pr_err("%s: wait_event timeout\n", __func__);
Helen Zeng0705a5f2011-10-14 15:29:52 -07001139 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 }
1141
1142 return 0;
1143}
1144
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301145int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
1146{
1147 int ret = 0;
1148 struct afe_cmd_memory_map mregion;
1149
1150 pr_debug("%s:\n", __func__);
1151
1152 if (this_afe.apr == NULL) {
1153 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1154 0xFFFFFFFF, &this_afe);
1155 pr_debug("%s: Register AFE\n", __func__);
1156 if (this_afe.apr == NULL) {
1157 pr_err("%s: Unable to register AFE\n", __func__);
1158 ret = -ENODEV;
1159 return ret;
1160 }
1161 }
1162
1163 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1164 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1165 mregion.hdr.pkt_size = sizeof(mregion);
1166 mregion.hdr.src_port = 0;
1167 mregion.hdr.dest_port = 0;
1168 mregion.hdr.token = 0;
1169 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
1170 mregion.phy_addr = dma_addr_p;
1171 mregion.mem_sz = dma_buf_sz;
1172 mregion.mem_id = 0;
1173 mregion.rsvd = 0;
1174
1175 atomic_set(&this_afe.state, 1);
1176 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1177 if (ret < 0) {
1178 pr_err("%s: AFE memory map cmd failed %d\n",
1179 __func__, ret);
1180 ret = -EINVAL;
1181 return ret;
1182 }
1183
1184 ret = wait_event_timeout(this_afe.wait,
1185 (atomic_read(&this_afe.state) == 0),
1186 msecs_to_jiffies(TIMEOUT_MS));
1187 if (!ret) {
1188 pr_err("%s: wait_event timeout\n", __func__);
1189 ret = -EINVAL;
1190 return ret;
1191 }
1192
1193 return 0;
1194}
1195
Ben Rombergerb7603232011-11-23 17:16:27 -08001196int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz)
1197{
1198 int ret = 0;
1199 struct afe_cmd_memory_map mregion;
1200
1201 pr_debug("%s:\n", __func__);
1202
1203 if (this_afe.apr == NULL) {
1204 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1205 0xFFFFFFFF, &this_afe);
1206 pr_debug("%s: Register AFE\n", __func__);
1207 if (this_afe.apr == NULL) {
1208 pr_err("%s: Unable to register AFE\n", __func__);
1209 ret = -ENODEV;
1210 return ret;
1211 }
1212 }
1213
1214 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1215 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1216 mregion.hdr.pkt_size = sizeof(mregion);
1217 mregion.hdr.src_port = 0;
1218 mregion.hdr.dest_port = 0;
1219 mregion.hdr.token = 0;
1220 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
1221 mregion.phy_addr = dma_addr_p;
1222 mregion.mem_sz = dma_buf_sz;
1223 mregion.mem_id = 0;
1224 mregion.rsvd = 0;
1225
1226 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1227 if (ret < 0) {
1228 pr_err("%s: AFE memory map cmd failed %d\n",
1229 __func__, ret);
1230 ret = -EINVAL;
1231 }
1232 return 0;
1233}
1234
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301235int afe_cmd_memory_unmap(u32 dma_addr_p)
1236{
1237 int ret = 0;
1238 struct afe_cmd_memory_unmap mregion;
1239
1240 pr_debug("%s:\n", __func__);
1241
1242 if (this_afe.apr == NULL) {
1243 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1244 0xFFFFFFFF, &this_afe);
1245 pr_debug("%s: Register AFE\n", __func__);
1246 if (this_afe.apr == NULL) {
1247 pr_err("%s: Unable to register AFE\n", __func__);
1248 ret = -ENODEV;
1249 return ret;
1250 }
1251 }
1252
1253 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1254 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1255 mregion.hdr.pkt_size = sizeof(mregion);
1256 mregion.hdr.src_port = 0;
1257 mregion.hdr.dest_port = 0;
1258 mregion.hdr.token = 0;
1259 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
1260 mregion.phy_addr = dma_addr_p;
1261
1262 atomic_set(&this_afe.state, 1);
1263 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1264 if (ret < 0) {
Ben Rombergerb7603232011-11-23 17:16:27 -08001265 pr_err("%s: AFE memory unmap cmd failed %d\n",
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301266 __func__, ret);
1267 ret = -EINVAL;
1268 return ret;
1269 }
1270
1271 ret = wait_event_timeout(this_afe.wait,
1272 (atomic_read(&this_afe.state) == 0),
1273 msecs_to_jiffies(TIMEOUT_MS));
1274 if (!ret) {
1275 pr_err("%s: wait_event timeout\n", __func__);
1276 ret = -EINVAL;
1277 return ret;
1278 }
Ben Rombergerb7603232011-11-23 17:16:27 -08001279 return 0;
1280}
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301281
Ben Rombergerb7603232011-11-23 17:16:27 -08001282int afe_cmd_memory_unmap_nowait(u32 dma_addr_p)
1283{
1284 int ret = 0;
1285 struct afe_cmd_memory_unmap mregion;
1286
1287 pr_debug("%s:\n", __func__);
1288
1289 if (this_afe.apr == NULL) {
1290 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1291 0xFFFFFFFF, &this_afe);
1292 pr_debug("%s: Register AFE\n", __func__);
1293 if (this_afe.apr == NULL) {
1294 pr_err("%s: Unable to register AFE\n", __func__);
1295 ret = -ENODEV;
1296 return ret;
1297 }
1298 }
1299
1300 mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1301 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1302 mregion.hdr.pkt_size = sizeof(mregion);
1303 mregion.hdr.src_port = 0;
1304 mregion.hdr.dest_port = 0;
1305 mregion.hdr.token = 0;
1306 mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
1307 mregion.phy_addr = dma_addr_p;
1308
1309 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
1310 if (ret < 0) {
1311 pr_err("%s: AFE memory unmap cmd failed %d\n",
1312 __func__, ret);
1313 ret = -EINVAL;
1314 }
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301315 return 0;
1316}
1317
1318int afe_register_get_events(u16 port_id,
1319 void (*cb) (uint32_t opcode,
1320 uint32_t token, uint32_t *payload, void *priv),
1321 void *private_data)
1322{
1323 int ret = 0;
1324 struct afe_cmd_reg_rtport rtproxy;
1325
1326 pr_debug("%s:\n", __func__);
1327
1328 if (this_afe.apr == NULL) {
1329 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1330 0xFFFFFFFF, &this_afe);
1331 pr_debug("%s: Register AFE\n", __func__);
1332 if (this_afe.apr == NULL) {
1333 pr_err("%s: Unable to register AFE\n", __func__);
1334 ret = -ENODEV;
1335 return ret;
1336 }
1337 }
1338 if ((port_id == RT_PROXY_DAI_002_RX) ||
1339 (port_id == RT_PROXY_DAI_001_TX))
1340 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1341 else
1342 return -EINVAL;
1343
1344 if (port_id == RT_PROXY_PORT_001_TX) {
1345 this_afe.tx_cb = cb;
1346 this_afe.tx_private_data = private_data;
1347 } else if (port_id == RT_PROXY_PORT_001_RX) {
1348 this_afe.rx_cb = cb;
1349 this_afe.rx_private_data = private_data;
1350 }
1351
1352 rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1353 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1354 rtproxy.hdr.pkt_size = sizeof(rtproxy);
1355 rtproxy.hdr.src_port = 1;
1356 rtproxy.hdr.dest_port = 1;
1357 rtproxy.hdr.token = 0;
1358 rtproxy.hdr.opcode = AFE_SERVICE_CMD_REG_RTPORT;
1359 rtproxy.port_id = port_id;
1360 rtproxy.rsvd = 0;
1361
1362 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
1363 if (ret < 0) {
1364 pr_err("%s: AFE reg. rtproxy_event failed %d\n",
1365 __func__, ret);
1366 ret = -EINVAL;
1367 return ret;
1368 }
1369 return 0;
1370}
1371
1372int afe_unregister_get_events(u16 port_id)
1373{
1374 int ret = 0;
1375 struct afe_cmd_unreg_rtport rtproxy;
1376
1377 pr_debug("%s:\n", __func__);
1378
1379 if (this_afe.apr == NULL) {
1380 this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
1381 0xFFFFFFFF, &this_afe);
1382 pr_debug("%s: Register AFE\n", __func__);
1383 if (this_afe.apr == NULL) {
1384 pr_err("%s: Unable to register AFE\n", __func__);
1385 ret = -ENODEV;
1386 return ret;
1387 }
1388 }
1389 if ((port_id == RT_PROXY_DAI_002_RX) ||
1390 (port_id == RT_PROXY_DAI_001_TX))
1391 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1392 else
1393 return -EINVAL;
1394
1395 rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1396 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1397 rtproxy.hdr.pkt_size = sizeof(rtproxy);
1398 rtproxy.hdr.src_port = 0;
1399 rtproxy.hdr.dest_port = 0;
1400 rtproxy.hdr.token = 0;
1401 rtproxy.hdr.opcode = AFE_SERVICE_CMD_UNREG_RTPORT;
1402 rtproxy.port_id = port_id;
1403 rtproxy.rsvd = 0;
1404
1405 if (port_id == RT_PROXY_PORT_001_TX) {
1406 this_afe.tx_cb = NULL;
1407 this_afe.tx_private_data = NULL;
1408 } else if (port_id == RT_PROXY_PORT_001_RX) {
1409 this_afe.rx_cb = NULL;
1410 this_afe.rx_private_data = NULL;
1411 }
1412
1413 atomic_set(&this_afe.state, 1);
1414 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
1415 if (ret < 0) {
1416 pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
1417 __func__, ret);
1418 ret = -EINVAL;
1419 return ret;
1420 }
1421
1422 ret = wait_event_timeout(this_afe.wait,
1423 (atomic_read(&this_afe.state) == 0),
1424 msecs_to_jiffies(TIMEOUT_MS));
1425 if (!ret) {
1426 pr_err("%s: wait_event timeout\n", __func__);
1427 ret = -EINVAL;
1428 return ret;
1429 }
1430 return 0;
1431}
1432
1433int afe_rt_proxy_port_write(u32 buf_addr_p, int bytes)
1434{
1435 int ret = 0;
1436 struct afe_cmd_rtport_wr afecmd_wr;
1437
1438 if (this_afe.apr == NULL) {
1439 pr_err("%s:register to AFE is not done\n", __func__);
1440 ret = -ENODEV;
1441 return ret;
1442 }
1443 pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
1444 buf_addr_p, bytes);
1445
1446 afecmd_wr.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1447 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1448 afecmd_wr.hdr.pkt_size = sizeof(afecmd_wr);
1449 afecmd_wr.hdr.src_port = 0;
1450 afecmd_wr.hdr.dest_port = 0;
1451 afecmd_wr.hdr.token = 0;
1452 afecmd_wr.hdr.opcode = AFE_SERVICE_CMD_RTPORT_WR;
1453 afecmd_wr.buf_addr = (uint32_t)buf_addr_p;
1454 afecmd_wr.port_id = RT_PROXY_PORT_001_TX;
1455 afecmd_wr.bytes_avail = bytes;
1456 afecmd_wr.rsvd = 0;
1457
1458 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
1459 if (ret < 0) {
1460 pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
1461 __func__, afecmd_wr.port_id, ret);
1462 ret = -EINVAL;
1463 return ret;
1464 }
1465 return 0;
1466
1467}
1468
1469int afe_rt_proxy_port_read(u32 buf_addr_p, int bytes)
1470{
1471 int ret = 0;
1472 struct afe_cmd_rtport_rd afecmd_rd;
1473
1474 if (this_afe.apr == NULL) {
1475 pr_err("%s: register to AFE is not done\n", __func__);
1476 ret = -ENODEV;
1477 return ret;
1478 }
1479 pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
1480 buf_addr_p, bytes);
1481
1482 afecmd_rd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1483 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1484 afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
1485 afecmd_rd.hdr.src_port = 0;
1486 afecmd_rd.hdr.dest_port = 0;
1487 afecmd_rd.hdr.token = 0;
1488 afecmd_rd.hdr.opcode = AFE_SERVICE_CMD_RTPORT_RD;
1489 afecmd_rd.buf_addr = (uint32_t)buf_addr_p;
1490 afecmd_rd.port_id = RT_PROXY_PORT_001_RX;
1491 afecmd_rd.bytes_avail = bytes;
1492 afecmd_rd.rsvd = 0;
1493
1494 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
1495 if (ret < 0) {
1496 pr_err("%s: AFE rtproxy read cmd to port 0x%x failed %d\n",
1497 __func__, afecmd_rd.port_id, ret);
1498 ret = -EINVAL;
1499 return ret;
1500 }
1501 return 0;
1502}
1503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504#ifdef CONFIG_DEBUG_FS
1505static struct dentry *debugfs_afelb;
1506static struct dentry *debugfs_afelb_gain;
1507
1508static int afe_debug_open(struct inode *inode, struct file *file)
1509{
1510 file->private_data = inode->i_private;
1511 pr_info("debug intf %s\n", (char *) file->private_data);
1512 return 0;
1513}
1514
1515static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
1516{
1517 char *token;
1518 int base, cnt;
1519
1520 token = strsep(&buf, " ");
1521
1522 for (cnt = 0; cnt < num_of_par; cnt++) {
1523 if (token != NULL) {
1524 if ((token[1] == 'x') || (token[1] == 'X'))
1525 base = 16;
1526 else
1527 base = 10;
1528
1529 if (strict_strtoul(token, base, &param1[cnt]) != 0)
1530 return -EINVAL;
1531
1532 token = strsep(&buf, " ");
1533 } else
1534 return -EINVAL;
1535 }
1536 return 0;
1537}
1538#define AFE_LOOPBACK_ON (1)
1539#define AFE_LOOPBACK_OFF (0)
1540static ssize_t afe_debug_write(struct file *filp,
1541 const char __user *ubuf, size_t cnt, loff_t *ppos)
1542{
1543 char *lb_str = filp->private_data;
1544 char lbuf[32];
1545 int rc;
1546 unsigned long param[5];
1547
1548 if (cnt > sizeof(lbuf) - 1)
1549 return -EINVAL;
1550
1551 rc = copy_from_user(lbuf, ubuf, cnt);
1552 if (rc)
1553 return -EFAULT;
1554
1555 lbuf[cnt] = '\0';
1556
1557 if (!strcmp(lb_str, "afe_loopback")) {
1558 rc = afe_get_parameters(lbuf, param, 3);
1559 if (!rc) {
1560 pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
1561 param[2]);
1562
1563 if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
1564 AFE_LOOPBACK_OFF)) {
1565 pr_err("%s: Error, parameter 0 incorrect\n",
1566 __func__);
1567 rc = -EINVAL;
1568 goto afe_error;
1569 }
1570 if ((afe_validate_port(param[1]) < 0) ||
1571 (afe_validate_port(param[2])) < 0) {
1572 pr_err("%s: Error, invalid afe port\n",
1573 __func__);
1574 }
1575 if (this_afe.apr == NULL) {
1576 pr_err("%s: Error, AFE not opened\n", __func__);
1577 rc = -EINVAL;
1578 } else {
1579 rc = afe_loopback(param[0], param[1], param[2]);
1580 }
1581 } else {
1582 pr_err("%s: Error, invalid parameters\n", __func__);
1583 rc = -EINVAL;
1584 }
1585
1586 } else if (!strcmp(lb_str, "afe_loopback_gain")) {
1587 rc = afe_get_parameters(lbuf, param, 2);
1588 if (!rc) {
1589 pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
1590
1591 if (afe_validate_port(param[0]) < 0) {
1592 pr_err("%s: Error, invalid afe port\n",
1593 __func__);
1594 rc = -EINVAL;
1595 goto afe_error;
1596 }
1597
Patrick Lai6d9fc602013-01-05 23:36:38 -08001598 if (param[1] > 100) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 pr_err("%s: Error, volume shoud be 0 to 100"
1600 " percentage param = %lu\n",
1601 __func__, param[1]);
1602 rc = -EINVAL;
1603 goto afe_error;
1604 }
1605
1606 param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
1607
1608 if (this_afe.apr == NULL) {
1609 pr_err("%s: Error, AFE not opened\n", __func__);
1610 rc = -EINVAL;
1611 } else {
1612 rc = afe_loopback_gain(param[0], param[1]);
1613 }
1614 } else {
1615 pr_err("%s: Error, invalid parameters\n", __func__);
1616 rc = -EINVAL;
1617 }
1618 }
1619
1620afe_error:
1621 if (rc == 0)
1622 rc = cnt;
1623 else
1624 pr_err("%s: rc = %d\n", __func__, rc);
1625
1626 return rc;
1627}
1628
1629static const struct file_operations afe_debug_fops = {
1630 .open = afe_debug_open,
1631 .write = afe_debug_write
1632};
1633#endif
1634int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
1635{
1636 struct afe_port_sidetone_command cmd_sidetone;
1637 int ret = 0;
1638
1639 pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
1640 tx_port_id, rx_port_id, enable, gain);
1641 cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1642 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1643 cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
1644 cmd_sidetone.hdr.src_port = 0;
1645 cmd_sidetone.hdr.dest_port = 0;
1646 cmd_sidetone.hdr.token = 0;
1647 cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SIDETONE_CTL;
1648 cmd_sidetone.tx_port_id = tx_port_id;
1649 cmd_sidetone.rx_port_id = rx_port_id;
1650 cmd_sidetone.gain = gain;
1651 cmd_sidetone.enable = enable;
1652
1653 atomic_set(&this_afe.state, 1);
1654 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
1655 if (ret < 0) {
1656 pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
1657 __func__, tx_port_id, rx_port_id);
1658 ret = -EINVAL;
1659 goto fail_cmd;
1660 }
1661
1662 ret = wait_event_timeout(this_afe.wait,
1663 (atomic_read(&this_afe.state) == 0),
1664 msecs_to_jiffies(TIMEOUT_MS));
1665 if (ret < 0) {
1666 pr_err("%s: wait_event timeout\n", __func__);
1667 ret = -EINVAL;
1668 goto fail_cmd;
1669 }
1670 return 0;
1671fail_cmd:
1672 return ret;
1673}
1674
1675int afe_port_stop_nowait(int port_id)
1676{
1677 struct afe_port_stop_command stop;
1678 int ret = 0;
1679
1680 if (this_afe.apr == NULL) {
1681 pr_err("AFE is already closed\n");
1682 ret = -EINVAL;
1683 goto fail_cmd;
1684 }
Jeff Ohlstein293b91f2011-12-16 13:22:46 -08001685 pr_debug("%s: port_id=%d\n", __func__, port_id);
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301686 port_id = afe_convert_virtual_to_portid(port_id);
1687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1689 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1690 stop.hdr.pkt_size = sizeof(stop);
1691 stop.hdr.src_port = 0;
1692 stop.hdr.dest_port = 0;
1693 stop.hdr.token = 0;
1694 stop.hdr.opcode = AFE_PORT_CMD_STOP;
1695 stop.port_id = port_id;
1696 stop.reserved = 0;
1697
1698 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1699
1700 if (ret == -ENETRESET) {
1701 pr_info("%s: Need to reset, calling APR deregister", __func__);
1702 return apr_deregister(this_afe.apr);
1703 } else if (IS_ERR_VALUE(ret)) {
1704 pr_err("%s: AFE close failed\n", __func__);
1705 ret = -EINVAL;
1706 }
1707
1708fail_cmd:
1709 return ret;
1710
1711}
1712
1713int afe_close(int port_id)
1714{
1715 struct afe_port_stop_command stop;
1716 int ret = 0;
1717
1718 if (this_afe.apr == NULL) {
1719 pr_err("AFE is already closed\n");
1720 ret = -EINVAL;
1721 goto fail_cmd;
1722 }
Jeff Ohlstein293b91f2011-12-16 13:22:46 -08001723 pr_debug("%s: port_id=%d\n", __func__, port_id);
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +05301724
1725 if ((port_id == RT_PROXY_DAI_001_RX) ||
1726 (port_id == RT_PROXY_DAI_002_TX)) {
1727 pr_debug("%s: before decrementing pcm_afe_instance %d\n",
1728 __func__, pcm_afe_instance[port_id & 0x1]);
1729 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1730 pcm_afe_instance[port_id & 0x1]--;
1731 if (!(pcm_afe_instance[port_id & 0x1] == 0 &&
1732 proxy_afe_instance[port_id & 0x1] == 0))
1733 return 0;
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +05301734 else
1735 afe_close_done[port_id & 0x1] = true;
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +05301736 }
1737
1738 if ((port_id == RT_PROXY_DAI_002_RX) ||
1739 (port_id == RT_PROXY_DAI_001_TX)) {
1740 pr_debug("%s: before decrementing proxy_afe_instance %d\n",
1741 __func__, proxy_afe_instance[port_id & 0x1]);
1742 port_id = VIRTUAL_ID_TO_PORTID(port_id);
1743 proxy_afe_instance[port_id & 0x1]--;
1744 if (!(pcm_afe_instance[port_id & 0x1] == 0 &&
1745 proxy_afe_instance[port_id & 0x1] == 0))
1746 return 0;
Satya Krishna Pindiproli63f53172013-01-31 20:51:23 +05301747 else
1748 afe_close_done[port_id & 0x1] = true;
Satya Krishna Pindiprolie8b84552013-01-24 09:46:10 +05301749 }
1750
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301751 port_id = afe_convert_virtual_to_portid(port_id);
1752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
1754 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
1755 stop.hdr.pkt_size = sizeof(stop);
1756 stop.hdr.src_port = 0;
1757 stop.hdr.dest_port = 0;
1758 stop.hdr.token = 0;
1759 stop.hdr.opcode = AFE_PORT_CMD_STOP;
1760 stop.port_id = port_id;
1761 stop.reserved = 0;
1762
1763 atomic_set(&this_afe.state, 1);
1764 ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
1765
1766 if (ret == -ENETRESET) {
1767 pr_info("%s: Need to reset, calling APR deregister", __func__);
1768 return apr_deregister(this_afe.apr);
1769 }
1770
1771 if (ret < 0) {
1772 pr_err("%s: AFE close failed\n", __func__);
1773 ret = -EINVAL;
1774 goto fail_cmd;
1775 }
1776
1777 ret = wait_event_timeout(this_afe.wait,
1778 (atomic_read(&this_afe.state) == 0),
1779 msecs_to_jiffies(TIMEOUT_MS));
1780 if (!ret) {
1781 pr_err("%s: wait_event timeout\n", __func__);
1782 ret = -EINVAL;
1783 goto fail_cmd;
1784 }
1785fail_cmd:
1786 return ret;
1787}
1788
1789static int __init afe_init(void)
1790{
1791 init_waitqueue_head(&this_afe.wait);
1792 atomic_set(&this_afe.state, 0);
1793 atomic_set(&this_afe.status, 0);
1794 this_afe.apr = NULL;
1795#ifdef CONFIG_DEBUG_FS
1796 debugfs_afelb = debugfs_create_file("afe_loopback",
Glenn Kasten5dfda802012-10-04 16:40:27 -07001797 0220, NULL, (void *) "afe_loopback",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 &afe_debug_fops);
1799
1800 debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
Glenn Kasten5dfda802012-10-04 16:40:27 -07001801 0220, NULL, (void *) "afe_loopback_gain",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 &afe_debug_fops);
1803
1804
1805#endif
1806 return 0;
1807}
1808
1809static void __exit afe_exit(void)
1810{
Ben Rombergerb7603232011-11-23 17:16:27 -08001811 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812#ifdef CONFIG_DEBUG_FS
1813 if (debugfs_afelb)
1814 debugfs_remove(debugfs_afelb);
1815 if (debugfs_afelb_gain)
1816 debugfs_remove(debugfs_afelb_gain);
1817#endif
Ben Rombergerb7603232011-11-23 17:16:27 -08001818 for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
Ben Romberger9e792562012-02-24 12:29:01 -08001819 if (afe_cal_addr[i].cal_paddr != 0)
1820 afe_cmd_memory_unmap_nowait(
1821 afe_cal_addr[i].cal_paddr);
Ben Rombergerb7603232011-11-23 17:16:27 -08001822 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823}
1824
1825device_initcall(afe_init);
1826__exitcall(afe_exit);