ASoc: msm: Add support for adie RX & TX calibration
Add support for adie RX & TX calibration. This calibration
is used for RMC and speaker protection. A non-blocking
function was created for AFE memory map since it is now
being called from an atomic process and the acdb driver
was changed to use to use atomic variables.
Change-Id: Id6c6ca7a303ef5ee5d23a9932e910e6a7a08805d
Signed-off-by: Ben Romberger <bromberg@codeaurora.org>
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 74a66945..a214529 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
#include <linux/wait.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
+#include <mach/qdsp6v2/audio_acdb.h>
#include <sound/apr_audio.h>
#include <sound/q6afe.h>
@@ -36,6 +37,8 @@
static struct afe_ctl this_afe;
+static uint32_t afe_cal_addr[MAX_AUDPROC_TYPES];
+
#define TIMEOUT_MS 1000
#define Q6AFE_MAX_VOLUME 0x3FFF
@@ -314,6 +317,63 @@
return ret;
}
+static void afe_send_cal_block(int32_t path, u16 port_id)
+{
+ int result = 0;
+ struct acdb_cal_block cal_block;
+ struct afe_port_cmd_set_param_no_payload afe_cal;
+ pr_debug("%s: path %d\n", __func__, path);
+
+ get_afe_cal(path, &cal_block);
+ if (cal_block.cal_size <= 0) {
+ pr_debug("%s: No AFE cal to send!\n", __func__);
+ goto done;
+ }
+
+ if (afe_cal_addr[path] != cal_block.cal_paddr) {
+ if (afe_cal_addr[path] != 0)
+ afe_cmd_memory_unmap_nowait(afe_cal_addr[path]);
+ afe_cmd_memory_map_nowait(cal_block.cal_paddr,
+ cal_block.cal_size);
+ afe_cal_addr[path] = cal_block.cal_paddr;
+ }
+
+ afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ afe_cal.hdr.pkt_size = sizeof(afe_cal);
+ afe_cal.hdr.src_port = 0;
+ afe_cal.hdr.dest_port = 0;
+ afe_cal.hdr.token = 0;
+ afe_cal.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+ afe_cal.port_id = port_id;
+ afe_cal.payload_size = cal_block.cal_size;
+ afe_cal.payload_address = cal_block.cal_paddr;
+
+ pr_debug("%s: AFE cal sent for device port = %d, path = %d, "
+ "cal size = %d, cal addr = 0x%x\n", __func__,
+ port_id, path, cal_block.cal_size, cal_block.cal_paddr);
+
+ result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
+ if (result < 0) {
+ pr_err("%s: AFE cal for port %d failed\n",
+ __func__, port_id);
+ }
+
+ pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+done:
+ return;
+}
+
+void afe_send_cal(u16 port_id)
+{
+ pr_debug("%s\n", __func__);
+
+ if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+ afe_send_cal_block(TX_CAL, port_id);
+ else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+ afe_send_cal_block(RX_CAL, port_id);
+}
+
int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
u32 rate) /* This function is no blocking */
{
@@ -365,6 +425,10 @@
ret = -EINVAL;
goto fail_cmd;
}
+
+ /* send AFE cal */
+ afe_send_cal(port_id);
+
start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
start.hdr.pkt_size = sizeof(start);
@@ -875,6 +939,45 @@
return 0;
}
+int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz)
+{
+ int ret = 0;
+ struct afe_cmd_memory_map mregion;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mregion.hdr.pkt_size = sizeof(mregion);
+ mregion.hdr.src_port = 0;
+ mregion.hdr.dest_port = 0;
+ mregion.hdr.token = 0;
+ mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
+ mregion.phy_addr = dma_addr_p;
+ mregion.mem_sz = dma_buf_sz;
+ mregion.mem_id = 0;
+ mregion.rsvd = 0;
+
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+ if (ret < 0) {
+ pr_err("%s: AFE memory map cmd failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+ return 0;
+}
+
int afe_cmd_memory_unmap(u32 dma_addr_p)
{
int ret = 0;
@@ -905,7 +1008,7 @@
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
if (ret < 0) {
- pr_err("%s: AFE memory map cmd failed %d\n",
+ pr_err("%s: AFE memory unmap cmd failed %d\n",
__func__, ret);
ret = -EINVAL;
return ret;
@@ -919,7 +1022,42 @@
ret = -EINVAL;
return ret;
}
+ return 0;
+}
+int afe_cmd_memory_unmap_nowait(u32 dma_addr_p)
+{
+ int ret = 0;
+ struct afe_cmd_memory_unmap mregion;
+
+ pr_debug("%s:\n", __func__);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_debug("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mregion.hdr.pkt_size = sizeof(mregion);
+ mregion.hdr.src_port = 0;
+ mregion.hdr.dest_port = 0;
+ mregion.hdr.token = 0;
+ mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
+ mregion.phy_addr = dma_addr_p;
+
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+ if (ret < 0) {
+ pr_err("%s: AFE memory unmap cmd failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
return 0;
}
@@ -1389,12 +1527,17 @@
static void __exit afe_exit(void)
{
+ int i;
#ifdef CONFIG_DEBUG_FS
if (debugfs_afelb)
debugfs_remove(debugfs_afelb);
if (debugfs_afelb_gain)
debugfs_remove(debugfs_afelb_gain);
#endif
+ for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+ if (afe_cal_addr[i] != 0)
+ afe_cmd_memory_unmap_nowait(afe_cal_addr[i]);
+ }
}
device_initcall(afe_init);