summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp27
-rw-r--r--Documentation/devicetree/bindings/sound/qcom-audio-dev.txt66
-rw-r--r--arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts6
-rw-r--r--arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts4
-rw-r--r--arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts4
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi51
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts6
-rw-r--r--arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts4
-rw-r--r--arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts4
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts5
-rw-r--r--arch/arm64/configs/msm-auto-gvm-perf_defconfig7
-rw-r--r--arch/arm64/configs/msm-auto-gvm_defconfig7
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c4
-rw-r--r--drivers/irqchip/irq-gic.c123
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c6
-rw-r--r--drivers/power/supply/qcom/smb-lib.c96
-rw-r--r--drivers/power/supply/qcom/smb-lib.h3
-rw-r--r--drivers/soc/qcom/Kconfig7
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c23
-rw-r--r--drivers/soc/qcom/glink_ssr.c3
-rw-r--r--drivers/soc/qcom/qdsp6v2/Makefile2
-rw-r--r--drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c1170
-rw-r--r--drivers/soc/qcom/qdsp6v2/audio_anc.c350
-rw-r--r--drivers/soc/qcom/qdsp6v2/sdsp-anc.c801
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c5
-rw-r--r--fs/proc/meminfo.c7
-rw-r--r--include/linux/diagchar.h52
-rw-r--r--include/linux/mmzone.h1
-rw-r--r--include/linux/power_supply.h3
-rw-r--r--include/linux/qdsp6v2/audio-anc-dev-mgr.h46
-rw-r--r--include/linux/qdsp6v2/sdsp_anc.h302
-rw-r--r--include/sound/apr_audio-v2.h257
-rw-r--r--include/sound/q6afe-v2.h10
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/msm_audio_anc.h53
-rw-r--r--kernel/taskstats.c6
-rw-r--r--mm/mmap.c7
-rw-r--r--mm/nommu.c7
-rw-r--r--mm/vmstat.c1
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c2
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c7
-rw-r--r--sound/soc/msm/apq8096-auto.c16
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c4
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c286
-rw-r--r--sound/soc/msm/qdsp6v2/q6audio-v2.c3
46 files changed, 3767 insertions, 101 deletions
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 000000000000..4341e3a71dad
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,27 @@
+cc_binary_host {
+ name: "unifdef",
+ srcs: ["scripts/unifdef.c"],
+ sanitize: {
+ never: true,
+ }
+}
+
+gensrcs {
+ name: "qseecom-kernel-includes",
+
+ // move to out/ as root for header generation because of scripts/unifdef
+ // storage - at the expense of extra ../ references
+ cmd: "pushd out && mkdir -p scripts && rm -f scripts/unifdef && ln -s ../../$(location unifdef) scripts/unifdef && ../$(location scripts/headers_install.sh) `dirname ../$(out)` ../ $(in) && popd",
+
+ tools: ["unifdef"],
+ tool_files: ["scripts/headers_install.sh"],
+ export_include_dirs: ["include/uapi"],
+ srcs: ["include/uapi/linux/qseecom.h"],
+ output_extension: "h",
+}
+
+cc_library_headers {
+ name: "qseecom-kernel-headers",
+ generated_headers: ["qseecom-kernel-includes"],
+ export_generated_headers: ["qseecom-kernel-includes"],
+}
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index b6d0c9affa0e..4cf7b93b922e 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -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>;
+ };
diff --git a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts
index a91ec5eeb2e7..46894ea1e530 100644
--- a/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts
+++ b/arch/arm/boot/dts/qcom/apq8096-v3-auto-adp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -36,10 +36,6 @@
};
&soc {
- qcom,msm-ssc-sensors {
- status = "disabled";
- };
-
qcom,msm-thermal {
qcom,hotplug-temp = <115>;
qcom,hotplug-temp-hysteresis = <25>;
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts
index 6c2413d98efd..e4eca6aed98b 100644
--- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts
+++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts
@@ -30,10 +30,6 @@
};
&soc {
- qcom,msm-ssc-sensors {
- status = "disabled";
- };
-
qcom,msm-thermal {
qcom,hotplug-temp = <115>;
qcom,hotplug-temp-hysteresis = <25>;
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
index eb24e7198f87..39ec8d4cb591 100644
--- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
+++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
@@ -37,10 +37,6 @@
};
&soc {
- qcom,msm-ssc-sensors {
- status = "disabled";
- };
-
qcom,msm-thermal {
qcom,hotplug-temp = <115>;
qcom,hotplug-temp-hysteresis = <25>;
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
index 2adfb8b749eb..2ab2d00de34b 100644
--- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
@@ -1041,6 +1041,12 @@
status = "disabled";
};
+ qcom,msm-ssc-sensors {
+ compatible = "qcom,msm-ssc-sensors";
+ qcom,firmware-name = "slpi";
+ status = "ok";
+ };
+
sound-adp-agave {
compatible = "qcom,apq8096-asoc-snd-adp-agave";
qcom,model = "apq8096-adp-agave-snd-card";
@@ -1107,6 +1113,37 @@
asoc-codec-names = "msm-stub-codec.1";
};
+ qcom,msm-dai-tdm-tert-rx {
+ qcom,msm-cpudai-tdm-group-num-ports = <6>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900
+ 36902 36904 36906>;
+
+ dai_tert_tdm_rx_5: qcom,msm-dai-q6-tdm-tert-rx-5 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36906>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ 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,sample-rate = <48000>;
+ qcom,num-channels = <8>;
+ qcom,bit-width = <32>;
+ 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>;
+ };
+
usb_detect: usb_detect {
compatible = "qcom,gpio-usbdetect";
qcom,vbus-det-gpio = <&pm8994_gpios 17 0>;
@@ -1547,3 +1584,17 @@
};
};
};
+
+/ {
+ qcom,sde-reserved-plane {
+ qcom,sde-plane-id@0 {
+ reg = <0x0>;
+ qcom,plane-name = "vig0";
+ };
+ };
+};
+
+&sde_kms {
+ contiguous-region = <&cont_splash_mem &cont_splash_mem_hdmi
+ &early_camera_mem>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
index 7cbc09767f62..2702ddb23a43 100644
--- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
@@ -1404,3 +1404,16 @@
};
};
+/ {
+ qcom,sde-reserved-plane {
+ qcom,sde-plane-id@0 {
+ reg = <0x0>;
+ qcom,plane-name = "vig0";
+ };
+ };
+};
+
+&sde_kms {
+ contiguous-region = <&cont_splash_mem &cont_splash_mem_hdmi
+ &early_camera_mem>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts
index 68956d71b74d..89a585bd426e 100644
--- a/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts
+++ b/arch/arm/boot/dts/qcom/msm8996-v3-auto-adp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -37,10 +37,6 @@
};
&soc {
- qcom,msm-ssc-sensors {
- status = "disabled";
- };
-
qcom,msm-thermal {
qcom,hotplug-temp = <115>;
qcom,hotplug-temp-hysteresis = <25>;
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
index 9fd2686dac67..02f5dbcc0d4d 100644
--- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
+++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp-lite.dts
@@ -30,10 +30,6 @@
};
&soc {
- qcom,msm-ssc-sensors {
- status = "disabled";
- };
-
qcom,msm-thermal {
qcom,hotplug-temp = <115>;
qcom,hotplug-temp-hysteresis = <25>;
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts
index ec1b7cec4147..05a3144fb312 100644
--- a/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts
+++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-adp.dts
@@ -37,10 +37,6 @@
};
&soc {
- qcom,msm-ssc-sensors {
- status = "disabled";
- };
-
qcom,msm-thermal {
qcom,hotplug-temp = <115>;
qcom,hotplug-temp-hysteresis = <25>;
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts
index 7900d963bef3..21e358afd21a 100644
--- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts
@@ -46,6 +46,11 @@
};
};
};
+
+ bluetooth: bt_qca6174 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&pm8994_gpios 19 0>; /* BT_EN */
+ };
};
&soc {
diff --git a/arch/arm64/configs/msm-auto-gvm-perf_defconfig b/arch/arm64/configs/msm-auto-gvm-perf_defconfig
index 91115071f99b..55655ac06803 100644
--- a/arch/arm64/configs/msm-auto-gvm-perf_defconfig
+++ b/arch/arm64/configs/msm-auto-gvm-perf_defconfig
@@ -164,8 +164,13 @@ CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_CAN=y
CONFIG_CAN_RH850=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_BTFM_SLIM=y
+CONFIG_BTFM_SLIM_WCN3990=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_DEVTMPFS=y
@@ -223,6 +228,8 @@ CONFIG_DIAG_CHAR=y
CONFIG_MSM_SMD_PKT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MSM_V2=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_NGD=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=y
diff --git a/arch/arm64/configs/msm-auto-gvm_defconfig b/arch/arm64/configs/msm-auto-gvm_defconfig
index 56f6629ee4fb..177ccef17f77 100644
--- a/arch/arm64/configs/msm-auto-gvm_defconfig
+++ b/arch/arm64/configs/msm-auto-gvm_defconfig
@@ -163,8 +163,13 @@ CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_CAN=y
CONFIG_CAN_RH850=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_BTFM_SLIM=y
+CONFIG_BTFM_SLIM_WCN3990=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_RFKILL=y
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_DEVTMPFS=y
@@ -225,6 +230,8 @@ CONFIG_DIAG_CHAR=y
CONFIG_MSM_SMD_PKT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MSM_V2=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_NGD=y
CONFIG_SPI=y
CONFIG_SPI_DEBUG=y
CONFIG_SPI_QUP=y
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 4787f2bcd768..13680130c2de 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -681,10 +681,12 @@ static enum flash_area fwu_go_nogo(struct image_header_data *header)
goto exit;
}
- while (strptr[index] >= '0' && strptr[index] <= '9') {
+ while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0'
+ && strptr[index] <= '9') {
firmware_id[index] = strptr[index];
index++;
}
+ firmware_id[index] = '\0';
retval = sstrtoul(firmware_id, 10, &image_fw_id);
kfree(firmware_id);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 10b73d9bea78..b0b534622734 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -41,6 +41,7 @@
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/syscore_ops.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -69,6 +70,7 @@ union gic_base {
};
struct gic_chip_data {
+ unsigned int irq_offset;
union gic_base dist_base;
union gic_base cpu_base;
#ifdef CONFIG_CPU_PM
@@ -85,6 +87,10 @@ struct gic_chip_data {
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
#endif
+#ifdef CONFIG_PM
+ unsigned int wakeup_irqs[32];
+ unsigned int enabled_irqs[32];
+#endif
};
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -222,6 +228,109 @@ static void gic_unmask_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
+#ifdef CONFIG_PM
+static int gic_suspend_one(struct gic_chip_data *gic)
+{
+ unsigned int i;
+ void __iomem *base = gic_data_dist_base(gic);
+
+ for (i = 0; i * 32 < gic->gic_irqs; i++) {
+ gic->enabled_irqs[i]
+ = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
+ /* disable all of them */
+ writel_relaxed(0xffffffff,
+ base + GIC_DIST_ENABLE_CLEAR + i * 4);
+ /* enable the wakeup set */
+ writel_relaxed(gic->wakeup_irqs[i],
+ base + GIC_DIST_ENABLE_SET + i * 4);
+ }
+ /* make sure all gic setting finished */
+ mb();
+ return 0;
+}
+
+static int gic_suspend(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_GIC_NR; i++)
+ gic_suspend_one(&gic_data[i]);
+ return 0;
+}
+
+static void gic_show_resume_irq(struct gic_chip_data *gic)
+{
+ unsigned int i;
+ u32 enabled;
+ u32 pending[32];
+ void __iomem *base = gic_data_dist_base(gic);
+
+ raw_spin_lock(&irq_controller_lock);
+ for (i = 0; i * 32 < gic->gic_irqs; i++) {
+ enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
+ pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
+ pending[i] &= enabled;
+ }
+ raw_spin_unlock(&irq_controller_lock);
+
+ for (i = find_first_bit((unsigned long *)pending, gic->gic_irqs);
+ i < gic->gic_irqs;
+ i = find_next_bit((unsigned long *)pending,
+ gic->gic_irqs, i+1)) {
+ unsigned int irq = irq_find_mapping(gic->domain,
+ i + gic->irq_offset);
+ struct irq_desc *desc = irq_to_desc(irq);
+ const char *name = "null";
+
+ if (desc == NULL)
+ name = "stray irq";
+ else if (desc->action && desc->action->name)
+ name = desc->action->name;
+
+ pr_warn("%s: %d triggered %s\n", __func__,
+ i + gic->irq_offset, name);
+ }
+}
+
+static void gic_resume_one(struct gic_chip_data *gic)
+{
+ unsigned int i;
+ void __iomem *base = gic_data_dist_base(gic);
+
+ gic_show_resume_irq(gic);
+ for (i = 0; i * 32 < gic->gic_irqs; i++) {
+ /* disable all of them */
+ writel_relaxed(0xffffffff,
+ base + GIC_DIST_ENABLE_CLEAR + i * 4);
+ /* enable the enabled set */
+ writel_relaxed(gic->enabled_irqs[i],
+ base + GIC_DIST_ENABLE_SET + i * 4);
+ }
+ /* make sure all gic setting finished */
+ mb();
+}
+
+static void gic_resume(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_GIC_NR; i++)
+ gic_resume_one(&gic_data[i]);
+}
+
+static struct syscore_ops gic_syscore_ops = {
+ .suspend = gic_suspend,
+ .resume = gic_resume,
+};
+
+static int __init gic_init_sys(void)
+{
+ register_syscore_ops(&gic_syscore_ops);
+ return 0;
+}
+arch_initcall(gic_init_sys);
+#endif
+
static void gic_eoi_irq(struct irq_data *d)
{
if (gic_arch_extn.irq_eoi) {
@@ -373,6 +482,20 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
static int gic_set_wake(struct irq_data *d, unsigned int on)
{
int ret = -ENXIO;
+ unsigned int reg_offset, bit_offset;
+ unsigned int gicirq = gic_irq(d);
+ struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+
+ /* per-cpu interrupts cannot be wakeup interrupts */
+ WARN_ON(gicirq < 32);
+
+ reg_offset = gicirq / 32;
+ bit_offset = gicirq % 32;
+
+ if (on)
+ gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
+ else
+ gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
if (gic_arch_extn.irq_set_wake)
ret = gic_arch_extn.irq_set_wake(d, on);
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 4beaddff47b3..02b1204789bf 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -1829,7 +1829,8 @@ static int smb2_chg_config_init(struct smb2 *chip)
switch (pmic_rev_id->pmic_subtype) {
case PMI8998_SUBTYPE:
chip->chg.smb_version = PMI8998_SUBTYPE;
- chip->chg.wa_flags |= BOOST_BACK_WA | QC_AUTH_INTERRUPT_WA_BIT;
+ chip->chg.wa_flags |= BOOST_BACK_WA | QC_AUTH_INTERRUPT_WA_BIT
+ | TYPEC_PBS_WA_BIT;
if (pmic_rev_id->rev4 == PMI8998_V1P1_REV4) /* PMI rev 1.1 */
chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
if (pmic_rev_id->rev4 == PMI8998_V2P0_REV4) /* PMI rev 2.0 */
@@ -1844,7 +1845,8 @@ static int smb2_chg_config_init(struct smb2 *chip)
break;
case PM660_SUBTYPE:
chip->chg.smb_version = PM660_SUBTYPE;
- chip->chg.wa_flags |= BOOST_BACK_WA | OTG_WA;
+ chip->chg.wa_flags |= BOOST_BACK_WA | OTG_WA | OV_IRQ_WA_BIT
+ | TYPEC_PBS_WA_BIT;
chg->param.freq_buck = pm660_params.freq_buck;
chg->param.freq_boost = pm660_params.freq_boost;
chg->chg_freq.freq_5V = 650;
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 6d3316b934de..0ed748b5d582 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -670,6 +670,7 @@ static void smblib_uusb_removal(struct smb_charger *chg)
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
+ vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -2012,6 +2013,18 @@ static int smblib_dm_pulse(struct smb_charger *chg)
return rc;
}
+static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
+{
+ int rc;
+
+ rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+ rc);
+
+ return rc;
+}
+
int smblib_dp_dm(struct smb_charger *chg, int val)
{
int target_icl_ua, rc = 0;
@@ -2063,6 +2076,21 @@ int smblib_dp_dm(struct smb_charger *chg, int val)
smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
target_icl_ua, chg->usb_icl_delta_ua);
break;
+ case POWER_SUPPLY_DP_DM_FORCE_5V:
+ rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
+ if (rc < 0)
+ pr_err("Failed to force 5V\n");
+ break;
+ case POWER_SUPPLY_DP_DM_FORCE_9V:
+ rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
+ if (rc < 0)
+ pr_err("Failed to force 9V\n");
+ break;
+ case POWER_SUPPLY_DP_DM_FORCE_12V:
+ rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
+ if (rc < 0)
+ pr_err("Failed to force 12V\n");
+ break;
case POWER_SUPPLY_DP_DM_ICL_UP:
default:
break;
@@ -2634,19 +2662,21 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg,
return -EINVAL;
}
- if (power_role == UFP_EN_CMD_BIT) {
- /* disable PBS workaround when forcing sink mode */
- rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
- if (rc < 0) {
- smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
- rc);
- }
- } else {
- /* restore it back to 0xA5 */
- rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
- if (rc < 0) {
- smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
- rc);
+ if (chg->wa_flags & TYPEC_PBS_WA_BIT) {
+ if (power_role == UFP_EN_CMD_BIT) {
+ /* disable PBS workaround when forcing sink mode */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
+ rc);
+ }
+ } else {
+ /* restore it back to 0xA5 */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
+ rc);
+ }
}
}
@@ -3426,6 +3456,33 @@ static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
rising ? "rising" : "falling");
}
+#define MICRO_10P3V 10300000
+static void smblib_check_ov_condition(struct smb_charger *chg)
+{
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ if (chg->wa_flags & OV_IRQ_WA_BIT) {
+ rc = power_supply_get_property(chg->usb_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get current voltage, rc=%d\n",
+ rc);
+ return;
+ }
+
+ if (pval.intval > MICRO_10P3V) {
+ smblib_err(chg, "USBIN OV detected\n");
+ vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, true,
+ 0);
+ pval.intval = POWER_SUPPLY_DP_DM_FORCE_5V;
+ rc = power_supply_set_property(chg->batt_psy,
+ POWER_SUPPLY_PROP_DP_DM, &pval);
+ return;
+ }
+ }
+}
+
#define QC3_PULSES_FOR_6V 5
#define QC3_PULSES_FOR_9V 20
#define QC3_PULSES_FOR_12V 35
@@ -3435,6 +3492,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
u8 stat;
int pulses;
+ smblib_check_ov_condition(chg);
power_supply_changed(chg->usb_main_psy);
if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
@@ -3967,6 +4025,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
/* reset hvdcp voters */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
+ vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
/* reset power delivery voters */
vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
@@ -4041,10 +4100,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
if (rc < 0)
smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
- /* restore crude sensor */
- rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
- if (rc < 0)
- smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
+ /* restore crude sensor if PM660/PMI8998 */
+ if (chg->wa_flags & TYPEC_PBS_WA_BIT) {
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't restore crude sensor rc=%d\n",
+ rc);
+ }
mutex_lock(&chg->vconn_oc_lock);
if (!chg->vconn_en)
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index f292ca09f532..0de99b9da7bd 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -66,6 +66,7 @@ enum print_reason {
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
#define WBC_VOTER "WBC_VOTER"
+#define OV_VOTER "OV_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -84,6 +85,8 @@ enum {
TYPEC_CC2_REMOVAL_WA_BIT = BIT(2),
QC_AUTH_INTERRUPT_WA_BIT = BIT(3),
OTG_WA = BIT(4),
+ OV_IRQ_WA_BIT = BIT(5),
+ TYPEC_PBS_WA_BIT = BIT(6),
};
enum smb_irq_index {
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 1e8f50c4ebad..b92c217dc1b5 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -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"
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index df94bbc6b696..6cf4c7b6dd8a 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -171,8 +171,6 @@ struct mailbox_config_info {
* @kwork: Work to be executed when an irq is received.
* @kworker: Handle to the entity processing of
deferred commands.
- * @tasklet Handle to tasklet to process incoming data
- packets in atomic manner.
* @task: Handle to the task context used to run @kworker.
* @use_ref: Active uses of this transport use this to grab
* a reference. Used for ssr synchronization.
@@ -216,7 +214,6 @@ struct edge_info {
struct kthread_work kwork;
struct kthread_worker kworker;
struct task_struct *task;
- struct tasklet_struct tasklet;
struct srcu_struct use_ref;
bool in_ssr;
spinlock_t rx_lock;
@@ -1191,18 +1188,6 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx)
}
/**
- * rx_worker_atomic() - worker function to process received command in atomic
- * context.
- * @param: The param parameter passed during initialization of the tasklet.
- */
-static void rx_worker_atomic(unsigned long param)
-{
- struct edge_info *einfo = (struct edge_info *)param;
-
- __rx_worker(einfo, true);
-}
-
-/**
* rx_worker() - worker function to process received commands
* @work: kwork associated with the edge to process commands on.
*/
@@ -1221,7 +1206,7 @@ irqreturn_t irq_handler(int irq, void *priv)
if (einfo->rx_reset_reg)
writel_relaxed(einfo->out_irq_mask, einfo->rx_reset_reg);
- tasklet_hi_schedule(&einfo->tasklet);
+ __rx_worker(einfo, true);
einfo->rx_irq_count++;
return IRQ_HANDLED;
@@ -2373,7 +2358,6 @@ static int glink_smem_native_probe(struct platform_device *pdev)
init_waitqueue_head(&einfo->tx_blocked_queue);
init_kthread_work(&einfo->kwork, rx_worker);
init_kthread_worker(&einfo->kworker);
- tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
einfo->read_from_fifo = read_from_fifo;
einfo->write_to_fifo = write_to_fifo;
init_srcu_struct(&einfo->use_ref);
@@ -2477,7 +2461,6 @@ smem_alloc_fail:
flush_kthread_worker(&einfo->kworker);
kthread_stop(einfo->task);
einfo->task = NULL;
- tasklet_kill(&einfo->tasklet);
kthread_fail:
iounmap(einfo->out_irq_reg);
ioremap_fail:
@@ -2563,7 +2546,6 @@ static int glink_rpm_native_probe(struct platform_device *pdev)
init_waitqueue_head(&einfo->tx_blocked_queue);
init_kthread_work(&einfo->kwork, rx_worker);
init_kthread_worker(&einfo->kworker);
- tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
einfo->intentless = true;
einfo->read_from_fifo = memcpy32_fromio;
einfo->write_to_fifo = memcpy32_toio;
@@ -2725,7 +2707,6 @@ toc_init_fail:
flush_kthread_worker(&einfo->kworker);
kthread_stop(einfo->task);
einfo->task = NULL;
- tasklet_kill(&einfo->tasklet);
kthread_fail:
iounmap(msgram);
msgram_ioremap_fail:
@@ -2854,7 +2835,6 @@ static int glink_mailbox_probe(struct platform_device *pdev)
init_waitqueue_head(&einfo->tx_blocked_queue);
init_kthread_work(&einfo->kwork, rx_worker);
init_kthread_worker(&einfo->kworker);
- tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
einfo->read_from_fifo = read_from_fifo;
einfo->write_to_fifo = write_to_fifo;
init_srcu_struct(&einfo->use_ref);
@@ -2977,7 +2957,6 @@ smem_alloc_fail:
flush_kthread_worker(&einfo->kworker);
kthread_stop(einfo->task);
einfo->task = NULL;
- tasklet_kill(&einfo->tasklet);
kthread_fail:
iounmap(einfo->rx_reset_reg);
rx_reset_ioremap_fail:
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index fe7fb1e5b925..177737f3e314 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -538,7 +538,6 @@ int notify_for_subsystem(struct subsys_info *ss_info)
* only modified during setup.
*/
atomic_set(&responses_remaining, ss_info->notify_list_len);
- init_waitqueue_head(&waitqueue);
notifications_successful = true;
list_for_each_entry(ss_leaf_entry, &ss_info->notify_list,
@@ -945,7 +944,7 @@ static int glink_ssr_probe(struct platform_device *pdev)
ss_info->cb_data = NULL;
spin_lock_init(&ss_info->link_up_lock);
spin_lock_init(&ss_info->cb_lock);
-
+ init_waitqueue_head(&waitqueue);
nb = kmalloc(sizeof(struct restart_notifier_block), GFP_KERNEL);
if (!nb) {
GLINK_SSR_ERR("<SSR> %s: Could not allocate notifier block\n",
diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile
index 90feb8b659d1..0a0e258e6ec1 100644
--- a/drivers/soc/qcom/qdsp6v2/Makefile
+++ b/drivers/soc/qcom/qdsp6v2/Makefile
@@ -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
index 000000000000..75b114e6905c
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c
@@ -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
index 000000000000..e0abd2b58027
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/audio_anc.c
@@ -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
index 000000000000..9294485f7ff2
--- /dev/null
+++ b/drivers/soc/qcom/qdsp6v2/sdsp-anc.c
@@ -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/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index c19b87d10df0..0034dfe17ac8 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -64,6 +64,9 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
list_add_tail(&page->lru, &pool->low_items);
pool->low_count++;
}
+
+ mod_zone_page_state(page_zone(page), NR_INDIRECTLY_RECLAIMABLE_BYTES,
+ (1 << (PAGE_SHIFT + pool->order)));
mutex_unlock(&pool->mutex);
return 0;
}
@@ -83,6 +86,8 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
}
list_del(&page->lru);
+ mod_zone_page_state(page_zone(page), NR_INDIRECTLY_RECLAIMABLE_BYTES,
+ -(1 << (PAGE_SHIFT + pool->order)));
return page;
}
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 9155a5a0d3b9..b7594b9fa5fa 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -79,6 +79,13 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
available += global_page_state(NR_SLAB_RECLAIMABLE) -
min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);
+ /*
+ * Part of the kernel memory, which can be released under memory
+ * pressure.
+ */
+ available += global_page_state(NR_INDIRECTLY_RECLAIMABLE_BYTES) >>
+ PAGE_SHIFT;
+
if (available < 0)
available = 0;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7c92113e20c3..112d8b73d066 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -145,10 +145,10 @@ the appropriate macros. */
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
#define MSG_MASK_TBL_CNT 26
-#define APPS_EVENT_LAST_ID 0x0B3F
+#define APPS_EVENT_LAST_ID 0x0C5A
#define MSG_SSID_0 0
-#define MSG_SSID_0_LAST 121
+#define MSG_SSID_0_LAST 125
#define MSG_SSID_1 500
#define MSG_SSID_1_LAST 506
#define MSG_SSID_2 1000
@@ -160,11 +160,11 @@ the appropriate macros. */
#define MSG_SSID_5 4000
#define MSG_SSID_5_LAST 4010
#define MSG_SSID_6 4500
-#define MSG_SSID_6_LAST 4583
+#define MSG_SSID_6_LAST 4584
#define MSG_SSID_7 4600
-#define MSG_SSID_7_LAST 4615
+#define MSG_SSID_7_LAST 4616
#define MSG_SSID_8 5000
-#define MSG_SSID_8_LAST 5033
+#define MSG_SSID_8_LAST 5034
#define MSG_SSID_9 5500
#define MSG_SSID_9_LAST 5516
#define MSG_SSID_10 6000
@@ -264,7 +264,7 @@ static const uint32_t msg_bld_masks_0[] = {
MSG_MASK_6|MSG_MASK_7|MSG_MASK_8|MSG_MASK_9|MSG_MASK_10,
MSG_LVL_MED,
MSG_LVL_LOW,
- MSG_LVL_LOW,
+ MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_LOW,
MSG_LVL_LOW,
@@ -317,7 +317,7 @@ static const uint32_t msg_bld_masks_0[] = {
MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
MSG_LVL_MED,
MSG_LVL_HIGH,
- MSG_LVL_LOW,
+ MSG_LVL_MED,
MSG_LVL_HIGH,
MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR,
@@ -486,6 +486,7 @@ static const uint32_t msg_bld_masks_6[] = {
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
+ MSG_LVL_LOW,
MSG_LVL_LOW
};
@@ -505,7 +506,9 @@ static const uint32_t msg_bld_masks_7[] = {
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
- MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL
+ MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR |
+ MSG_LVL_FATAL,
+ MSG_LVL_LOW
};
static const uint32_t msg_bld_masks_8[] = {
@@ -525,9 +528,6 @@ static const uint32_t msg_bld_masks_8[] = {
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
@@ -542,6 +542,10 @@ static const uint32_t msg_bld_masks_8[] = {
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_HIGH,
MSG_LVL_HIGH
};
@@ -644,14 +648,14 @@ static const uint32_t msg_bld_masks_10[] = {
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
- MSG_LVL_LOW,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
MSG_LVL_MED
};
@@ -797,7 +801,9 @@ static const uint32_t msg_bld_masks_19[] = {
};
static const uint32_t msg_bld_masks_20[] = {
- MSG_LVL_LOW,
+ MSG_LVL_LOW | MSG_MASK_5 | MSG_MASK_6 | MSG_MASK_7 |
+ MSG_MASK_8 | MSG_MASK_9 | MSG_MASK_10 | MSG_MASK_11 |
+ MSG_MASK_12,
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
@@ -875,7 +881,7 @@ static const uint32_t msg_bld_masks_25[] = {
/* LOG CODES */
static const uint32_t log_code_last_tbl[] = {
0x0, /* EQUIP ID 0 */
- 0x1A11, /* EQUIP ID 1 */
+ 0x1C68, /* EQUIP ID 1 */
0x0, /* EQUIP ID 2 */
0x0, /* EQUIP ID 3 */
0x4910, /* EQUIP ID 4 */
@@ -885,7 +891,7 @@ static const uint32_t log_code_last_tbl[] = {
0x0, /* EQUIP ID 8 */
0x0, /* EQUIP ID 9 */
0xA38A, /* EQUIP ID 10 */
- 0xB201, /* EQUIP ID 11 */
+ 0xB9FF, /* EQUIP ID 11 */
0x0, /* EQUIP ID 12 */
0xD1FF, /* EQUIP ID 13 */
0x0, /* EQUIP ID 14 */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 0db2f3cb1b6c..f09c5b28ed70 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -176,6 +176,7 @@ enum zone_stat_item {
NR_ANON_TRANSPARENT_HUGEPAGES,
NR_FREE_CMA_PAGES,
NR_SWAPCACHE,
+ NR_INDIRECTLY_RECLAIMABLE_BYTES, /* measured in bytes */
NR_VM_ZONE_STAT_ITEMS };
/*
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 8b8a46ce32d0..64d0797cc3a7 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -103,6 +103,9 @@ enum {
POWER_SUPPLY_DP_DM_HVDCP3_SUPPORTED = 10,
POWER_SUPPLY_DP_DM_ICL_DOWN = 11,
POWER_SUPPLY_DP_DM_ICL_UP = 12,
+ POWER_SUPPLY_DP_DM_FORCE_5V = 13,
+ POWER_SUPPLY_DP_DM_FORCE_9V = 14,
+ POWER_SUPPLY_DP_DM_FORCE_12V = 15,
};
enum {
diff --git a/include/linux/qdsp6v2/audio-anc-dev-mgr.h b/include/linux/qdsp6v2/audio-anc-dev-mgr.h
new file mode 100644
index 000000000000..dfa6752bc31b
--- /dev/null
+++ b/include/linux/qdsp6v2/audio-anc-dev-mgr.h
@@ -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
index 000000000000..3b236e827e3d
--- /dev/null
+++ b/include/linux/qdsp6v2/sdsp_anc.h
@@ -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__ */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 0393c8869b8f..ee65bdae9971 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3512,6 +3512,263 @@ struct afe_param_id_set_topology_cfg {
u32 topology_id;
} __packed;
+/*
+ * This command is used by client to request the LPASS resources.
+ * Currently this command supports only LPAIF DMA resources.
+ * Allocated resources will be in control of remote client until
+ * they get released.
+ *
+ * If all the requested resources are available then response status in
+ * AFE_CMDRSP_REQUEST_LPASS_RESOURCES payload will
+ * be updated with ADSP_EOK, otherwise it will be ADSP_EFAILED.
+ *
+ * This command is variable payload size command, and size depends
+ * on the type of resource requested.
+ *
+ * For example, if client requests AFE_LPAIF_DMA_RESOURCE_ID
+ * resources, afe_cmd_request_lpass_resources structure will
+ * be followed with the afe_cmd_request_lpass_dma_resources
+ * structure.
+ *
+ * AFE_CMDRSP_REQUEST_LPASS_RESOURCES is the response for
+ * this command, which returns the allocated resources.
+ *
+ * @apr_hdr_fields
+ * Opcode -- AFE_CMD_REQUEST_LPASS_RESOURCES
+ *
+ * @return
+ * #AFE_CMDRSP_REQUEST_LPASS_RESOURCES
+ */
+#define AFE_CMD_REQUEST_LPASS_RESOURCES 0x00010109
+
+/* Macro for requesting LPAIF DMA resources */
+#define AFE_LPAIF_DMA_RESOURCE_ID 0x00000001
+
+struct afe_cmd_request_lpass_resources {
+ /*
+ * LPASS Resource ID
+ * @values:
+ * - AFE_LPAIF_DMA_RESOURCE_ID
+ */
+ u32 resource_id;
+} __packed;
+
+/*
+ * AFE_CMD_REQUEST_LPASS_RESOURCES uses this structure when
+ * client is requesting LPAIF DMA resources.
+ *
+ * Number of read DMA channels and write DMA channels varies from chipset to
+ * chipset. HLOS needs to make sure that when it requests LPASS DMA
+ * resources, it should not impact the concurrencies which
+ * are mandatory for a given chipset.
+ */
+
+/* Macro for AFE LPAIF default DMA data type */
+#define AFE_LPAIF_DEFAULT_DMA_TYPE 0x0
+
+struct afe_cmd_request_lpass_dma_resources {
+ /*
+ * LPASS DMA Type
+ * @values:
+ * - AFE_LPAIF_DEFAULT_DMA_TYPE
+ */
+ u8 dma_type;
+ /*
+ * Number of read DMA channels required
+ * @values: >=0
+ * - 0 indicates channels are not requested
+ */
+ u8 num_read_dma_channels;
+ /*
+ * Number of write DMA channels required
+ * @values: >=0
+ * - 0 indicates channels are not requested
+ */
+ u8 num_write_dma_channels;
+ /*
+ * Reserved field for 4 byte alignment
+ * @values: 0
+ */
+ u8 reserved;
+} __packed;
+
+struct afe_request_lpass_dma_resources_command {
+ struct apr_hdr hdr;
+ struct afe_cmd_request_lpass_resources resources;
+ struct afe_cmd_request_lpass_dma_resources dma_resources;
+} __packed;
+
+/*
+ * This is the response for the command AFE_CMD_REQUEST_LPASS_RESOURCES.
+ * Payload of this command is variable.
+ *
+ * Resources allocated successfully or not, are determined by the "status"
+ * in the payload. If status is ADSP_EOK, then resources are
+ * allocated successfully and allocated resource information
+ * follows.
+ *
+ * For example, if the response resource id is AFE_LPAIF_DMA_RESOURCE_ID,
+ * afe_cmdrsp_request_lpass_dma_resources structure will
+ * follow after afe_cmdrsp_request_lpass_resources.
+ *
+ * If status is ADSP_EFAILED, this indicates requested resources
+ * are not allocated successfully. In this case the payload following
+ * this structure is invalid.
+ * @apr_hdr_fields
+ * Opcode -- AFE_CMDRSP_REQUEST_LPASS_RESOURCES
+*/
+#define AFE_CMDRSP_REQUEST_LPASS_RESOURCES 0x0001010A
+
+struct afe_cmdrsp_request_lpass_resources {
+ /*
+ * ADSP_EOK if all requested resources are allocated.
+ * ADSP_EFAILED if resource allocation is failed.
+ */
+ u32 status;
+ /*
+ * Returned LPASS DMA resource ID
+ * @values:
+ * - AFE_LPAIF_DMA_RESOURCE_ID
+ */
+ u32 resource_id;
+} __packed;
+
+/*
+ * This command will be sent as a payload for
+ * AFE_CMDRSP_REQUEST_LPASS_RESOURCES, when the LPAIF DMA resources
+ * were requested. Payload of this command is variable, which
+ * follows after the afe_cmdrsp_request_lpass_dma_resources structure.
+ * The size in bytes following this structure is sum of
+ * num_read_dma_channels and num_write_dma_channels.
+ *
+ * If the resource allocation is successful, then the payload contains
+ * the valid DMA channel indices.
+ *
+ * For example, if number of requested DMA read channels is 2, and they
+ * are successfully allocated, the variable payload contains
+ * valid DMA channel index values in first two bytes array.
+ *
+ * In the failure case this payload can be ignored, and all the values will be
+ * initialized with zeros.
+ *
+ * An example payload of the command response is below:
+ * <struct afe_cmdrsp_request_lpass_resources>
+ * <struct afe_cmdrsp_request_lpass_dma_resources>
+ * read DMA index value for each byte.
+ * write DMA index value for each byte.
+ * padded zeros, if sum of num_read_dma_channels and num_write_dma_channels
+ * are not multiples of 4.
+*/
+
+struct afe_cmdrsp_request_lpass_dma_resources {
+ /*
+ * LPASS DMA Type
+ * @values:
+ * - AFE_LPAIF_DEFAULT_DMA_TYPE
+ */
+ u8 dma_type;
+ /*
+ * Returned number of read DMA channels allocated
+ * @values: >=0
+ */
+ u8 num_read_dma_channels;
+ /*
+ * Returned number of write DMA channels allocated
+ * @values: >=0
+ */
+ u8 num_write_dma_channels;
+ /*
+ * Reserved field for 4 byte alignment
+ * @values: 0
+ */
+ u8 reserved;
+} __packed;
+
+/*
+ * This command is for releasing resources which are allocated as
+ * part of AFE_CMD_REQUEST_LPASS_RESOURCES.
+ *
+ * Payload of this command is variable, which follows
+ * after the afe_cmd_release_lpass_resources structure.
+ *
+ * If release resource is AFE_LPAIF_DMA_RESOURCE_ID
+ * afe_cmd_release_lpass_dma_resources structure will be
+ * followed after afe_cmd_release_lpass_resources.
+ *
+ *
+ * @apr_hdr_fields
+ * Opcode -- AFE_CMD_RELEASE_LPASS_RESOURCES
+
+ * @return
+ * #APRv2 IBASIC RSP Result
+*/
+#define AFE_CMD_RELEASE_LPASS_RESOURCES 0x0001010B
+
+struct afe_cmd_release_lpass_resources {
+ /*
+ * LPASS DMA resource ID
+ * @values:
+ * - AFE_LPAIF_DMA_RESOURCE_ID
+ */
+ u32 resource_id;
+} __packed;
+
+/*
+ * This payload to be appended as part of AFE_CMD_RELEASE_LPASS_RESOURCES
+ * when resource id AFE_LPAIF_DMA_RESOURCE_ID is used.
+ *
+ * Payload of this command is variable, which will be followed after the
+ * afe_cmd_release_lpass_dma_resources structure.
+ * The variable payload's size in bytes is sum of
+ * num_read_dma_channels and num_write_dma_channels.
+ * Variable payload data contains the valid DMA channel indices which are
+ * allocated as part of AFE_CMD_REQUEST_LPASS_RESOURCES.
+ *
+ * For example, if number of DMA read channels released are 2,
+ * the variable payload contains valid DMA channel
+ * index values in first two bytes of variable payload.
+ * Client needs to fill the same DMA channel indices were returned
+ * as part of AFE_CMD_RELEASE_LPASS_RESOURCES, otherwise
+ * ADSP will return the error.
+ *
+ * An example payload of the release command is below:
+ * <struct afe_cmd_release_lpass_resources>
+ * <struct afe_cmd_release_lpass_dma_resources>
+ * read DMA index value for each byte.
+ * write DMA index value for each byte.
+*/
+
+struct afe_cmd_release_lpass_dma_resources {
+ /*
+ * LPASS DMA Type
+ * @values:
+ * - AFE_LPAIF_DEFAULT_DMA_TYPE
+ */
+ u8 dma_type;
+ /*
+ * Number of read DMA channels to be released
+ * @values: >=0
+ * - 0 indicates channels are not released
+ */
+ u8 num_read_dma_channels;
+ /*
+ * Number of write DMA channels to be released
+ * @values: >=0
+ * - 0 indicates channels are not released
+ */
+ u8 num_write_dma_channels;
+ /*
+ * Reserved field for 4 byte alignment
+ * @values: 0
+ */
+ u8 reserved;
+} __packed;
+
+struct afe_release_lpass_dma_resources_command {
+ struct apr_hdr hdr;
+ struct afe_cmd_release_lpass_resources resources;
+ struct afe_cmd_release_lpass_dma_resources dma_resources;
+} __packed;
/*
* Generic encoder module ID.
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 922ebb69205d..cdbf97023f66 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -42,6 +42,9 @@
#define AFE_CLK_VERSION_V1 1
#define AFE_CLK_VERSION_V2 2
+#define AFE_MAX_RDDMA 10
+#define AFE_MAX_WRDMA 10
+
typedef int (*routing_cb)(int port);
enum {
@@ -450,4 +453,9 @@ void afe_set_routing_callback(routing_cb);
int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
u16 port);
int afe_get_svc_version(uint32_t service_id);
+int afe_request_dma_resources(uint8_t dma_type, uint8_t num_read_dma_channels,
+ uint8_t num_write_dma_channels);
+int afe_get_dma_idx(bool **ret_rddma_idx,
+ bool **ret_wrdma_idx);
+int afe_release_all_dma_resources(void);
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 2604d3f387ba..c06237170542 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -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
index 000000000000..028d381bc1a6
--- /dev/null
+++ b/include/uapi/linux/msm_audio_anc.h
@@ -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 */
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 21f82c29c914..11cc757795cd 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -54,7 +54,11 @@ static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1
[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
-static const struct nla_policy cgroupstats_cmd_get_policy[CGROUPSTATS_CMD_ATTR_MAX+1] = {
+/*
+ * We have to use TASKSTATS_CMD_ATTR_MAX here, it is the maxattr in the family.
+ * Make sure they are always aligned.
+ */
+static const struct nla_policy cgroupstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
[CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
};
diff --git a/mm/mmap.c b/mm/mmap.c
index 2339b533f4b2..5457c5f4935b 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -206,6 +206,13 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
free += global_page_state(NR_SLAB_RECLAIMABLE);
/*
+ * Part of the kernel memory, which can be released
+ * under memory pressure.
+ */
+ free += global_page_state(
+ NR_INDIRECTLY_RECLAIMABLE_BYTES) >> PAGE_SHIFT;
+
+ /*
* Leave reserved pages. The pages are not for anonymous pages.
*/
if (free <= totalreserve_pages)
diff --git a/mm/nommu.c b/mm/nommu.c
index 92be862c859b..8d75e425c21c 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1880,6 +1880,13 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
free += global_page_state(NR_SLAB_RECLAIMABLE);
/*
+ * Part of the kernel memory, which can be released
+ * under memory pressure.
+ */
+ free += global_page_state(
+ NR_INDIRECTLY_RECLAIMABLE_BYTES) >> PAGE_SHIFT;
+
+ /*
* Leave reserved pages. The pages are not for anonymous pages.
*/
if (free <= totalreserve_pages)
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 6c841595b963..9ab13e3be5df 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -765,6 +765,7 @@ const char * const vmstat_text[] = {
"nr_anon_transparent_hugepages",
"nr_free_cma",
"nr_swapcache",
+ "nr_indirectly_reclaimable",
/* enum writeback_stat_item counters */
"nr_dirty_threshold",
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 2f0e4f61c40f..9979f4a1053b 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2808,7 +2808,7 @@ static struct genl_family ip_vs_genl_family = {
.hdrsize = 0,
.name = IPVS_GENL_NAME,
.version = IPVS_GENL_VERSION,
- .maxattr = IPVS_CMD_MAX,
+ .maxattr = IPVS_CMD_ATTR_MAX,
.netnsok = true, /* Make ipvsadm to work on netns */
};
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 55eef61a01de..fe455c9b8c25 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-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
@@ -3805,12 +3805,11 @@ static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec)
}
msm_anlg_cdc_boost_off(codec);
sdm660_cdc_priv->hph_mode = NORMAL_MODE;
-
- /* 40ms to allow boost to discharge */
- msleep(40);
/* Disable PA to avoid pop during codec bring up */
snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN,
0x30, 0x00);
+ /* 40ms to allow boost to discharge */
+ msleep(40);
snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL,
0x80, 0x00);
snd_soc_write(codec,
diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c
index 0de8b0237aae..a0c5ef0dce6d 100644
--- a/sound/soc/msm/apq8096-auto.c
+++ b/sound/soc/msm/apq8096-auto.c
@@ -5699,6 +5699,22 @@ static struct snd_soc_dai_link apq8096_auto_fe_dai_links[] = {
.ignore_pmdown_time = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "DTMF RX Hostless",
+ .stream_name = "DTMF RX Hostless",
+ .cpu_dai_name = "DTMF_RX_HOSTLESS",
+ .platform_name = "msm-pcm-dtmf",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_DTMF_RX,
}
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 8a28c4fa6746..4e4970b7be33 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -8916,6 +8916,9 @@ static const struct snd_kcontrol_new quat_tdm_rx_2_voice_mixer_controls[] = {
SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUAT_TDM_RX_2,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -14954,6 +14957,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_Voice Mixer"},
{"QUAT_TDM_RX_2_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"},
+ {"QUAT_TDM_RX_2_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"QUAT_TDM_RX_2", NULL, "QUAT_TDM_RX_2_Voice Mixer"},
{"VOC_EXT_EC MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 84ab632d9b9c..38dc3639a682 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -124,6 +124,10 @@ struct afe_ctl {
int set_custom_topology;
int dev_acdb_id[AFE_MAX_PORTS];
routing_cb rt_cb;
+ int num_alloced_rddma;
+ bool alloced_rddma[AFE_MAX_RDDMA];
+ int num_alloced_wrdma;
+ bool alloced_wrdma[AFE_MAX_WRDMA];
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -385,6 +389,99 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload,
return 0;
}
+static int32_t afe_lpass_resources_callback(struct apr_client_data *data)
+{
+ uint8_t *payload = data->payload;
+ struct afe_cmdrsp_request_lpass_resources *resources =
+ (struct afe_cmdrsp_request_lpass_resources *) payload;
+ struct afe_cmdrsp_request_lpass_dma_resources *dma_resources = NULL;
+ uint8_t *dma_channels_id_payload = NULL;
+
+ 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);
+ atomic_set(&this_afe.status, ADSP_EBADPARAM);
+ return -EINVAL;
+ }
+
+ if (resources->status != 0) {
+ pr_debug("%s: Error: Requesting LPASS resources ret %d\n",
+ __func__, resources->status);
+ atomic_set(&this_afe.status, ADSP_EBADPARAM);
+ return -EINVAL;
+ }
+
+ if (resources->resource_id == AFE_LPAIF_DMA_RESOURCE_ID) {
+ int i;
+
+ payload += sizeof(
+ struct afe_cmdrsp_request_lpass_resources);
+ dma_resources = (struct
+ afe_cmdrsp_request_lpass_dma_resources *)
+ payload;
+
+ pr_debug("%s: DMA Type allocated = %d\n",
+ __func__,
+ dma_resources->dma_type);
+
+ if (dma_resources->num_read_dma_channels > AFE_MAX_RDDMA) {
+ pr_err("%s: Allocated Read DMA %d exceeds max %d\n",
+ __func__,
+ dma_resources->num_read_dma_channels,
+ AFE_MAX_RDDMA);
+ dma_resources->num_read_dma_channels = AFE_MAX_RDDMA;
+ }
+
+ if (dma_resources->num_write_dma_channels > AFE_MAX_WRDMA) {
+ pr_err("%s: Allocated Write DMA %d exceeds max %d\n",
+ __func__,
+ dma_resources->num_write_dma_channels,
+ AFE_MAX_WRDMA);
+ dma_resources->num_write_dma_channels = AFE_MAX_WRDMA;
+ }
+
+ this_afe.num_alloced_rddma =
+ dma_resources->num_read_dma_channels;
+ this_afe.num_alloced_wrdma =
+ dma_resources->num_write_dma_channels;
+
+ pr_debug("%s: Number of allocated Read DMA channels= %d\n",
+ __func__,
+ dma_resources->num_read_dma_channels);
+ pr_debug("%s: Number of allocated Write DMA channels= %d\n",
+ __func__,
+ dma_resources->num_write_dma_channels);
+
+ payload += sizeof(
+ struct afe_cmdrsp_request_lpass_dma_resources);
+ dma_channels_id_payload = payload;
+
+ for (i = 0; i < this_afe.num_alloced_rddma; i++) {
+ pr_debug("%s: Read DMA Index %d allocated\n",
+ __func__, *dma_channels_id_payload);
+ this_afe.alloced_rddma
+ [*dma_channels_id_payload] = 1;
+ dma_channels_id_payload++;
+ }
+
+ for (i = 0; i < this_afe.num_alloced_wrdma; i++) {
+ pr_debug("%s: Write DMA Index %d allocated\n",
+ __func__, *dma_channels_id_payload);
+ this_afe.alloced_wrdma
+ [*dma_channels_id_payload] = 1;
+ dma_channels_id_payload++;
+ }
+ } else {
+ pr_err("%s: Error: Unknown resource ID %d",
+ __func__, resources->resource_id);
+ atomic_set(&this_afe.status, ADSP_EBADPARAM);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int32_t afe_callback(struct apr_client_data *data, void *priv)
{
if (!data) {
@@ -472,6 +569,15 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
return -EINVAL;
}
wake_up(&this_afe.wait[data->token]);
+ } else if (data->opcode == AFE_CMDRSP_REQUEST_LPASS_RESOURCES) {
+ uint32_t ret = 0;
+
+ ret = afe_lpass_resources_callback(data);
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait[data->token]);
+ if (!ret) {
+ return ret;
+ }
} else if (data->payload_size) {
uint32_t *payload;
uint16_t port_id = 0;
@@ -502,6 +608,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
case AFE_PORTS_CMD_DTMF_CTL:
case AFE_SVC_CMD_SET_PARAM:
case AFE_SVC_CMD_SET_PARAM_V2:
+ case AFE_CMD_REQUEST_LPASS_RESOURCES:
atomic_set(&this_afe.state, 0);
wake_up(&this_afe.wait[data->token]);
break;
@@ -541,6 +648,18 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
atomic_set(&this_afe.state, payload[1]);
wake_up(&this_afe.wait[data->token]);
break;
+ case AFE_CMD_RELEASE_LPASS_RESOURCES:
+ memset(&this_afe.alloced_rddma[0],
+ 0,
+ AFE_MAX_RDDMA);
+ memset(&this_afe.alloced_wrdma[0],
+ 0,
+ AFE_MAX_WRDMA);
+ this_afe.num_alloced_rddma = 0;
+ this_afe.num_alloced_wrdma = 0;
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait[data->token]);
+ break;
default:
pr_err("%s: Unknown cmd 0x%x\n", __func__,
payload[0]);
@@ -6598,6 +6717,173 @@ done:
return result;
}
+int afe_request_dma_resources(uint8_t dma_type, uint8_t num_read_dma_channels,
+ uint8_t num_write_dma_channels)
+{
+ int result = 0;
+ struct afe_request_lpass_dma_resources_command config;
+
+ pr_debug("%s:\n", __func__);
+
+ if (dma_type != AFE_LPAIF_DEFAULT_DMA_TYPE) {
+ pr_err("%s: DMA type %d is invalid\n",
+ __func__,
+ dma_type);
+ goto done;
+ }
+
+ if ((num_read_dma_channels == 0) &&
+ (num_write_dma_channels == 0)) {
+ pr_err("%s: DMA channels to allocate are 0\n",
+ __func__);
+ goto done;
+ }
+
+ if (num_read_dma_channels > AFE_MAX_RDDMA) {
+ pr_err("%s: Read DMA channels %d to allocate are > %d\n",
+ __func__,
+ num_read_dma_channels,
+ AFE_MAX_RDDMA);
+ goto done;
+ }
+
+ if (num_write_dma_channels > AFE_MAX_WRDMA) {
+ pr_err("%s: Write DMA channels %d to allocate are > %d\n",
+ __func__,
+ num_write_dma_channels,
+ AFE_MAX_WRDMA);
+ goto done;
+ }
+
+ result = afe_q6_interface_prepare();
+ if (result != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n",
+ __func__, result);
+ goto done;
+ }
+
+ 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 = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_CMD_REQUEST_LPASS_RESOURCES;
+ config.resources.resource_id = AFE_LPAIF_DMA_RESOURCE_ID;
+ /* Only AFE_LPAIF_DEFAULT_DMA_TYPE dma type is supported */
+ config.dma_resources.dma_type = dma_type;
+ config.dma_resources.num_read_dma_channels = num_read_dma_channels;
+ config.dma_resources.num_write_dma_channels = num_write_dma_channels;
+
+ result = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (result)
+ pr_err("%s: AFE_CMD_REQUEST_LPASS_RESOURCES failed %d\n",
+ __func__, result);
+
+done:
+ return result;
+}
+EXPORT_SYMBOL(afe_request_dma_resources);
+
+int afe_get_dma_idx(bool **ret_rddma_idx,
+ bool **ret_wrdma_idx)
+{
+ int ret = 0;
+
+ if (!ret_rddma_idx || !ret_wrdma_idx) {
+ pr_err("%s: invalid return pointers.", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ *ret_rddma_idx = &this_afe.alloced_rddma[0];
+ *ret_wrdma_idx = &this_afe.alloced_wrdma[0];
+
+done:
+ return ret;
+}
+EXPORT_SYMBOL(afe_get_dma_idx);
+
+int afe_release_all_dma_resources(void)
+{
+ int result = 0;
+ int i, total_size;
+ struct afe_release_lpass_dma_resources_command *config;
+ uint8_t *payload;
+
+ pr_debug("%s:\n", __func__);
+
+ if ((this_afe.num_alloced_rddma == 0) &&
+ (this_afe.num_alloced_wrdma == 0)) {
+ pr_err("%s: DMA channels to release is 0",
+ __func__);
+ goto done;
+ }
+
+ result = afe_q6_interface_prepare();
+ if (result != 0) {
+ pr_err("%s: Q6 interface prepare failed %d\n",
+ __func__, result);
+ goto done;
+ }
+
+ total_size = sizeof(struct afe_release_lpass_dma_resources_command) +
+ sizeof(uint8_t) *
+ (this_afe.num_alloced_rddma + this_afe.num_alloced_wrdma);
+
+ config = kzalloc(total_size, GFP_KERNEL);
+ if (!config) {
+ result = -ENOMEM;
+ goto done;
+ }
+
+ memset(config, 0, total_size);
+ payload = (uint8_t *) config +
+ sizeof(struct afe_release_lpass_dma_resources_command);
+
+ 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 = total_size;
+ config->hdr.src_port = 0;
+ config->hdr.dest_port = 0;
+ config->hdr.token = IDX_GLOBAL_CFG;
+ config->hdr.opcode = AFE_CMD_RELEASE_LPASS_RESOURCES;
+ config->resources.resource_id = AFE_LPAIF_DMA_RESOURCE_ID;
+ /* Only AFE_LPAIF_DEFAULT_DMA_TYPE dma type is supported */
+ config->dma_resources.dma_type = AFE_LPAIF_DEFAULT_DMA_TYPE;
+ config->dma_resources.num_read_dma_channels =
+ this_afe.num_alloced_rddma;
+ config->dma_resources.num_write_dma_channels =
+ this_afe.num_alloced_wrdma;
+
+ for (i = 0; i < AFE_MAX_RDDMA; i++) {
+ if (this_afe.alloced_rddma[i]) {
+ *payload = i;
+ payload++;
+ }
+ }
+
+ for (i = 0; i < AFE_MAX_WRDMA; i++) {
+ if (this_afe.alloced_wrdma[i]) {
+ *payload = i;
+ payload++;
+ }
+ }
+
+ result = afe_apr_send_pkt(config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (result)
+ pr_err("%s: AFE_CMD_RELEASE_LPASS_RESOURCES failed %d\n",
+ __func__, result);
+
+ kfree(config);
+done:
+ return result;
+}
+EXPORT_SYMBOL(afe_release_all_dma_resources);
+
static int __init afe_init(void)
{
int i = 0, ret;
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 3b745c24f90e..0062e4cd6432 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -794,6 +794,7 @@ int q6audio_validate_port(u16 port_id)
case AFE_PORT_ID_INT5_MI2S_TX:
case AFE_PORT_ID_INT6_MI2S_RX:
case AFE_PORT_ID_INT6_MI2S_TX:
+ case AFE_PORT_ID_MULTICHAN_HDMI_RX:
{
ret = 0;
break;