OSDN Git Service

soc: msm: add sensor dsp framework support for anc
authorDerek Chen <chenche@codeaurora.org>
Thu, 19 Oct 2017 22:06:35 +0000 (18:06 -0400)
committerGerrit - the friendly Code Review server <code-review@localhost>
Mon, 30 Apr 2018 20:38:37 +0000 (13:38 -0700)
Add Sensor DSP framework support for Active
Engine Noise Cancellation (ANC).

CRs-fixed: 2153236
Signed-off-by: Derek Chen <chenche@codeaurora.org>
Change-Id: I4cd28ac1bbfd3fcd21174e0216c70cd664cfa319

Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
drivers/soc/qcom/Kconfig
drivers/soc/qcom/qdsp6v2/Makefile
drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c [new file with mode: 0644]
drivers/soc/qcom/qdsp6v2/audio_anc.c [new file with mode: 0644]
drivers/soc/qcom/qdsp6v2/sdsp-anc.c [new file with mode: 0644]
include/linux/qdsp6v2/audio-anc-dev-mgr.h [new file with mode: 0644]
include/linux/qdsp6v2/sdsp_anc.h [new file with mode: 0644]
include/uapi/linux/Kbuild
include/uapi/linux/msm_audio_anc.h [new file with mode: 0644]

index b6d0c9a..4cf7b93 100644 (file)
@@ -2550,3 +2550,69 @@ Example of child node that would have qcom,wdsp-cmpnt-dev-name property
        wcd934x_cdc: tavil_codec {
                qcom,wdsp-cmpnt-dev-name = "tavil_codec";
        };
+
+
+* MSM external ANC driver
+
+Required properties:
+- compatible : "qcom,msm-ext-anc"
+- qcom,refs-port-id : This is AFE port ID for playback in ADSP used for ANC Algo refers input.
+- qcom,spkr-port-id : This is AFE port ID for ANC speaker in Sensor DSP.
+- qcom,mic-port-id : This is AFE port ID for ANC mic in Sensor DSP.
+- qcom,num-anc-mic : Define the number of microphones which are directly involved in ANC processing.
+- qcom,num-add-mic-signal : Define additional microphone which might be required for monitoring the environment, input reference signal.
+- qcom,anc-mic-array : Array that specifies the channel or slot index used for ANC in one MIC hardware interface like TDM Tx.
+                       The channel or slot index is count from 0.
+                       Always place the valid channel or slot index value setting in from index 0 of this array.
+                       This array include two parts:
+                       Part I  ---- num_anc_mic, define the number of microphones which are directly involved in ANC processing.
+                       Part II ---- num_add_mic_signal, define additional microphones which might be required for
+                       monitoring the environment, input reference signal.
+                       num_add_mic_signal is always appened at the end of num_anc_mic.
+- qcom,num-anc-spkr : Define the number of speakers which are directly involved in ANC processing.
+- qcom,num-add-spkr-signal : Define additional speaker channels which connects to interested speakers for example a subwoofer.
+- qcom,anc-spkr-array : Array that specifies the channel or slot index used for ANC in one SPEAKER hardware interface like TDM Rx.
+                       The channel or slot index is count from 0.
+                       Always place the valid channel or slot index value setting in from index 0 of this array.
+                       This array include two parts:
+                       Part I  ---- num_anc_spkr, define the number of speakers which are directly involved in ANC processing.
+                       Part II ---- num_add_spkr_signal, define additional speakers.
+                       num_add_spkr_signal is always appened at the end of num_anc_spkr.
+- qcom,refs-tdm-rx : Point to phandle for refs tdm port info.
+- qcom,spkr-tdm-rx : Point to phandle for spkr tdm port info.
+- qcom,mic-tdm-tx : Point to phandle for mic tdm port info.
+Example 1:
+
+       qcom,msm-ext-anc {
+               compatible = "qcom,msm-ext-anc";
+               qcom,refs-port-id = <36906>;
+               qcom,spkr-port-id = <36912>;
+               qcom,mic-port-id = <36913>;
+               qcom,num-anc-mic = <4>;
+               qcom,num-add-mic-signal = <0>;
+               qcom,anc-mic-array = <0 1 2 3>;
+               qcom,num-anc-spkr = <4>;
+               qcom,num-add-spkr-signal = <0>;
+               qcom,anc-spkr-array = <0 1 2 3>;
+               qcom,refs-tdm-rx = <&dai_tert_tdm_rx_5>;
+               qcom,spkr-tdm-rx = <&dai_quat_tdm_rx_0>;
+               qcom,mic-tdm-tx = <&dai_quat_tdm_tx_0>;
+       };
+
+Example 2:
+
+       qcom,msm-ext-anc {
+               compatible = "qcom,msm-ext-anc";
+               qcom,refs-port-id = <36906>;
+               qcom,spkr-port-id = <36912>;
+               qcom,mic-port-id = <36913>;
+               qcom,num-anc-mic = <4>;
+               qcom,num-add-mic-signal = <2>;
+               qcom,anc-mic-array = <2 1 0 3 6 7>;
+               qcom,num-anc-spkr = <4>;
+               qcom,num-add-spkr-signal = <1>;
+               qcom,anc-spkr-array = <0 1 2 3 6>;
+               qcom,refs-tdm-rx = <&dai_tert_tdm_rx_5>;
+               qcom,spkr-tdm-rx = <&dai_quat_tdm_rx_0>;
+               qcom,mic-tdm-tx = <&dai_quat_tdm_tx_0>;
+       };
index 1e8f50c..b92c217 100644 (file)
@@ -967,4 +967,11 @@ config QCOM_QDSS_BRIDGE
          sub-system to USB on APSS side. The driver acts as a bridge between the
          MHI and USB interface. If unsure, say N.
 
+config EXT_ANC
+       bool "Enable External ANC"
+       depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3
+       help
+        This option enables support for anti-noise cnacellation
+        on Sensor DSP.
+
 source "drivers/soc/qcom/memshare/Kconfig"
index 90feb8b..0a0e258 100644 (file)
@@ -10,3 +10,5 @@ obj-$(CONFIG_MSM_QDSP6_SSR) += audio_ssr.o
 obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.o
 obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += audio_notifier.o
 obj-$(CONFIG_MSM_CDSP_LOADER) += cdsp-loader.o
+obj-$(CONFIG_EXT_ANC) += sdsp-anc.o audio_anc.o audio-anc-dev-mgr.o
+
diff --git a/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c b/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c
new file mode 100644 (file)
index 0000000..75b114e
--- /dev/null
@@ -0,0 +1,1170 @@
+/* Copyright (c) 2018, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/clk/msm-clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/msm-dai-q6-v2.h>
+#include <linux/qdsp6v2/audio-anc-dev-mgr.h>
+#include <linux/qdsp6v2/sdsp_anc.h>
+
+#define LPM_START_ADDR      (0x9120000 + 60*1024)
+#define LPM_LENGTH          (4*1024)
+
+enum {
+       ANC_DEV_PORT_REFS = 0,
+       ANC_DEV_PORT_ANC_SPKR,
+       ANC_DEV_PORT_ANC_MIC,
+       ANC_DEV_PORT_MAX,
+};
+
+struct anc_tdm_port_cfg_info {
+       u16 port_id;
+       struct afe_param_id_tdm_cfg port_cfg;
+};
+
+struct anc_tdm_group_set_info {
+       struct afe_param_id_group_device_tdm_cfg gp_cfg;
+       uint32_t num_tdm_group_ports;
+       struct afe_clk_set tdm_clk_set;
+       uint32_t clk_mode;
+};
+
+struct anc_dev_drv_info {
+       uint32_t state;
+       uint32_t rpm;
+       uint32_t bypass_mode;
+       uint32_t algo_module_id;
+};
+
+struct anc_dev_port_cfg_info {
+       uint32_t port_id;
+       uint32_t sample_rate;
+       uint32_t num_channels;
+       uint32_t bit_width;
+};
+
+static struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info
+                       anc_mic_spkr_layout;
+
+static struct anc_dev_port_cfg_info anc_port_cfg[ANC_DEV_PORT_MAX];
+
+static struct anc_tdm_group_set_info anc_dev_tdm_gp_set[IDX_GROUP_TDM_MAX];
+
+static struct anc_tdm_port_cfg_info anc_dev_tdm_port_cfg[IDX_TDM_MAX];
+
+static struct anc_dev_drv_info this_anc_dev_info;
+
+static int anc_dev_get_free_tdm_gp_cfg_idx(void)
+{
+       int idx = -1;
+       int i;
+
+       for (i = 0; i < IDX_GROUP_TDM_MAX; i++) {
+               if (anc_dev_tdm_gp_set[i].gp_cfg.group_id == 0) {
+                       idx = i;
+                       break;
+               }
+       }
+
+       return idx;
+}
+
+static int anc_dev_get_free_tdm_port_cfg_idx(void)
+{
+       int idx = -1;
+       int i;
+
+       for (i = 0; i < IDX_TDM_MAX; i++) {
+               if (anc_dev_tdm_port_cfg[i].port_id == 0) {
+                       idx = i;
+                       break;
+               }
+       }
+
+       return idx;
+}
+
+static u16 get_group_id_from_port_id(int32_t port_id)
+{
+       u16 gp_id = AFE_PORT_INVALID;
+
+       switch (port_id) {
+       case AFE_PORT_ID_PRIMARY_TDM_RX:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_1:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_2:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_3:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_4:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_5:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_6:
+       case AFE_PORT_ID_PRIMARY_TDM_RX_7:
+               gp_id = AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX;
+               break;
+       case AFE_PORT_ID_SECONDARY_TDM_RX:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_1:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_2:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_3:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_4:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_5:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_6:
+       case AFE_PORT_ID_SECONDARY_TDM_RX_7:
+               gp_id = AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX;
+               break;
+       case AFE_PORT_ID_TERTIARY_TDM_RX:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_1:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_2:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_3:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_5:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_6:
+       case AFE_PORT_ID_TERTIARY_TDM_RX_7:
+               gp_id = AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX;
+               break;
+       case AFE_PORT_ID_QUATERNARY_TDM_RX:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_1:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_2:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_3:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_4:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
+       case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
+               gp_id = AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX;
+               break;
+       default:
+               break;
+       }
+
+       return gp_id;
+}
+
+static int anc_dev_get_matched_tdm_gp_cfg_idx(u16 gp_id)
+{
+       int idx = -1;
+       int i;
+
+       for (i = 0; i < IDX_GROUP_TDM_MAX; i++) {
+               if (anc_dev_tdm_gp_set[i].gp_cfg.group_id == gp_id) {
+                       idx = i;
+                       break;
+               }
+       }
+
+       return idx;
+}
+
+static int anc_dev_get_matched_tdm_port_cfg_idx(u16 port_id)
+{
+       int idx = -1;
+       int i;
+
+       for (i = 0; i < IDX_TDM_MAX; i++) {
+               if (anc_dev_tdm_port_cfg[i].port_id == port_id) {
+                       idx = i;
+                       break;
+               }
+       }
+
+       return idx;
+}
+
+static int anc_dev_tdm_set_clk(
+               struct anc_tdm_group_set_info *gp_set_data,
+               u16 port_id, bool enable)
+{
+       int rc = 0;
+
+       switch (gp_set_data->gp_cfg.group_id) {
+       case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_RX:
+       case AFE_GROUP_DEVICE_ID_PRIMARY_TDM_TX:
+               if (gp_set_data->clk_mode) {
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT;
+               } else
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT;
+               break;
+       case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_RX:
+       case AFE_GROUP_DEVICE_ID_SECONDARY_TDM_TX:
+               if (gp_set_data->clk_mode) {
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT;
+               } else
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT;
+               break;
+       case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_RX:
+       case AFE_GROUP_DEVICE_ID_TERTIARY_TDM_TX:
+               if (gp_set_data->clk_mode) {
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT;
+               } else
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT;
+               break;
+       case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_RX:
+       case AFE_GROUP_DEVICE_ID_QUATERNARY_TDM_TX:
+               if (gp_set_data->clk_mode) {
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT;
+               } else
+                       gp_set_data->tdm_clk_set.clk_id =
+                               Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT;
+               break;
+       default:
+               pr_err("%s: port id 0x%x not supported\n",
+                       __func__, port_id);
+               return -EINVAL;
+       }
+       gp_set_data->tdm_clk_set.enable = enable;
+
+       rc = afe_set_lpass_clock_v2(port_id,
+               &gp_set_data->tdm_clk_set);
+
+       if (rc < 0)
+               pr_err("%s: afe lpass clock failed, err:%d\n",
+                       __func__, rc);
+
+       return rc;
+}
+
+static int anc_dev_port_start(int32_t which_port)
+{
+       int rc = 0;
+       int pt_idx;
+
+       struct afe_tdm_port_config tdm_cfg;
+
+       pt_idx =
+       anc_dev_get_matched_tdm_port_cfg_idx(anc_port_cfg[which_port].port_id);
+
+       if (pt_idx == -1) {
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       tdm_cfg.tdm = anc_dev_tdm_port_cfg[pt_idx].port_cfg;
+
+       tdm_cfg.tdm.num_channels = anc_port_cfg[which_port].num_channels;
+       tdm_cfg.tdm.sample_rate = anc_port_cfg[which_port].sample_rate;
+       tdm_cfg.tdm.bit_width = anc_port_cfg[which_port].bit_width;
+
+       tdm_cfg.tdm.nslots_per_frame = anc_port_cfg[which_port].num_channels;
+       tdm_cfg.tdm.slot_width = anc_port_cfg[which_port].bit_width;
+       tdm_cfg.tdm.slot_mask =
+               ((1 << anc_port_cfg[which_port].num_channels) - 1);
+
+       pr_debug("%s: port_id %x num_channels %x  bit_width %x sample_rate %x nslots_per_frame %x slot_width %x slot_mask %x!\n",
+                       __func__,
+                       anc_port_cfg[which_port].port_id,
+                       tdm_cfg.tdm.num_channels,
+                       tdm_cfg.tdm.bit_width,
+                       tdm_cfg.tdm.sample_rate,
+                       tdm_cfg.tdm.nslots_per_frame,
+                       tdm_cfg.tdm.slot_width,
+                       tdm_cfg.tdm.slot_mask);
+
+       rc = anc_if_tdm_port_start(anc_port_cfg[which_port].port_id,
+                                                               &tdm_cfg);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to open ANC port from SDSP 0x%x\n",
+                       __func__, anc_port_cfg[which_port].port_id);
+               goto rtn;
+       }
+
+rtn:
+       return rc;
+}
+
+static int anc_dev_port_stop(int32_t which_port)
+{
+       int rc = 0;
+
+       rc = anc_if_tdm_port_stop(anc_port_cfg[which_port].port_id);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to stop ANC port from SDSP 0x%x\n",
+                       __func__, anc_port_cfg[which_port].port_id);
+       }
+
+       return rc;
+}
+
+int msm_anc_dev_set_info(void *info_p, int32_t anc_cmd)
+{
+       int rc = 0;
+
+       switch (anc_cmd) {
+       case ANC_CMD_RPM: {
+               struct audio_anc_rpm_info *rpm_info_p =
+                       (struct audio_anc_rpm_info *)info_p;
+
+               if (this_anc_dev_info.state)
+               rc = anc_if_set_rpm(
+                       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id,
+                       rpm_info_p->rpm);
+               else
+                       this_anc_dev_info.rpm = 0;
+               break;
+       }
+       case ANC_CMD_BYPASS_MODE: {
+               struct audio_anc_bypass_mode *bypass_mode_p =
+                       (struct audio_anc_bypass_mode *)info_p;
+
+               if (this_anc_dev_info.state)
+                       rc = anc_if_set_bypass_mode(
+                       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id,
+                       bypass_mode_p->mode);
+               else
+                       this_anc_dev_info.bypass_mode = bypass_mode_p->mode;
+               break;
+       }
+       case ANC_CMD_ALGO_MODULE: {
+               struct audio_anc_algo_module_info *module_info_p =
+               (struct audio_anc_algo_module_info *)info_p;
+
+               if (this_anc_dev_info.state)
+                       rc = anc_if_set_algo_module_id(
+                       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id,
+                       module_info_p->module_id);
+               else
+                       this_anc_dev_info.algo_module_id =
+                       module_info_p->module_id;
+               break;
+       }
+       }
+
+       return rc;
+}
+
+
+int msm_anc_dev_start(void)
+{
+       int rc = 0;
+       u16 group_id;
+       int gp_idx, pt_idx;
+       union afe_port_group_config anc_dev_gp_cfg;
+       struct afe_tdm_port_config tdm_cfg;
+
+       pr_debug("%s: ANC devices start in!\n", __func__);
+
+       memset(&tdm_cfg, 0, sizeof(tdm_cfg));
+
+       /*
+        * Refs port for ADSP
+        * 1. enable clk
+        * 2. group cfg and enable
+        * 3. Refs port cfg and start
+        */
+
+       group_id =
+       get_group_id_from_port_id(anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+
+       gp_idx = anc_dev_get_matched_tdm_gp_cfg_idx(group_id);
+
+       if (gp_idx == -1) {
+               rc = -EINVAL;
+               pr_err("%s: anc_dev_get_matched_tdm_gp_cfg_idx() failed with group_id 0x%x\n",
+                               __func__, group_id);
+               goto rtn;
+       } else {
+               rc = anc_dev_tdm_set_clk(&anc_dev_tdm_gp_set[gp_idx],
+                       (u16)anc_port_cfg[ANC_DEV_PORT_REFS].port_id, true);
+
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to enable AFE clk 0x%x\n",
+                       __func__,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+                               goto rtn;
+               }
+
+               anc_dev_gp_cfg.tdm_cfg = anc_dev_tdm_gp_set[gp_idx].gp_cfg;
+
+               anc_dev_gp_cfg.tdm_cfg.group_device_cfg_minor_version =
+               AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG;
+               anc_dev_gp_cfg.tdm_cfg.num_channels =
+               anc_port_cfg[ANC_DEV_PORT_REFS].num_channels;
+               anc_dev_gp_cfg.tdm_cfg.bit_width =
+               anc_port_cfg[ANC_DEV_PORT_REFS].bit_width;
+               anc_dev_gp_cfg.tdm_cfg.sample_rate =
+               anc_port_cfg[ANC_DEV_PORT_REFS].sample_rate;
+               anc_dev_gp_cfg.tdm_cfg.nslots_per_frame =
+               anc_port_cfg[ANC_DEV_PORT_REFS].num_channels;
+               anc_dev_gp_cfg.tdm_cfg.slot_width =
+               anc_port_cfg[ANC_DEV_PORT_REFS].bit_width;
+               anc_dev_gp_cfg.tdm_cfg.slot_mask =
+               ((1 << anc_port_cfg[ANC_DEV_PORT_REFS].num_channels) - 1);
+
+               pr_debug("%s: refs_port_id %x\n", __func__,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+
+               pr_debug("%s: anc_dev_gp_cfg num_channels %x  bit_width %x sample_rate %x nslots_per_frame %x slot_width %x slot_mask %x!\n",
+                       __func__,
+                       anc_dev_gp_cfg.tdm_cfg.num_channels,
+                       anc_dev_gp_cfg.tdm_cfg.bit_width,
+                       anc_dev_gp_cfg.tdm_cfg.sample_rate,
+                       anc_dev_gp_cfg.tdm_cfg.nslots_per_frame,
+                       anc_dev_gp_cfg.tdm_cfg.slot_width,
+                       anc_dev_gp_cfg.tdm_cfg.slot_mask);
+
+               rc = afe_port_group_enable(group_id,
+                               &anc_dev_gp_cfg, true);
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to enable AFE group 0x%x\n",
+                               __func__, group_id);
+                       goto rtn;
+               }
+
+               pt_idx =
+               anc_dev_get_matched_tdm_port_cfg_idx(
+                       anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+
+               if (pt_idx == -1) {
+                       rc = -EINVAL;
+                       pr_err("%s: anc_dev_get_matched_tdm_port_cfg_idx() failed with port_id 0x%x\n",
+                       __func__,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+                       goto rtn;
+               }
+
+               tdm_cfg.tdm = anc_dev_tdm_port_cfg[pt_idx].port_cfg;
+
+               tdm_cfg.tdm.num_channels =
+               anc_port_cfg[ANC_DEV_PORT_REFS].num_channels;
+               tdm_cfg.tdm.sample_rate =
+               anc_port_cfg[ANC_DEV_PORT_REFS].sample_rate;
+               tdm_cfg.tdm.bit_width =
+               anc_port_cfg[ANC_DEV_PORT_REFS].bit_width;
+
+               tdm_cfg.tdm.nslots_per_frame =
+               anc_dev_gp_cfg.tdm_cfg.nslots_per_frame;
+               tdm_cfg.tdm.slot_width = anc_dev_gp_cfg.tdm_cfg.slot_width;
+               tdm_cfg.tdm.slot_mask = anc_dev_gp_cfg.tdm_cfg.slot_mask;
+
+               rc = afe_tdm_port_start(anc_port_cfg[ANC_DEV_PORT_REFS].port_id,
+                       &tdm_cfg,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].sample_rate, 0);
+               if (IS_ERR_VALUE(rc)) {
+                       afe_port_group_enable(group_id,
+                                       &anc_dev_gp_cfg, false);
+
+                               anc_dev_tdm_set_clk(&anc_dev_tdm_gp_set[gp_idx],
+                       (u16)anc_port_cfg[ANC_DEV_PORT_REFS].port_id, false);
+
+                       pr_err("%s: fail to open AFE port 0x%x\n",
+                       __func__,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+                       goto rtn;
+               }
+
+       }
+
+       rc = anc_if_set_anc_mic_spkr_layout(
+               anc_port_cfg[ANC_DEV_PORT_REFS].port_id,
+               &anc_mic_spkr_layout);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to pass ANC MIC and SPKR layout info to SDSP 0x%x\n",
+               __func__,
+               anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+               goto rtn;
+       }
+
+       rc = anc_if_share_resource(
+       anc_port_cfg[ANC_DEV_PORT_REFS].port_id, 4, 3,
+       LPM_START_ADDR, LPM_LENGTH);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to assign lpass resource to SDSP 0x%x\n",
+               __func__,
+               anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+               goto rtn;
+       }
+
+       rc = anc_if_config_ref(anc_port_cfg[ANC_DEV_PORT_REFS].port_id,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].sample_rate,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].bit_width,
+                       anc_port_cfg[ANC_DEV_PORT_REFS].num_channels);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to refs port cfg in SDSP 0x%x\n",
+               __func__,
+               anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+               goto rtn;
+       }
+
+       if (this_anc_dev_info.algo_module_id != 0)
+               rc = anc_if_set_algo_module_id(
+               anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id,
+               this_anc_dev_info.algo_module_id);
+
+       if (this_anc_dev_info.bypass_mode != 0)
+               rc = anc_if_set_bypass_mode(
+               anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id,
+               this_anc_dev_info.bypass_mode);
+
+       group_id = get_group_id_from_port_id(
+                       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id);
+
+       gp_idx = anc_dev_get_matched_tdm_gp_cfg_idx(group_id);
+
+       if (gp_idx == -1) {
+               rc = -EINVAL;
+                       pr_err("%s: anc_dev_get_matched_tdm_gp_cfg_idx() failed with group_id 0x%x\n",
+                               __func__, group_id);
+               goto rtn;
+       } else {
+               rc = anc_dev_tdm_set_clk(&anc_dev_tdm_gp_set[gp_idx],
+                       (u16)anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, true);
+
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to enable AFE clk 0x%x\n",
+                       __func__,
+                       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id);
+                       goto rtn;
+               }
+       }
+
+       rc = anc_dev_port_start(ANC_DEV_PORT_ANC_MIC);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to enable ANC MIC Port 0x%x\n",
+               __func__,
+               anc_port_cfg[ANC_DEV_PORT_ANC_MIC].port_id);
+               goto rtn;
+       }
+
+       rc = anc_dev_port_start(ANC_DEV_PORT_ANC_SPKR);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: fail to enable ANC SPKR Port 0x%x\n",
+               __func__,
+               anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id);
+               goto rtn;
+       }
+
+       this_anc_dev_info.state = 1;
+
+       pr_debug("%s: ANC devices start successfully!\n", __func__);
+
+rtn:
+       return rc;
+}
+
+int msm_anc_dev_stop(void)
+{
+       int rc = 0;
+       u16 group_id;
+       int gp_idx;
+
+       anc_dev_port_stop(ANC_DEV_PORT_ANC_SPKR);
+       anc_dev_port_stop(ANC_DEV_PORT_ANC_MIC);
+
+       group_id = get_group_id_from_port_id(
+       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id);
+
+       gp_idx = anc_dev_get_matched_tdm_gp_cfg_idx(group_id);
+
+       if (gp_idx == -1) {
+               rc = -EINVAL;
+               goto rtn;
+       } else {
+               rc = anc_dev_tdm_set_clk(&anc_dev_tdm_gp_set[gp_idx],
+               (u16)anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, false);
+
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to disable AFE clk 0x%x\n",
+                       __func__,
+                       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id);
+               }
+       }
+
+       group_id =
+       get_group_id_from_port_id(anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+
+       gp_idx = anc_dev_get_matched_tdm_gp_cfg_idx(group_id);
+
+       if (gp_idx == -1) {
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       afe_close(anc_port_cfg[ANC_DEV_PORT_REFS].port_id);
+
+       afe_port_group_enable(group_id, NULL, false);
+
+       anc_dev_tdm_set_clk(&anc_dev_tdm_gp_set[gp_idx],
+                       (u16)anc_port_cfg[ANC_DEV_PORT_REFS].port_id, false);
+
+       this_anc_dev_info.state = 0;
+       this_anc_dev_info.algo_module_id = 0;
+       this_anc_dev_info.rpm = 0;
+       this_anc_dev_info.bypass_mode = 0;
+
+       pr_debug("%s: ANC devices stop successfully!\n", __func__);
+
+rtn:
+       return rc;
+}
+
+
+static int msm_anc_tdm_dev_group_cfg_info(
+               struct platform_device *pdev,
+               struct device_node *ctx_node)
+{
+       int rc = 0;
+       const uint32_t *port_id_array = NULL;
+       uint32_t num_tdm_group_ports = 0;
+       uint32_t array_length = 0;
+       int i = 0;
+       int gp_idx = anc_dev_get_free_tdm_gp_cfg_idx();
+
+       if ((gp_idx < 0) || (gp_idx > IDX_GROUP_TDM_MAX)) {
+               dev_err(&pdev->dev, "%s: could not get abaiable tdm group cfg slot\n",
+               __func__);
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       /* extract tdm group info into static */
+       rc = of_property_read_u32(ctx_node,
+               "qcom,msm-cpudai-tdm-group-id",
+               (u32 *)&anc_dev_tdm_gp_set[gp_idx].gp_cfg.group_id);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Group ID from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-group-id");
+               goto rtn;
+       }
+
+       dev_dbg(&pdev->dev, "%s: dev_name: %s group_id: 0x%x\n",
+               __func__, dev_name(&pdev->dev),
+               anc_dev_tdm_gp_set[gp_idx].gp_cfg.group_id);
+
+       rc = of_property_read_u32(ctx_node,
+               "qcom,msm-cpudai-tdm-group-num-ports",
+               &num_tdm_group_ports);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Group Num Ports from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-group-num-ports");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Group Num Ports from DT file 0x%x\n",
+               __func__, num_tdm_group_ports);
+
+       if (num_tdm_group_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
+               dev_err(&pdev->dev, "%s Group Num Ports %d greater than Max %d\n",
+                       __func__, num_tdm_group_ports,
+                       AFE_GROUP_DEVICE_NUM_PORTS);
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       port_id_array = of_get_property(ctx_node,
+               "qcom,msm-cpudai-tdm-group-port-id",
+               &array_length);
+       if (port_id_array == NULL) {
+               dev_err(&pdev->dev, "%s port_id_array is not valid\n",
+                       __func__);
+               rc = -EINVAL;
+               goto rtn;
+       }
+       if (array_length != sizeof(uint32_t) * num_tdm_group_ports) {
+               dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
+                       __func__, array_length,
+                       sizeof(uint32_t) * num_tdm_group_ports);
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       for (i = 0; i < num_tdm_group_ports; i++)
+               anc_dev_tdm_gp_set[gp_idx].gp_cfg.port_id[i] =
+                       (u16)be32_to_cpu(port_id_array[i]);
+       /* Unused index should be filled with 0 or AFE_PORT_INVALID */
+       for (i = num_tdm_group_ports;
+                       i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
+               anc_dev_tdm_gp_set[gp_idx].gp_cfg.port_id[i] = AFE_PORT_INVALID;
+
+       anc_dev_tdm_gp_set[gp_idx].num_tdm_group_ports = num_tdm_group_ports;
+
+       /* extract tdm clk info into static */
+       rc = of_property_read_u32(ctx_node,
+               "qcom,msm-cpudai-tdm-clk-rate",
+               &anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_freq_in_hz);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Clk Rate from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-clk-rate");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Clk Rate from DT file %d\n",
+       __func__,
+       anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_freq_in_hz);
+
+       anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_set_minor_version =
+       Q6AFE_LPASS_CLK_CONFIG_API_VERSION;
+       anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_attri =
+       Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO;
+       anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_root =
+       Q6AFE_LPASS_CLK_ROOT_DEFAULT;
+
+
+       /* extract tdm clk attribute into static */
+       if (of_find_property(ctx_node,
+                       "qcom,msm-cpudai-tdm-clk-attribute", NULL)) {
+               rc = of_property_read_u16(ctx_node,
+                       "qcom,msm-cpudai-tdm-clk-attribute",
+                       &anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_attri);
+               if (rc) {
+                       dev_err(&pdev->dev, "%s: No Clk attribute in DT file %s\n",
+                       __func__,
+                       "qcom,msm-cpudai-tdm-clk-attribute");
+                       goto rtn;
+               }
+       } else {
+               dev_dbg(&pdev->dev, "%s: Clk Attribute from DT file %d\n",
+               __func__,
+               anc_dev_tdm_gp_set[gp_idx].tdm_clk_set.clk_attri);
+       }
+
+       /* extract tdm clk src master/slave info into static */
+       rc = of_property_read_u32(ctx_node,
+               "qcom,msm-cpudai-tdm-clk-internal",
+               &anc_dev_tdm_gp_set[gp_idx].clk_mode);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Clk id from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-clk-internal");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Clk id from DT file %d\n",
+               __func__, anc_dev_tdm_gp_set[gp_idx].clk_mode);
+
+rtn:
+       return rc;
+}
+
+
+static int msm_anc_tdm_dev_port_cfg_info(
+               struct platform_device *pdev,
+               struct device_node *ctx_node)
+{
+       int rc = 0;
+       u32 tdm_dev_id = 0;
+       int pt_idx = anc_dev_get_free_tdm_port_cfg_idx();
+       struct device_node *tdm_parent_node = NULL;
+
+       if ((pt_idx < 0) || (pt_idx > IDX_TDM_MAX)) {
+               dev_err(&pdev->dev, "%s: could not get abaiable tdm port cfg slot\n",
+               __func__);
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       /* retrieve device/afe id */
+       rc = of_property_read_u32(ctx_node,
+               "qcom,msm-cpudai-tdm-dev-id",
+               &tdm_dev_id);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Device ID missing in DT file\n",
+                       __func__);
+               goto rtn;
+       }
+       if ((tdm_dev_id < AFE_PORT_ID_TDM_PORT_RANGE_START) ||
+               (tdm_dev_id > AFE_PORT_ID_TDM_PORT_RANGE_END)) {
+               dev_err(&pdev->dev, "%s: Invalid TDM Device ID 0x%x in DT file\n",
+                       __func__, tdm_dev_id);
+               rc = -ENXIO;
+               goto rtn;
+       }
+       anc_dev_tdm_port_cfg[pt_idx].port_id = tdm_dev_id;
+
+       dev_dbg(&pdev->dev, "%s: dev_name: %s dev_id: 0x%x\n",
+               __func__, dev_name(&pdev->dev), tdm_dev_id);
+
+       /* TDM CFG */
+       tdm_parent_node = of_get_parent(ctx_node);
+       rc = of_property_read_u32(tdm_parent_node,
+               "qcom,msm-cpudai-tdm-sync-mode",
+               (u32 *)&anc_dev_tdm_port_cfg[pt_idx].port_cfg.sync_mode);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Sync Mode from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-sync-mode");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Sync Mode from DT file 0x%x\n",
+               __func__, anc_dev_tdm_port_cfg[pt_idx].port_cfg.sync_mode);
+
+       rc = of_property_read_u32(tdm_parent_node,
+               "qcom,msm-cpudai-tdm-sync-src",
+               (u32 *)&anc_dev_tdm_port_cfg[pt_idx].port_cfg.sync_src);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Sync Src from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-sync-src");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Sync Src from DT file 0x%x\n",
+               __func__, anc_dev_tdm_port_cfg[pt_idx].port_cfg.sync_src);
+
+       rc = of_property_read_u32(tdm_parent_node,
+       "qcom,msm-cpudai-tdm-data-out",
+       (u32 *)&anc_dev_tdm_port_cfg[pt_idx].port_cfg.ctrl_data_out_enable);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Data Out from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-data-out");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Data Out from DT file 0x%x\n",
+       __func__,
+       anc_dev_tdm_port_cfg[pt_idx].port_cfg.ctrl_data_out_enable);
+
+       rc = of_property_read_u32(tdm_parent_node,
+       "qcom,msm-cpudai-tdm-invert-sync",
+       (u32 *)&anc_dev_tdm_port_cfg[pt_idx].port_cfg.ctrl_invert_sync_pulse);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Invert Sync from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-invert-sync");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Invert Sync from DT file 0x%x\n",
+       __func__,
+       anc_dev_tdm_port_cfg[pt_idx].port_cfg.ctrl_invert_sync_pulse);
+
+       rc = of_property_read_u32(tdm_parent_node,
+       "qcom,msm-cpudai-tdm-data-delay",
+       (u32 *)&anc_dev_tdm_port_cfg[pt_idx].port_cfg.ctrl_sync_data_delay);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Data Delay from DT file %s\n",
+                       __func__, "qcom,msm-cpudai-tdm-data-delay");
+               goto rtn;
+       }
+       dev_dbg(&pdev->dev, "%s: Data Delay from DT file 0x%x\n",
+       __func__,
+       anc_dev_tdm_port_cfg[pt_idx].port_cfg.ctrl_sync_data_delay);
+
+       /* TDM CFG -- set default */
+       anc_dev_tdm_port_cfg[pt_idx].port_cfg.data_format = AFE_LINEAR_PCM_DATA;
+       anc_dev_tdm_port_cfg[pt_idx].port_cfg.tdm_cfg_minor_version =
+               AFE_API_VERSION_TDM_CONFIG;
+
+       msm_anc_tdm_dev_group_cfg_info(pdev, tdm_parent_node);
+
+       return 0;
+
+rtn:
+       return rc;
+}
+
+static int msm_anc_dev_probe(struct platform_device *pdev)
+{
+       int rc = 0;
+
+       u32 port_id = 0;
+       const uint32_t *layout_array = NULL;
+       uint32_t num_anc_io = 0;
+       uint32_t array_length = 0;
+       int i = 0;
+       uint32_t sample_rate = 0;
+       uint32_t num_channels = 0;
+       uint32_t bit_width = 0;
+
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,refs-port-id",
+               (u32 *)&port_id);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC refs-port-id DT file %s\n",
+                       __func__, "qcom,refs-port-id");
+               goto rtn;
+       }
+
+       anc_port_cfg[ANC_DEV_PORT_REFS].port_id = port_id;
+
+       dev_dbg(&pdev->dev, "%s: refs-port-id 0x%x\n",
+               __func__, port_id);
+
+       port_id = 0;
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,spkr-port-id",
+               (u32 *)&port_id);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC spkr-port-id DT file %s\n",
+                       __func__, "qcom,spkr-port-id");
+               goto rtn;
+       }
+
+       anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id = port_id;
+
+       dev_dbg(&pdev->dev, "%s: spkr-port-id 0x%x\n",
+               __func__, port_id);
+
+       port_id = 0;
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,mic-port-id",
+               (u32 *)&port_id);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC mic-port-id DT file %s\n",
+                       __func__, "qcom,mic-port-id");
+               goto rtn;
+       }
+
+       anc_port_cfg[ANC_DEV_PORT_ANC_MIC].port_id = port_id;
+
+       dev_dbg(&pdev->dev, "%s: mic-port-id 0x%x\n",
+               __func__, port_id);
+
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,sample-rate",
+               (u32 *)&sample_rate);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC sample rate DT file %s\n",
+                       __func__, "qcom,sample-rate");
+               goto rtn;
+       }
+
+       dev_dbg(&pdev->dev, "%s: ANC sample rate 0x%x\n",
+               __func__, sample_rate);
+
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,num-channels",
+               (u32 *)&num_channels);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC num channels DT file %s\n",
+                       __func__, "qcom,num-channels");
+               goto rtn;
+       }
+
+       dev_dbg(&pdev->dev, "%s: ANC num channel 0x%x\n",
+               __func__, num_channels);
+
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,bit-width",
+               (u32 *)&bit_width);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC bit width DT file %s\n",
+                       __func__, "qcom,bit-width");
+               goto rtn;
+       }
+
+       dev_dbg(&pdev->dev, "%s: ANC bit width 0x%x\n",
+               __func__, bit_width);
+
+       for (i = 0; i < ANC_DEV_PORT_MAX; i++) {
+               anc_port_cfg[i].sample_rate = sample_rate;
+               anc_port_cfg[i].num_channels = num_channels;
+               anc_port_cfg[i].bit_width = bit_width;
+       }
+
+       memset(&anc_mic_spkr_layout, 0, sizeof(anc_mic_spkr_layout));
+
+       anc_mic_spkr_layout.minor_version = 1;
+
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,num-anc-mic",
+               (u32 *)&num_anc_io);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC num_anc_mic DT file %s\n",
+                       __func__, "qcom,num-anc-mic");
+               goto rtn;
+       }
+
+       layout_array = of_get_property(pdev->dev.of_node,
+               "qcom,anc-mic-array",
+               &array_length);
+       if (layout_array == NULL) {
+               dev_err(&pdev->dev, "%s layout_array is not valid\n",
+                       __func__);
+               rc = -EINVAL;
+               goto rtn;
+       }
+       if (array_length != sizeof(uint32_t) * num_anc_io) {
+               dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
+                       __func__, array_length,
+                       sizeof(uint32_t) * num_anc_io);
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       anc_mic_spkr_layout.num_anc_mic = num_anc_io;
+
+       for (i = 0; i < num_anc_io; i++)
+               anc_mic_spkr_layout.mic_layout_array[i] =
+                       (u16)be32_to_cpu(layout_array[i]);
+
+       num_anc_io = 0;
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,num-anc-spkr",
+               (u32 *)&num_anc_io);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC num_anc_mic DT file %s\n",
+                       __func__, "qcom,num-anc-spkr");
+               goto rtn;
+       }
+
+       layout_array = of_get_property(pdev->dev.of_node,
+               "qcom,anc-spkr-array",
+               &array_length);
+       if (layout_array == NULL) {
+               dev_err(&pdev->dev, "%s layout_array is not valid\n",
+                       __func__);
+               rc = -EINVAL;
+               goto rtn;
+       }
+       if (array_length != sizeof(uint32_t) * num_anc_io) {
+               dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
+                       __func__, array_length,
+                       sizeof(uint32_t) * num_anc_io);
+               rc = -EINVAL;
+               goto rtn;
+       }
+
+       anc_mic_spkr_layout.num_anc_spkr = num_anc_io;
+
+       for (i = 0; i < num_anc_io; i++)
+               anc_mic_spkr_layout.spkr_layout_array[i] =
+                       (u16)be32_to_cpu(layout_array[i]);
+
+       dev_dbg(&pdev->dev, "%s: num_anc_mic 0x%x\n",
+               __func__, anc_mic_spkr_layout.num_anc_mic);
+
+       dev_dbg(&pdev->dev, "%s: num_anc_spkr 0x%x\n",
+               __func__, anc_mic_spkr_layout.num_anc_spkr);
+
+       num_anc_io = 0;
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,num-add-mic-signal",
+               (u32 *)&num_anc_io);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC num_add_mic_signal DT file %s\n",
+                       __func__, "qcom,num-add-mic-signal");
+               goto rtn;
+       }
+
+       anc_mic_spkr_layout.num_add_mic_signal = num_anc_io;
+
+       num_anc_io = 0;
+       rc = of_property_read_u32(pdev->dev.of_node,
+               "qcom,num-add-spkr-signal",
+               (u32 *)&num_anc_io);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: ANC num_add_spkr_signal DT file %s\n",
+                       __func__, "qcom,num-add-spkr-signal");
+               goto rtn;
+       }
+
+       anc_mic_spkr_layout.num_add_spkr_signal = num_anc_io;
+
+       dev_dbg(&pdev->dev, "%s: num_add_mic_signal 0x%x\n",
+               __func__, anc_mic_spkr_layout.num_add_mic_signal);
+
+       dev_dbg(&pdev->dev, "%s: num_add_spkr_signal 0x%x\n",
+               __func__, anc_mic_spkr_layout.num_add_spkr_signal);
+
+       /* TDM group CFG and TDM port CFG */
+       {
+               struct device_node *ctx_node = NULL;
+
+               ctx_node = of_parse_phandle(pdev->dev.of_node,
+                       "qcom,refs-tdm-rx", 0);
+               if (!ctx_node) {
+                       pr_err("%s Could not find refs-tdm-rx info\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+               rc = msm_anc_tdm_dev_port_cfg_info(pdev, ctx_node);
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to probe TDM group info\n",
+                       __func__);
+               }
+
+               ctx_node = of_parse_phandle(pdev->dev.of_node,
+                       "qcom,spkr-tdm-rx", 0);
+               if (!ctx_node) {
+                       pr_err("%s Could not find spkr-tdm-rx info\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+               rc = msm_anc_tdm_dev_port_cfg_info(pdev, ctx_node);
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to probe TDM group info\n",
+                       __func__);
+               }
+
+               ctx_node = of_parse_phandle(pdev->dev.of_node,
+                       "qcom,mic-tdm-tx", 0);
+               if (!ctx_node) {
+                       pr_err("%s Could not find mic-tdm-tx info\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+               rc = msm_anc_tdm_dev_port_cfg_info(pdev, ctx_node);
+               if (IS_ERR_VALUE(rc)) {
+                       pr_err("%s: fail to probe TDM group info\n",
+                       __func__);
+               }
+       }
+
+       rc = msm_anc_dev_create(pdev);
+
+rtn:
+       return rc;
+}
+
+static int msm_anc_dev_remove(struct platform_device *pdev)
+{
+       return msm_anc_dev_destroy(pdev);
+}
+
+static const struct of_device_id msm_anc_dev_dt_match[] = {
+       { .compatible = "qcom,msm-ext-anc", },
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_anc_dev_dt_match);
+
+static struct platform_driver msm_anc_dev = {
+       .probe  = msm_anc_dev_probe,
+       .remove = msm_anc_dev_remove,
+       .driver = {
+               .name = "msm-ext-anc",
+               .owner = THIS_MODULE,
+               .of_match_table = msm_anc_dev_dt_match,
+       },
+};
+
+int msm_anc_dev_init(void)
+{
+       int rc = 0;
+
+       memset(&anc_dev_tdm_gp_set, 0, sizeof(anc_dev_tdm_gp_set));
+       memset(&anc_dev_tdm_port_cfg, 0, sizeof(anc_dev_tdm_port_cfg));
+       memset(&anc_port_cfg, 0, sizeof(anc_port_cfg));
+       memset(&this_anc_dev_info, 0, sizeof(this_anc_dev_info));
+
+       rc = platform_driver_register(&msm_anc_dev);
+       if (rc)
+       pr_err("%s: fail to register msm ANC device driver\n",
+       __func__);
+
+       return rc;
+}
+
+int msm_anc_dev_deinit(void)
+{
+       platform_driver_unregister(&msm_anc_dev);
+       return 0;
+}
+
diff --git a/drivers/soc/qcom/qdsp6v2/audio_anc.c b/drivers/soc/qcom/qdsp6v2/audio_anc.c
new file mode 100644 (file)
index 0000000..e0abd2b
--- /dev/null
@@ -0,0 +1,350 @@
+/* Copyright (c) 2018, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+
+#include <linux/qdsp6v2/audio-anc-dev-mgr.h>
+
+#define DEVICE_NAME "msm_audio_anc"
+
+struct audio_anc_info {
+       struct cdev myc;
+       struct class *anc_class;
+};
+
+static int major;
+
+static struct audio_anc_info   audio_anc;
+
+static size_t get_user_anc_cmd_size(int32_t anc_cmd)
+{
+       size_t size = 0;
+
+       switch (anc_cmd) {
+       case ANC_CMD_START:
+       case ANC_CMD_STOP:
+               size = 0;
+               break;
+       case ANC_CMD_RPM:
+               size = sizeof(struct audio_anc_rpm_info);
+               break;
+       case ANC_CMD_BYPASS_MODE:
+               size = sizeof(struct audio_anc_bypass_mode);
+               break;
+       case ANC_CMD_ALGO_MODULE:
+               size = sizeof(struct audio_anc_algo_module_info);
+               break;
+       default:
+               pr_err("%s:Invalid anc cmd %d!",
+                       __func__, anc_cmd);
+       }
+       return size;
+}
+
+static int call_set_anc(int32_t anc_cmd,
+                               size_t anc_cmd_size, void *data)
+{
+       int                             ret = 0;
+
+       pr_err("%s EXT_ANC anc_cmd %x\n", __func__, anc_cmd);
+
+       switch (anc_cmd) {
+       case ANC_CMD_START:
+               ret = msm_anc_dev_start();
+               break;
+       case ANC_CMD_STOP:
+               ret = msm_anc_dev_stop();
+               break;
+       case ANC_CMD_RPM:
+       case ANC_CMD_BYPASS_MODE:
+       case ANC_CMD_ALGO_MODULE:
+               ret = msm_anc_dev_set_info(data, anc_cmd);
+               break;
+       default:
+               break;
+       }
+
+       pr_err("%s EXT_ANC ret %x\n", __func__, ret);
+
+       return ret;
+}
+
+static int call_get_anc(int32_t anc_cmd,
+                               size_t anc_cmd_size, void *data)
+{
+       int                             ret = 0;
+
+       switch (anc_cmd) {
+       case ANC_CMD_RPM:
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static int audio_anc_open(struct inode *inode, struct file *f)
+{
+       int ret = 0;
+
+       pr_debug("%s\n", __func__);
+       return ret;
+}
+
+static int audio_anc_close(struct inode *inode, struct file *f)
+{
+       int ret = 0;
+
+       pr_debug("%s\n", __func__);
+       return ret;
+}
+
+static long audio_anc_shared_ioctl(struct file *file, unsigned int cmd,
+                                                       void __user *arg)
+{
+       int                             ret = 0;
+       int32_t                         size;
+       struct audio_anc_packet         *data = NULL;
+
+       pr_err("%s EXT_ANC cmd %x\n", __func__, cmd);
+
+       switch (cmd) {
+       case AUDIO_ANC_SET_PARAM:
+       case AUDIO_ANC_GET_PARAM:
+               break;
+       default:
+               pr_err("%s: ioctl not found!\n", __func__);
+               ret = -EFAULT;
+               goto done;
+       }
+
+       if (copy_from_user(&size, (void *)arg, sizeof(size))) {
+               pr_err("%s: Could not copy size value from user\n", __func__);
+               ret = -EFAULT;
+               goto done;
+       } else if (size < sizeof(struct audio_anc_packet)) {
+               pr_err("%s: Invalid size sent to driver: %d, min size is %zd\n",
+                       __func__, size, sizeof(struct audio_anc_packet));
+               ret = -EINVAL;
+               goto done;
+       }
+
+       data = kmalloc(size, GFP_KERNEL);
+       if (data == NULL) {
+               ret = -ENOMEM;
+               pr_err("%s: Could not allocate memory of size %d for ioctl\n",
+                       __func__, size);
+               goto done;
+       } else if (copy_from_user(data, (void *)arg, size)) {
+               pr_err("%s: Could not copy data from user\n",
+                       __func__);
+               ret = -EFAULT;
+               goto done;
+       } else if ((data->hdr.anc_cmd < 0) ||
+               (data->hdr.anc_cmd >= ANC_CMD_MAX)) {
+               pr_err("%s: anc_cmd %d is Invalid!\n",
+                       __func__, data->hdr.anc_cmd);
+               ret = -EINVAL;
+               goto done;
+       } else if ((data->hdr.anc_cmd_size <
+               get_user_anc_cmd_size(data->hdr.anc_cmd)) ||
+               (data->hdr.anc_cmd_size >
+               sizeof(union audio_anc_data))) {
+               pr_err("%s: anc_cmd size %d is Invalid! Min is %zd Max is %zd!\n",
+                       __func__, data->hdr.anc_cmd_size,
+                       get_user_anc_cmd_size(data->hdr.anc_cmd),
+                       sizeof(union audio_anc_data));
+               ret = -EINVAL;
+               goto done;
+       }
+
+       switch (cmd) {
+       case AUDIO_ANC_SET_PARAM:
+               ret = call_set_anc(data->hdr.anc_cmd,
+                     data->hdr.anc_cmd_size, &data->anc_data);
+               break;
+       case AUDIO_ANC_GET_PARAM:
+               ret = call_get_anc(data->hdr.anc_cmd,
+                       data->hdr.anc_cmd_size, &data->anc_data);
+               break;
+       }
+
+       if (cmd == AUDIO_ANC_GET_PARAM) {
+               if (data->hdr.anc_cmd_size == 0)
+                       goto done;
+               if (data == NULL)
+                       goto done;
+               if ((sizeof(data->hdr) + data->hdr.anc_cmd_size) > size) {
+                       pr_err("%s: header size %zd plus ype size %d larger than data buffer size %d\n",
+                               __func__, sizeof(data->hdr),
+                               data->hdr.anc_cmd_size, size);
+                       ret = -EFAULT;
+                       goto done;
+               } else if (copy_to_user((void *)arg, data,
+                       sizeof(data->hdr) + data->hdr.anc_cmd_size)) {
+                       pr_err("%s: Could not copy cal type to user\n",
+                               __func__);
+                       ret = -EFAULT;
+                       goto done;
+               }
+       }
+
+done:
+       kfree(data);
+
+       pr_err("%s EXT_ANC ret %x\n", __func__, ret);
+
+       return ret;
+}
+
+static long audio_anc_ioctl(struct file *f,
+               unsigned int cmd, unsigned long arg)
+{
+       return audio_anc_shared_ioctl(f, cmd, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+
+#define AUDIO_ANC_SET_PARAM32          _IOWR(ANC_IOCTL_MAGIC, \
+                                                       300, compat_uptr_t)
+#define AUDIO_ANC_GET_PARAM32          _IOWR(ANC_IOCTL_MAGIC, \
+                                                       301, compat_uptr_t)
+
+static long audio_anc_compat_ioctl(struct file *f,
+               unsigned int cmd, unsigned long arg)
+{
+       unsigned int cmd64;
+       int ret = 0;
+
+       switch (cmd) {
+       case AUDIO_ANC_SET_PARAM32:
+               cmd64 = AUDIO_ANC_SET_PARAM;
+               break;
+       case AUDIO_ANC_GET_PARAM32:
+               cmd64 = AUDIO_ANC_GET_PARAM;
+               break;
+       default:
+               pr_err("%s: ioctl not found!\n", __func__);
+               ret = -EFAULT;
+               goto done;
+       }
+
+       ret = audio_anc_shared_ioctl(f, cmd64, compat_ptr(arg));
+done:
+       return ret;
+}
+#endif
+
+static const struct file_operations audio_anc_fops = {
+       .owner = THIS_MODULE,
+       .open = audio_anc_open,
+       .release = audio_anc_close,
+       .unlocked_ioctl = audio_anc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl =   audio_anc_compat_ioctl,
+#endif
+};
+
+int msm_anc_dev_create(struct platform_device *pdev)
+{
+       int result = 0;
+       dev_t dev = MKDEV(major, 0);
+       struct device *device_handle;
+
+       pr_debug("%s\n", __func__);
+
+       if (major) {
+               result = register_chrdev_region(dev, 1, DEVICE_NAME);
+       } else {
+               result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
+               major = MAJOR(dev);
+       }
+
+       if (result < 0) {
+               pr_err("%s: Registering msm_audio_anc device failed\n",
+                       __func__);
+               goto done;
+       }
+
+       audio_anc.anc_class = class_create(THIS_MODULE, "msm_audio_anc");
+       if (IS_ERR(audio_anc.anc_class)) {
+               result = PTR_ERR(audio_anc.anc_class);
+               pr_err("%s: Error creating anc class: %d\n",
+                       __func__, result);
+               goto unregister_chrdev_region;
+       }
+
+       cdev_init(&audio_anc.myc, &audio_anc_fops);
+       result = cdev_add(&audio_anc.myc, dev, 1);
+
+       if (result < 0) {
+               pr_err("%s: Registering file operations failed\n",
+                       __func__);
+               goto class_destroy;
+       }
+
+       device_handle = device_create(audio_anc.anc_class,
+                       NULL, audio_anc.myc.dev, NULL, "msm_audio_anc");
+       if (IS_ERR(device_handle)) {
+               result = PTR_ERR(device_handle);
+               pr_err("%s: device_create failed: %d\n", __func__, result);
+               goto class_destroy;
+       }
+
+       pr_debug("exit %s\n", __func__);
+       return 0;
+
+class_destroy:
+       class_destroy(audio_anc.anc_class);
+unregister_chrdev_region:
+       unregister_chrdev_region(MKDEV(major, 0), 1);
+done:
+       pr_err("exit %s\n", __func__);
+       return result;
+}
+
+int msm_anc_dev_destroy(struct platform_device *pdev)
+{
+       device_destroy(audio_anc.anc_class, audio_anc.myc.dev);
+       cdev_del(&audio_anc.myc);
+       class_destroy(audio_anc.anc_class);
+       unregister_chrdev_region(MKDEV(major, 0), 1);
+
+       return 0;
+}
+
+static int __init audio_anc_init(void)
+{
+       return msm_anc_dev_init();
+}
+
+static void __exit audio_anc_exit(void)
+{
+       msm_anc_dev_deinit();
+}
+
+module_init(audio_anc_init);
+module_exit(audio_anc_exit);
+
+MODULE_DESCRIPTION("SoC QDSP6v2 Audio ANC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/qdsp6v2/sdsp-anc.c b/drivers/soc/qcom/qdsp6v2/sdsp-anc.c
new file mode 100644 (file)
index 0000000..9294485
--- /dev/null
@@ -0,0 +1,801 @@
+/* Copyright (c) 2018, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_ion.h>
+#include <linux/delay.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/q6audio-v2.h>
+#include <sound/audio_cal_utils.h>
+#include <sound/adsp_err.h>
+#include <linux/qdsp6v2/apr_tal.h>
+
+#include <linux/qdsp6v2/sdsp_anc.h>
+
+#define TIMEOUT_MS 1000
+
+struct anc_if_ctl {
+       void *apr;
+       atomic_t state;
+       atomic_t status;
+       wait_queue_head_t wait[AFE_MAX_PORTS];
+       struct task_struct *task;
+       struct anc_get_rpm_resp rpm_calib_data;
+       uint32_t mmap_handle;
+       struct mutex afe_cmd_lock;
+};
+
+static struct anc_if_ctl this_anc_if;
+
+static int32_t anc_get_param_callback(uint32_t *payload,
+                       uint32_t payload_size)
+{
+       u32 param_id;
+       struct anc_get_rpm_resp *resp =
+               (struct anc_get_rpm_resp *) payload;
+
+       if (!(&(resp->pdata))) {
+               pr_err("%s: Error: resp pdata is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       param_id = resp->pdata.param_id;
+       if (param_id == AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM) {
+               if (payload_size < sizeof(this_anc_if.rpm_calib_data)) {
+                       pr_err("%s: Error: received size %d, calib_data size %zu\n",
+                               __func__, payload_size,
+                               sizeof(this_anc_if.rpm_calib_data));
+                       return -EINVAL;
+               }
+
+               memcpy(&this_anc_if.rpm_calib_data, payload,
+                       sizeof(this_anc_if.rpm_calib_data));
+               if (!this_anc_if.rpm_calib_data.status) {
+                       atomic_set(&this_anc_if.state, 0);
+          } else {
+                       pr_debug("%s: calib resp status: %d", __func__,
+                               this_anc_if.rpm_calib_data.status);
+                       atomic_set(&this_anc_if.state, -1);
+               }
+       }
+
+       return 0;
+}
+
+static void anc_if_callback_debug_print(struct apr_client_data *data)
+{
+       uint32_t *payload;
+
+       payload = data->payload;
+
+       if (data->payload_size >= 8)
+               pr_debug("%s: code = 0x%x PL#0[0x%x], PL#1[0x%x], size = %d\n",
+                       __func__, data->opcode, payload[0], payload[1],
+                       data->payload_size);
+       else if (data->payload_size >= 4)
+               pr_debug("%s: code = 0x%x PL#0[0x%x], size = %d\n",
+                       __func__, data->opcode, payload[0],
+                       data->payload_size);
+       else
+               pr_debug("%s: code = 0x%x, size = %d\n",
+                       __func__, data->opcode, data->payload_size);
+}
+
+static int32_t anc_if_callback(struct apr_client_data *data, void *priv)
+{
+       if (!data) {
+               pr_err("%s: Invalid param data\n", __func__);
+               return -EINVAL;
+       }
+       if (data->opcode == RESET_EVENTS) {
+               pr_debug("%s: reset event = %d %d apr[%pK]\n",
+                       __func__,
+                       data->reset_event, data->reset_proc, this_anc_if.apr);
+
+               if (this_anc_if.apr) {
+                       apr_reset(this_anc_if.apr);
+                       atomic_set(&this_anc_if.state, 0);
+                       this_anc_if.apr = NULL;
+               }
+
+               return 0;
+       }
+       anc_if_callback_debug_print(data);
+       if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
+               u8 *payload = data->payload;
+
+               if (!payload || (data->token >= AFE_MAX_PORTS)) {
+                       pr_err("%s: Error: size %d payload %pK token %d\n",
+                               __func__, data->payload_size,
+                               payload, data->token);
+                       return -EINVAL;
+               }
+
+               if (anc_get_param_callback(data->payload, data->payload_size))
+                       return -EINVAL;
+
+               wake_up(&this_anc_if.wait[data->token]);
+
+       } else if (data->payload_size) {
+               uint32_t *payload;
+
+               payload = data->payload;
+               if (data->opcode == APR_BASIC_RSP_RESULT) {
+                       pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x token=%d\n",
+                               __func__, data->opcode,
+                               payload[0], payload[1], data->token);
+                       /* payload[1] contains the error status for response */
+                       if (payload[1] != 0) {
+                               atomic_set(&this_anc_if.status, payload[1]);
+                               pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+                                       __func__, payload[0], payload[1]);
+                       }
+                       switch (payload[0]) {
+                       case AFE_PORT_CMD_SET_PARAM_V2:
+                       case AFE_PORT_CMD_DEVICE_STOP:
+                       case AFE_PORT_CMD_DEVICE_START:
+                       case AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS:
+                       case AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS:
+                       case AFE_SVC_CMD_SET_PARAM:
+                               atomic_set(&this_anc_if.state, 0);
+                               wake_up(&this_anc_if.wait[data->token]);
+                               break;
+                       default:
+                               pr_err("%s: Unknown cmd 0x%x\n", __func__,
+                                               payload[0]);
+                               break;
+                       }
+               } else if (data->opcode ==
+                               AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS) {
+                       pr_err("%s: ANC mmap_handle: 0x%x\n",
+                       __func__, payload[0]);
+                       this_anc_if.mmap_handle = payload[0];
+                       atomic_set(&this_anc_if.state, 0);
+                       wake_up(&this_anc_if.wait[data->token]);
+               }
+       }
+       return 0;
+}
+
+int anc_sdsp_interface_prepare(void)
+{
+       int ret = 0;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_anc_if.apr == NULL) {
+               this_anc_if.apr = apr_register("SDSP", "MAS", anc_if_callback,
+                       0xFFFFFFFF, &this_anc_if);
+               if (this_anc_if.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+               }
+       }
+       return ret;
+}
+
+/*
+ * anc_if_apr_send_pkt : returns 0 on success, negative otherwise.
+ */
+static int anc_if_apr_send_pkt(void *data, wait_queue_head_t *wait)
+{
+       int ret;
+
+       if (wait)
+               atomic_set(&this_anc_if.state, 1);
+       atomic_set(&this_anc_if.status, 0);
+       ret = apr_send_pkt(this_anc_if.apr, data);
+       if (ret > 0) {
+               if (wait) {
+                       ret = wait_event_timeout(*wait,
+                                       (atomic_read(&this_anc_if.state) == 0),
+                                       msecs_to_jiffies(TIMEOUT_MS));
+                       if (!ret) {
+                               ret = -ETIMEDOUT;
+                       } else if (atomic_read(&this_anc_if.status) > 0) {
+                               pr_err("%s: DSP returned error[%s]\n", __func__,
+                                       adsp_err_get_err_str(atomic_read(
+                                       &this_anc_if.status)));
+                               ret = adsp_err_get_lnx_err_code(
+                       atomic_read(&this_anc_if.status));
+                       } else {
+                               ret = 0;
+                       }
+               } else {
+                       ret = 0;
+               }
+       } else if (ret == 0) {
+               pr_err("%s: packet not transmitted\n", __func__);
+               /* apr_send_pkt can return 0 when nothing is transmitted */
+               ret = -EINVAL;
+       }
+
+       pr_debug("%s: leave %d\n", __func__, ret);
+       return ret;
+}
+
+static int anc_if_send_cmd_port_start(u16 port_id)
+{
+       struct afe_port_cmd_device_start start;
+       int ret, index;
+
+       pr_debug("%s: enter\n", __func__);
+       index = q6audio_get_port_index(port_id);
+       if (index < 0 || index > AFE_MAX_PORTS) {
+               pr_err("%s: AFE port index[%d] invalid!\n",
+                               __func__, index);
+               return -EINVAL;
+       }
+       ret = q6audio_validate_port(port_id);
+       if (ret < 0) {
+               pr_err("%s: port id: 0x%x ret %d\n", __func__, port_id, ret);
+               return -EINVAL;
+       }
+
+       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);
+       start.hdr.src_port = 0;
+       start.hdr.dest_port = 0;
+       start.hdr.token = index;
+       start.hdr.opcode = AFE_PORT_CMD_DEVICE_START;
+       start.port_id = q6audio_get_port_id(port_id);
+       pr_debug("%s: cmd device start opcode[0x%x] port id[0x%x]\n",
+               __func__, start.hdr.opcode, start.port_id);
+
+       ret = anc_if_apr_send_pkt(&start, &this_anc_if.wait[index]);
+       if (ret) {
+               pr_err("%s: AFE enable for port 0x%x failed %d\n", __func__,
+                               port_id, ret);
+       } else if (this_anc_if.task != current) {
+               this_anc_if.task = current;
+               pr_debug("task_name = %s pid = %d\n",
+                       this_anc_if.task->comm, this_anc_if.task->pid);
+       }
+
+       return ret;
+}
+
+int anc_if_send_cmd_port_stop(int port_id)
+{
+       struct afe_port_cmd_device_stop stop;
+       int ret = 0;
+
+       if (this_anc_if.apr == NULL) {
+               pr_err("%s: AFE is already closed\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       pr_debug("%s: port_id = 0x%x\n", __func__, port_id);
+       port_id = q6audio_convert_virtual_to_portid(port_id);
+
+       stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       stop.hdr.pkt_size = sizeof(stop);
+       stop.hdr.src_port = 0;
+       stop.hdr.dest_port = 0;
+       stop.hdr.token = 0;
+       stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP;
+       stop.port_id = port_id;
+       stop.reserved = 0;
+
+       ret = anc_if_apr_send_pkt(&stop, NULL);
+       if (ret)
+               pr_err("%s: AFE close failed %d\n", __func__, ret);
+
+fail_cmd:
+       return ret;
+
+}
+
+int anc_if_config_ref(u16 port_id, u32 sample_rate,
+               u32 bit_width, u16 num_channel)
+{
+       struct anc_config_ref_command config;
+       int ret = 0;
+       int index;
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+       memset(&config, 0, sizeof(config));
+       config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       config.hdr.pkt_size = sizeof(config);
+       config.hdr.src_port = 0;
+       config.hdr.dest_port = 0;
+       config.hdr.token = index;
+       config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+       config.param.port_id = q6audio_get_port_id(port_id);
+       config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+               sizeof(config.param);
+       config.param.payload_address_lsw = 0x00;
+       config.param.payload_address_msw = 0x00;
+       config.param.mem_map_handle = 0x00;
+       config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_REFS;
+       config.pdata.param_id = AUD_MSVC_PARAM_ID_DEV_ANC_REFS_CONFIG;
+       config.pdata.param_size = sizeof(config.refs);
+       config.refs.minor_version = AUD_MSVC_API_VERSION_DEV_ANC_REFS_CONFIG;
+       config.refs.port_id = q6audio_get_port_id(port_id);
+       config.refs.sample_rate = sample_rate;
+       config.refs.bit_width = bit_width;
+       config.refs.num_channel = num_channel;
+
+       ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+       if (ret) {
+               pr_err("%s: anc_if_config_ref for port 0x%x failed ret = %d\n",
+                               __func__, port_id, ret);
+               pr_err("%s: anc_if_config_ref size of param is %lu\n",
+                               __func__, sizeof(config.refs));
+       }
+
+       return ret;
+}
+
+int anc_if_share_resource(u16 port_id, u16 rddma_idx, u16 wrdma_idx,
+                       u32 lpm_start_addr, u32 lpm_length)
+{
+       struct anc_share_resource_command config;
+       int ret = 0;
+       int index;
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+       memset(&config, 0, sizeof(config));
+       config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       config.hdr.pkt_size = sizeof(config);
+       config.hdr.src_port = 0;
+       config.hdr.dest_port = 0;
+       config.hdr.token = index;
+       config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+       config.param.port_id = q6audio_get_port_id(port_id);
+       config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+               sizeof(config.param);
+       config.param.payload_address_lsw = 0x00;
+       config.param.payload_address_msw = 0x00;
+       config.param.mem_map_handle = 0x00;
+       config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_RESOURCE_SHARE;
+       config.pdata.param_id = AUD_MSVC_PARAM_ID_PORT_SHARE_RESOURCE_CONFIG;
+       config.pdata.param_size = sizeof(config.resource);
+       config.resource.minor_version =
+       AUD_MSVC_API_VERSION_SHARE_RESOURCE_CONFIG;
+       config.resource.rddma_idx = rddma_idx;
+       config.resource.wrdma_idx = wrdma_idx;
+       config.resource.lpm_start_addr = lpm_start_addr;
+       config.resource.lpm_length = lpm_length;
+
+       ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+       if (ret) {
+               pr_err("%s: share resource for port 0x%x failed ret = %d\n",
+                               __func__, port_id, ret);
+       }
+
+       return ret;
+}
+
+int anc_if_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port)
+{
+       struct aud_audioif_config_command config;
+       int ret = 0;
+       int index = 0;
+
+       if (!tdm_port) {
+               pr_err("%s: Error, no configuration data\n", __func__);
+               return -EINVAL;
+       }
+
+       pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+       index = q6audio_get_port_index(port_id);
+       if (index < 0 || index > AFE_MAX_PORTS) {
+               pr_err("%s: AFE port index[%d] invalid!\n",
+                               __func__, index);
+               return -EINVAL;
+       }
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       memset(&config, 0, sizeof(config));
+       config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       config.hdr.pkt_size = sizeof(config);
+       config.hdr.src_port = 0;
+       config.hdr.dest_port = 0;
+       config.hdr.token = index;
+       config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+       config.param.port_id = q6audio_get_port_id(port_id);
+       config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+               sizeof(config.param);
+       config.param.payload_address_lsw = 0x00;
+       config.param.payload_address_msw = 0x00;
+       config.param.mem_map_handle = 0x00;
+       config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+       config.pdata.param_id = AFE_PARAM_ID_TDM_CONFIG;
+       config.pdata.param_size = sizeof(config.port);
+       config.port.tdm = tdm_port->tdm;
+
+       ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+       if (ret) {
+               pr_err("%s: AFE enable for port 0x%x failed ret = %d\n",
+                               __func__, port_id, ret);
+               goto fail_cmd;
+       }
+
+       ret = anc_if_send_cmd_port_start(port_id);
+
+fail_cmd:
+       return ret;
+}
+
+int anc_if_tdm_port_stop(u16 port_id)
+{
+       return anc_if_send_cmd_port_stop(port_id);
+}
+
+int anc_if_set_rpm(u16 port_id, u32 rpm)
+{
+       int ret = 0;
+       int index;
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+
+       {
+               struct anc_set_rpm_command config;
+
+               memset(&config, 0, sizeof(config));
+               config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               config.hdr.pkt_size = sizeof(config);
+               config.hdr.src_port = 0;
+               config.hdr.dest_port = 0;
+               config.hdr.token = index;
+               config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+               config.param.port_id = q6audio_get_port_id(port_id);
+               config.param.payload_size = sizeof(config) -
+                       sizeof(struct apr_hdr) -
+                       sizeof(config.param);
+               config.param.payload_address_lsw = 0x00;
+               config.param.payload_address_msw = 0x00;
+               config.param.mem_map_handle = 0x00;
+               config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO;
+               config.pdata.param_id = AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM;
+               config.pdata.param_size = sizeof(config.set_rpm);
+               config.set_rpm.minor_version =
+               AUD_MSVC_API_VERSION_DEV_ANC_ALGO_RPM;
+               config.set_rpm.rpm = rpm;
+
+               ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+               if (ret) {
+                       pr_err("%s: share resource for port 0x%x failed ret = %d\n",
+                                       __func__, port_id, ret);
+               }
+       }
+
+       return ret;
+}
+
+int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode)
+{
+       int ret = 0;
+
+       int index;
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+
+       {
+               struct anc_set_bypass_mode_command config;
+
+               memset(&config, 0, sizeof(config));
+               config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               config.hdr.pkt_size = sizeof(config);
+               config.hdr.src_port = 0;
+               config.hdr.dest_port = 0;
+               config.hdr.token = index;
+               config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+               config.param.port_id = q6audio_get_port_id(port_id);
+               config.param.payload_size = sizeof(config) -
+                       sizeof(struct apr_hdr) -
+                       sizeof(config.param);
+               config.param.payload_address_lsw = 0x00;
+               config.param.payload_address_msw = 0x00;
+               config.param.mem_map_handle = 0x00;
+               config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO;
+               config.pdata.param_id =
+               AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_BYPASS_MODE;
+               config.pdata.param_size = sizeof(config.set_bypass_mode);
+               config.set_bypass_mode.minor_version =
+               AUD_MSVC_API_VERSION_DEV_ANC_ALGO_BYPASS_MODE;
+               config.set_bypass_mode.bypass_mode = bypass_mode;
+
+               ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+               if (ret) {
+                       pr_err("%s: share resource for port 0x%x failed ret = %d\n",
+                                       __func__, port_id, ret);
+               }
+       }
+
+       return ret;
+}
+
+int anc_if_set_algo_module_id(u16 port_id, u32 module_id)
+{
+       int ret = 0;
+
+       int index;
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+
+       {
+               struct anc_set_algo_module_id_command config;
+
+               memset(&config, 0, sizeof(config));
+               config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               config.hdr.pkt_size = sizeof(config);
+               config.hdr.src_port = 0;
+               config.hdr.dest_port = 0;
+               config.hdr.token = index;
+               config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+               config.param.port_id = q6audio_get_port_id(port_id);
+               config.param.payload_size = sizeof(config) -
+                       sizeof(struct apr_hdr) -
+                       sizeof(config.param);
+               config.param.payload_address_lsw = 0x00;
+               config.param.payload_address_msw = 0x00;
+               config.param.mem_map_handle = 0x00;
+               config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO;
+               config.pdata.param_id =
+               AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID;
+               config.pdata.param_size = sizeof(config.set_algo_module_id);
+               config.set_algo_module_id.minor_version = 1;
+               config.set_algo_module_id.module_id = module_id;
+
+               ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+               if (ret) {
+                       pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n",
+                                       __func__, port_id, ret);
+               }
+       }
+
+       return ret;
+}
+
+int anc_if_set_anc_mic_spkr_layout(u16 port_id,
+struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p)
+{
+       int ret = 0;
+
+       int index;
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+
+       {
+               struct anc_set_mic_spkr_layout_info_command config;
+
+               memset(&config, 0, sizeof(config));
+               config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               config.hdr.pkt_size = sizeof(config);
+               config.hdr.src_port = 0;
+               config.hdr.dest_port = 0;
+               config.hdr.token = index;
+               config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+               config.param.port_id = q6audio_get_port_id(port_id);
+               config.param.payload_size = sizeof(config) -
+                       sizeof(struct apr_hdr) -
+                       sizeof(config.param);
+               config.param.payload_address_lsw = 0x00;
+               config.param.payload_address_msw = 0x00;
+               config.param.mem_map_handle = 0x00;
+               config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO;
+               config.pdata.param_id =
+               AUD_MSVC_PARAM_ID_PORT_ANC_MIC_SPKR_LAYOUT_INFO;
+               config.pdata.param_size = sizeof(config.set_mic_spkr_layout);
+
+               memcpy(&config.set_mic_spkr_layout, set_mic_spkr_layout_p,
+               sizeof(config.set_mic_spkr_layout));
+               ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]);
+               if (ret) {
+                       pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n",
+                                       __func__, port_id, ret);
+               }
+       }
+
+       return ret;
+}
+
+int anc_if_cmd_memory_map(int port_id, phys_addr_t dma_addr_p,
+               u32 dma_buf_sz)
+{
+       int ret = 0;
+       int cmd_size = 0;
+       void    *payload = NULL;
+       void    *mmap_region_cmd = NULL;
+       struct afe_service_cmd_shared_mem_map_regions *mregion = NULL;
+       struct  afe_service_shared_map_region_payload *mregion_pl = NULL;
+       int index = 0;
+
+       pr_debug("%s:\n", __func__);
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+       if (index < 0 || index > AFE_MAX_PORTS) {
+               pr_err("%s: AFE port index[%d] invalid!\n",
+                               __func__, index);
+               return -EINVAL;
+       }
+       ret = q6audio_validate_port(port_id);
+       if (ret < 0) {
+               pr_err("%s: Invalid port 0x%x ret %d",
+                       __func__, port_id, ret);
+               return -EINVAL;
+       }
+
+       cmd_size = sizeof(struct afe_service_cmd_shared_mem_map_regions)
+               + sizeof(struct afe_service_shared_map_region_payload);
+
+       mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+       if (!mmap_region_cmd) {
+               ret = -ENOMEM;
+               pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+               return ret;
+       }
+
+       mregion = (struct afe_service_cmd_shared_mem_map_regions *)
+                                               mmap_region_cmd;
+       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 = cmd_size;
+       mregion->hdr.src_port = 0;
+       mregion->hdr.dest_port = 0;
+       mregion->hdr.token = index;
+       mregion->hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS;
+       mregion->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+       mregion->num_regions = 1;
+       mregion->property_flag = 0x00;
+
+       payload = ((u8 *) mmap_region_cmd +
+               sizeof(struct afe_service_cmd_shared_mem_map_regions));
+       mregion_pl = (struct afe_service_shared_map_region_payload *)payload;
+
+       mregion_pl->shm_addr_lsw = lower_32_bits(dma_addr_p);
+       mregion_pl->shm_addr_msw = msm_audio_populate_upper_32_bits(dma_addr_p);
+       mregion_pl->mem_size_bytes = dma_buf_sz;
+
+       ret = anc_if_apr_send_pkt(mmap_region_cmd, &this_anc_if.wait[index]);
+       if (ret)
+               pr_err("%s: AFE memory map cmd failed %d\n",
+                               __func__, ret);
+       kfree(mmap_region_cmd);
+       return ret;
+}
+
+int anc_if_cmd_memory_unmap(int port_id, u32 mem_map_handle)
+{
+       int ret = 0;
+       struct afe_service_cmd_shared_mem_unmap_regions mregion;
+       int index = 0;
+
+       pr_debug("%s: handle 0x%x\n", __func__, mem_map_handle);
+
+       ret = anc_sdsp_interface_prepare();
+       if (ret != 0) {
+               pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       index = q6audio_get_port_index(port_id);
+       if (index < 0 || index > AFE_MAX_PORTS) {
+               pr_err("%s: AFE port index[%d] invalid!\n",
+                               __func__, index);
+               return -EINVAL;
+       }
+       ret = q6audio_validate_port(port_id);
+       if (ret < 0) {
+               pr_err("%s: Invalid port 0x%x ret %d",
+                       __func__, port_id, ret);
+               return -EINVAL;
+       }
+
+       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 = index;
+       mregion.hdr.opcode = AFE_SERVICE_CMD_SHARED_MEM_UNMAP_REGIONS;
+       mregion.mem_map_handle = mem_map_handle;
+
+       ret = anc_if_apr_send_pkt(&mregion, &this_anc_if.wait[index]);
+       if (ret)
+               pr_err("%s: msvc memory unmap cmd failed %d\n",
+                               __func__, ret);
+
+       return ret;
+}
+
+static int __init sdsp_anc_init(void)
+{
+       int i = 0, ret = 0;
+
+       atomic_set(&this_anc_if.state, 0);
+       atomic_set(&this_anc_if.status, 0);
+       this_anc_if.apr = NULL;
+       this_anc_if.mmap_handle = 0;
+       mutex_init(&this_anc_if.afe_cmd_lock);
+       for (i = 0; i < AFE_MAX_PORTS; i++)
+               init_waitqueue_head(&this_anc_if.wait[i]);
+
+       return ret;
+}
+
+static void __exit sdsp_anc_exit(void)
+{
+       mutex_destroy(&this_anc_if.afe_cmd_lock);
+}
+
+device_initcall(sdsp_anc_init);
+__exitcall(sdsp_anc_exit);
diff --git a/include/linux/qdsp6v2/audio-anc-dev-mgr.h b/include/linux/qdsp6v2/audio-anc-dev-mgr.h
new file mode 100644 (file)
index 0000000..dfa6752
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (c) 2018, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _AUDIO_ANC_DEV_MGR_H_
+#define _AUDIO_ANC_DEV_MGR_H_
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/clk/msm-clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6afe-v2.h>
+#include <sound/msm-dai-q6-v2.h>
+#include <linux/msm_audio_anc.h>
+
+int msm_anc_dev_init(void);
+int msm_anc_dev_deinit(void);
+
+int msm_anc_dev_start(void);
+int msm_anc_dev_stop(void);
+
+int msm_anc_dev_set_info(void *info_p, int32_t anc_cmd);
+
+int msm_anc_dev_create(struct platform_device *pdev);
+
+int msm_anc_dev_destroy(struct platform_device *pdev);
+
+#endif
diff --git a/include/linux/qdsp6v2/sdsp_anc.h b/include/linux/qdsp6v2/sdsp_anc.h
new file mode 100644 (file)
index 0000000..3b236e8
--- /dev/null
@@ -0,0 +1,302 @@
+/* Copyright (c) 2018, The Linux Foundation. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __SDSP_ANC_H__
+#define __SDSP_ANC_H__
+
+#include <sound/q6afe-v2.h>
+#include <sound/apr_audio-v2.h>
+
+
+#define AUD_MSVC_MODULE_AUDIO_DEV_RESOURCE_SHARE           0x0001028A
+#define AUD_MSVC_PARAM_ID_PORT_SHARE_RESOURCE_CONFIG       0x00010297
+#define AUD_MSVC_API_VERSION_SHARE_RESOURCE_CONFIG         0x1
+#define AUD_MSVC_MODULE_AUDIO_DEV_ANC_REFS                 0x00010254
+#define AUD_MSVC_PARAM_ID_DEV_ANC_REFS_CONFIG              0x00010286
+#define AUD_MSVC_API_VERSION_DEV_ANC_REFS_CONFIG           0x1
+#define AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO                 0x00010234
+#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM                0x00010235
+#define AUD_MSVC_API_VERSION_DEV_ANC_ALGO_RPM              0x1
+
+struct aud_msvc_port_param_data_v2 {
+       /* ID of the module to be configured.
+        * Supported values: Valid module ID
+        */
+       u32 module_id;
+
+       /* ID of the parameter corresponding to the supported parameters
+        * for the module ID.
+        * Supported values: Valid parameter ID
+        */
+       u32 param_id;
+
+       /* Actual size of the data for the
+        * module_id/param_id pair. The size is a
+        * multiple of four bytes.
+        * Supported values: > 0
+        */
+       u16 param_size;
+
+       /* This field must be set to zero.
+        */
+       u16 reserved;
+} __packed;
+
+
+/*  Payload of the #AFE_PORT_CMD_SET_PARAM_V2 command's
+ * configuration/calibration settings for the AFE port.
+ */
+struct aud_msvc_port_cmd_set_param_v2 {
+       /* Port interface and direction (Rx or Tx) to start.
+        */
+       u16 port_id;
+
+       /* Actual size of the payload in bytes.
+        * This is used for parsing the parameter payload.
+        * Supported values: > 0
+        */
+       u16 payload_size;
+
+       /* LSW of 64 bit Payload address.
+        * Address should be 32-byte,
+        * 4kbyte aligned and must be contiguous memory.
+        */
+       u32 payload_address_lsw;
+
+       /* MSW of 64 bit Payload address.
+        * In case of 32-bit shared memory address,
+        * this field must be set to zero.
+        * In case of 36-bit shared memory address,
+        * bit-4 to bit-31 must be set to zero.
+        * Address should be 32-byte, 4kbyte aligned
+        * and must be contiguous memory.
+        */
+       u32 payload_address_msw;
+
+       /* Memory map handle returned by
+        * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands.
+        * Supported Values:
+        * - NULL -- Message. The parameter data is in-band.
+        * - Non-NULL -- The parameter data is Out-band.Pointer to
+        * the physical address
+        * in shared memory of the payload data.
+        * An optional field is available if parameter
+        * data is in-band:
+        * aud_msvc_param_data_v2 param_data[...].
+        * For detailed payload content, see the
+        * aud_msvc_port_param_data_v2 structure.
+        */
+       u32 mem_map_handle;
+
+} __packed;
+
+/*  Payload of the #AFE_PORT_CMD_GET_PARAM_V2 command,
+ * which queries for one post/preprocessing parameter of a
+ * stream.
+ */
+struct aud_msvc_port_cmd_get_param_v2 {
+       /* Port interface and direction (Rx or Tx) to start. */
+       u16 port_id;
+
+       /* Maximum data size of the parameter ID/module ID combination.
+        * This is a multiple of four bytes
+        * Supported values: > 0
+        */
+       u16 payload_size;
+
+       /* LSW of 64 bit Payload address. Address should be 32-byte,
+        * 4kbyte aligned and must be contig memory.
+        */
+       u32 payload_address_lsw;
+
+       /* MSW of 64 bit Payload address. In case of 32-bit shared
+        * memory address, this field must be set to zero. In case of 36-bit
+        * shared memory address, bit-4 to bit-31 must be set to zero.
+        * Address should be 32-byte, 4kbyte aligned and must be contiguous
+        * memory.
+        */
+       u32 payload_address_msw;
+
+       /* Memory map handle returned by
+        * AFE_SERVICE_CMD_SHARED_MEM_MAP_REGIONS commands.
+        * Supported Values: - NULL -- Message. The parameter data is
+        * in-band. - Non-NULL -- The parameter data is Out-band.Pointer to
+        * - the physical address in shared memory of the payload data.
+        * For detailed payload content, see the aud_msvc_port_param_data_v2
+        * structure
+        */
+       u32 mem_map_handle;
+
+       /* ID of the module to be queried.
+        * Supported values: Valid module ID
+        */
+        u32 module_id;
+
+        /* ID of the parameter to be queried.
+        * Supported values: Valid parameter ID
+        */
+       u32 param_id;
+
+} __packed;
+
+struct aud_audioif_config_command {
+       struct apr_hdr                  hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       union afe_port_config            port;
+} __packed;
+
+struct aud_msvc_param_id_dev_share_resource_cfg {
+       u32                  minor_version;
+       u16                  rddma_idx;
+       u16                  wrdma_idx;
+       u32                  lpm_start_addr;
+       u32                  lpm_length;
+} __packed;
+
+
+struct aud_msvc_param_id_dev_anc_algo_rpm {
+       u32                  minor_version;
+       u32                  rpm;
+} __packed;
+
+
+struct aud_msvc_param_id_dev_anc_refs_cfg {
+       u32                  minor_version;
+       u16                  port_id;
+       u16                  num_channel;
+       u32                  sample_rate;
+       u32                  bit_width;
+} __packed;
+
+
+struct anc_share_resource_command {
+       struct apr_hdr                  hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_share_resource_cfg resource;
+} __packed;
+
+
+struct anc_config_ref_command {
+       struct apr_hdr                  hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_anc_refs_cfg refs;
+} __packed;
+
+
+
+struct anc_set_rpm_command {
+       struct apr_hdr                  hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_anc_algo_rpm set_rpm;
+} __packed;
+
+struct anc_get_rpm_command {
+       struct apr_hdr                  hdr;
+       struct aud_msvc_port_cmd_get_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_anc_algo_rpm get_rpm;
+} __packed;
+
+struct anc_get_rpm_resp {
+       uint32_t status;
+       struct aud_msvc_port_param_data_v2 pdata;
+       struct aud_msvc_param_id_dev_anc_algo_rpm res_rpm;
+} __packed;
+
+#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_BYPASS_MODE      0x0001029B
+
+#define AUD_MSVC_API_VERSION_DEV_ANC_ALGO_BYPASS_MODE    0x1
+
+#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_NO                               0x0
+#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_REFS_TO_ANC_SPKR                 0x1
+#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_ANC_MIC_TO_ANC_SPKR              0x2
+#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_REFS_MIXED_ANC_MIC_TO_ANC_SPKR   0x3
+
+struct aud_msvc_param_id_dev_anc_algo_bypass_mode {
+       uint32_t                  minor_version;
+       uint32_t                  bypass_mode;
+} __packed;
+
+struct anc_set_bypass_mode_command {
+       struct apr_hdr                   hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_anc_algo_bypass_mode set_bypass_mode;
+} __packed;
+
+#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID      0x0001023A
+
+struct aud_msvc_param_id_dev_anc_algo_module_id {
+       uint32_t                  minor_version;
+       uint32_t                  module_id;
+} __packed;
+
+struct anc_set_algo_module_id_command {
+       struct apr_hdr                   hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_anc_algo_module_id set_algo_module_id;
+} __packed;
+
+
+#define AUD_MSVC_PARAM_ID_PORT_ANC_MIC_SPKR_LAYOUT_INFO   0x0001029C
+
+#define AUD_MSVC_API_VERSION_DEV_ANC_MIC_SPKR_LAYOUT_INFO        0x1
+
+#define AUD_MSVC_ANC_MAX_NUM_OF_MICS              16
+#define AUD_MSVC_ANC_MAX_NUM_OF_SPKRS             16
+
+struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info {
+       uint32_t minor_version;
+       uint16_t mic_layout_array[AUD_MSVC_ANC_MAX_NUM_OF_MICS];
+       uint16_t spkr_layout_array[AUD_MSVC_ANC_MAX_NUM_OF_SPKRS];
+       uint16_t num_anc_mic;
+       uint16_t num_anc_spkr;
+       uint16_t num_add_mic_signal;
+       uint16_t num_add_spkr_signal;
+} __packed;
+
+struct anc_set_mic_spkr_layout_info_command {
+       struct apr_hdr                   hdr;
+       struct aud_msvc_port_cmd_set_param_v2 param;
+       struct aud_msvc_port_param_data_v2    pdata;
+       struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info
+               set_mic_spkr_layout;
+} __packed;
+
+int anc_if_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port);
+
+int anc_if_tdm_port_stop(u16 port_id);
+
+int anc_if_share_resource(u16 port_id, u16 rddma_idx, u16 wrdma_idx,
+               u32 lpm_start_addr, u32 lpm_length);
+
+int anc_if_config_ref(u16 port_id, u32 sample_rate, u32 bit_width,
+               u16 num_channel);
+
+int anc_if_set_rpm(u16 port_id, u32 rpm);
+
+int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode);
+
+int anc_if_set_algo_module_id(u16 port_id, u32 module_id);
+
+int anc_if_set_anc_mic_spkr_layout(u16 port_id,
+struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p);
+
+int anc_if_shared_mem_map(void);
+
+int anc_if_shared_mem_unmap(void);
+
+#endif /* __SDSP_ANC_H__ */
index 2604d3f..c062371 100644 (file)
@@ -296,6 +296,7 @@ header-y += msm_audio_amrnb.h
 header-y += msm_audio_amrwb.h
 header-y += msm_audio_amrwbplus.h
 header-y += msm_audio_calibration.h
+header-y += msm_audio_anc.h
 header-y += msm_audio_mvs.h
 header-y += msm_audio_qcp.h
 header-y += msm_audio_sbc.h
diff --git a/include/uapi/linux/msm_audio_anc.h b/include/uapi/linux/msm_audio_anc.h
new file mode 100644 (file)
index 0000000..028d381
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _UAPI_MSM_AUDIO_ANC_H
+#define _UAPI_MSM_AUDIO_ANC_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define ANC_IOCTL_MAGIC 'a'
+
+#define AUDIO_ANC_SET_PARAM            _IOWR(ANC_IOCTL_MAGIC, \
+               300, struct audio_anc_packet *)
+#define AUDIO_ANC_GET_PARAM            _IOWR(ANC_IOCTL_MAGIC, \
+               301, struct audio_anc_packet *)
+
+#define ANC_CMD_START   0
+#define ANC_CMD_STOP   1
+#define ANC_CMD_RPM    2
+#define ANC_CMD_BYPASS_MODE    3
+#define ANC_CMD_ALGO_MODULE    4
+
+/* room for ANC_CMD define extend */
+#define ANC_CMD_MAX   0xFF
+
+struct audio_anc_header {
+       int32_t data_size;
+       int32_t version;
+       int32_t anc_cmd;
+       int32_t anc_cmd_size;
+};
+
+struct audio_anc_rpm_info {
+       int32_t rpm;
+};
+
+struct audio_anc_bypass_mode {
+       int32_t mode;
+};
+
+struct audio_anc_algo_module_info {
+       int32_t module_id;
+};
+
+union  audio_anc_data {
+       struct audio_anc_rpm_info rpm_info;
+       struct audio_anc_bypass_mode bypass_mode_info;
+       struct audio_anc_algo_module_info algo_info;
+};
+
+struct audio_anc_packet {
+       struct audio_anc_header hdr;
+       union  audio_anc_data anc_data;
+};
+
+#endif /* _UAPI_MSM_AUDIO_ANC_H */