From 0814c5cebd418b10a24b11e22ae08a84324d0f27 Mon Sep 17 00:00:00 2001 From: Duy Dang Date: Sat, 20 Oct 2018 14:55:18 +0700 Subject: rcar-gen3: linux-renesas: Upgrade Linux BSP to v3.9.2 This commit upgrades Linux BSP to v3.9.2 for the following changes: [Kernel] - Add support for RCKSEL clock selection. - Fix pin functions of R-Car E3 according to H/W UM Rev1.00 errata. - Fix warning of the make W=1 C=2. - Identify R-Car M3 Ver.1.3. - Add the big.LITTLE CAS scheduler fix patches. - Fix MOD_SEL bit numbering for R-Car E3. [Power Management] - Fixup power-domains of 3DGE for R-Car E3 Ver.1.0 and add device tree file for R-Car E3 Ver.1.0. [Audio Driver] - Fixup clock start checker. - Resolve the problem that the noise is generated during long playback with R-Car E3 Ebisu-4D board by kernel rebasing. [Display Driver] - Add function of suspend and resume to adv7511_drv.c and add hot plug event function at resume in rcar_du_drv.c. - Add depends on DRM_RCAR_DU to config DRM_RCAR_LVDS. - Revert "drm: rcar-du: Fix legacy DT to create LVDS encoder nodes". - Add clock function for LVDS PLL. [Ethernet Driver] - Decrease TxFIFO depth of Q3 and Q2 to one. - Fix not to call phy_resume() if PHY is not attached and add toggling phy reset if PHY is not attached. - Revert "ravb: RX checksum offload" for communicating of Q-Tag VLAN frame correctly. - Resolved the problem that the S2RAM resume failed on R-Car E3 Ebisu-4D by kernel rebasing. - Avoid unsupported internal delay mode for R-Car E3 and limit to 100Mbps. [I2C Driver] - Check bus state before reinitializing. [IPMMU Driver] - Fix crash on early domain free. - Revert "arm64: defconfig: Enable QCOM_IOMMU" for suspending with LTSI kernel. - Correct whitelist devices assignment. [PCIe Driver] - Avoid PCI device removing/rescanning through sysfs triggers a deadlock. [PWM Driver] - Avoid deadlock warning when removing PWM device. [SD/MMC Driver] - Fix card initialization failure in high speed mode. - Add adjust HS400 offset by manual calibration mode and adjust HS400 offset by manual calibration mode for R-Car M3 Ver.1.3. [USB2.0 Function] - Add reset_control. - Backport upstream patches to support OTG mode for R-Car E3. - Make DMAC system sleep callbacks explicit. - Add Super-Speed (b-device) support. [Video Capture driver] - Review adv748x driver for R-Car E3 Ebisu board and add option for changing SD output route to TXA. - Revert "rcar-vin: rcar-csi2: Add blank margin when caluculating bit rate" and fix pixel rate values. - Add CPG reset and release when using digital pin. [RWDT Driver] - Don't keep timer value during suspend/resume. - Don't set divider while watchdog is running. This also updates ADSP driver patches to adapt to the new Linux version. Signed-off-by: Duy Dang Signed-off-by: Khang Nguyen Signed-off-by: Takamitsu Honda --- ...cument-for-compatible-string-renesas-rcar.patch | 32 + .../0001-Add-build-for-ADSP-sound-driver.patch | 31 - ...0001-arm64-dts-salvator-common-Rcar-Sound.patch | 83 - .../0002-ADSP-add-ADSP-sound-driver-source.patch | 7217 ++++++++++++++++++++ ...2-Add-document-file-for-ADSP-sound-driver.patch | 27 - ...dts-r8a7796-salvator-xs-Remove-Sound-Card.patch | 31 - ...0003-ADSP-add-build-for-ADSP-sound-driver.patch | 35 + .../0003-Add-ADSP-sound-driver-source.patch | 7172 ------------------- ...-dts-r8a7795-salvator-x-Remove-Sound-Card.patch | 32 - ...-integrate-ADSP-sound-for-H3-M3-M3N-board.patch | 185 + ...-Update-device-tree-for-ADSP-sound-driver.patch | 249 - ...dts-r8a7795-salvator-xs-Remove-Sound-Card.patch | 32 - ...05-ADSP-integrate-ADSP-sound-for-E3-board.patch | 272 + ...-r8a7795-es1-salvator-x-Remove-Sound-Card.patch | 31 - ...-ADSP-remove-HDMI-support-from-rcar-sound.patch | 82 + ...-dts-r8a7796-salvator-x-Remove-Sound-Card.patch | 31 - .../linux-libc-headers/linux-libc-headers_4.14.bb | 24 +- ...cument-for-compatible-string-renesas-rcar.patch | 32 + .../0001-Add-build-for-ADSP-sound-driver.patch | 31 - ...0001-arm64-dts-salvator-common-Rcar-Sound.patch | 83 - .../0002-ADSP-add-ADSP-sound-driver-source.patch | 7217 ++++++++++++++++++++ ...2-Add-document-file-for-ADSP-sound-driver.patch | 27 - ...dts-r8a7796-salvator-xs-Remove-Sound-Card.patch | 31 - ...0003-ADSP-add-build-for-ADSP-sound-driver.patch | 35 + .../0003-Add-ADSP-sound-driver-source.patch | 7172 ------------------- ...-dts-r8a7795-salvator-x-Remove-Sound-Card.patch | 32 - ...-integrate-ADSP-sound-for-H3-M3-M3N-board.patch | 185 + ...-Update-device-tree-for-ADSP-sound-driver.patch | 249 - ...dts-r8a7795-salvator-xs-Remove-Sound-Card.patch | 32 - ...05-ADSP-integrate-ADSP-sound-for-E3-board.patch | 272 + ...-r8a7795-es1-salvator-x-Remove-Sound-Card.patch | 31 - ...-ADSP-remove-HDMI-support-from-rcar-sound.patch | 82 + ...-dts-r8a7796-salvator-x-Remove-Sound-Card.patch | 31 - .../recipes-kernel/linux/linux-renesas/defconfig | 9 +- .../recipes-kernel/linux/linux-renesas_4.14.bb | 29 +- 35 files changed, 15669 insertions(+), 15477 deletions(-) create mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-Add-build-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-arm64-dts-salvator-common-Rcar-Sound.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-ADSP-add-ADSP-sound-driver-source.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-Add-document-file-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-ADSP-add-build-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-Add-ADSP-sound-driver-source.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-Update-device-tree-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-Add-build-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-arm64-dts-salvator-common-Rcar-Sound.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-ADSP-add-ADSP-sound-driver-source.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-Add-document-file-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-ADSP-add-build-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-Update-device-tree-for-ADSP-sound-driver.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch create mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch delete mode 100644 meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch (limited to 'meta-rcar-gen3') diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch new file mode 100644 index 0000000..765053f --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch @@ -0,0 +1,32 @@ +From 5f378e5db591a4a119b6cface6037cbded240506 Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Thu, 25 Oct 2018 13:25:10 +0700 +Subject: [PATCH 1/6] ADSP: add document for compatible string + "renesas,rcar_adsp_sound_gen3" + +Signed-off-by: tienphitran +--- + .../devicetree/bindings/sound/renesas,adsp.txt | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 Documentation/devicetree/bindings/sound/renesas,adsp.txt + +diff --git a/Documentation/devicetree/bindings/sound/renesas,adsp.txt b/Documentation/devicetree/bindings/sound/renesas,adsp.txt +new file mode 100644 +index 000000000000..b529bcadea82 +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/renesas,adsp.txt +@@ -0,0 +1,11 @@ ++Renesas ADSP sound driver ++ ++Required properties: ++- compatible : "renesas,rcar_adsp_sound_gen3" ++ ++Example: ++ ++rcar_adsp_sound: adsp_sound@0 { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++}; +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-Add-build-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-Add-build-for-ADSP-sound-driver.patch deleted file mode 100644 index 508600d..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-Add-build-for-ADSP-sound-driver.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 4e7d2e7b5737d9a7ffbd59ad260e6b86b2e48691 Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 17:57:56 +0700 -Subject: [PATCH 1/4] Add build for ADSP sound driver - -Signed-off-by: tienphitran - -diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig -index c0abad2..f5f6abb 100644 ---- a/sound/soc/Kconfig -+++ b/sound/soc/Kconfig -@@ -71,6 +71,7 @@ source "sound/soc/txx9/Kconfig" - source "sound/soc/ux500/Kconfig" - source "sound/soc/xtensa/Kconfig" - source "sound/soc/zte/Kconfig" -+source "sound/soc/adsp/Kconfig" - - # Supported codecs - source "sound/soc/codecs/Kconfig" -diff --git a/sound/soc/Makefile b/sound/soc/Makefile -index bf8c1e2..6e77abb 100644 ---- a/sound/soc/Makefile -+++ b/sound/soc/Makefile -@@ -52,3 +52,4 @@ obj-$(CONFIG_SND_SOC) += txx9/ - obj-$(CONFIG_SND_SOC) += ux500/ - obj-$(CONFIG_SND_SOC) += xtensa/ - obj-$(CONFIG_SND_SOC) += zte/ -+obj-$(CONFIG_SND_SOC) += adsp/ --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-arm64-dts-salvator-common-Rcar-Sound.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-arm64-dts-salvator-common-Rcar-Sound.patch deleted file mode 100644 index a7e0587..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0001-arm64-dts-salvator-common-Rcar-Sound.patch +++ /dev/null @@ -1,83 +0,0 @@ -From cda5747801eadd0f29a591bee4b36c6f1ae30a54 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:30 +0900 -Subject: [PATCH 1/6] arm64: dts: salvator-common: Rcar-Sound - -This Patch Adds Rcar_Sound - -Signed-off-by: Takeshi Kihara ---- - .../boot/dts/renesas/salvator-common.dtsi | 40 ++++++++----------- - 1 file changed, 16 insertions(+), 24 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -index 3257143e43c1..6cda02800731 100644 ---- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi -+++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -@@ -125,15 +125,21 @@ - regulator-boot-on; - regulator-always-on; - }; -+ rsnd_ak4613: sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,format = "left_j"; -+ simple-audio-card,bitclock-master = <&sndcpu>; -+ simple-audio-card,frame-master = <&sndcpu>; -+ sndcpu: simple-audio-card,cpu { -+ sound-dai = <&rcar_sound>; -+ }; - -- sound_card: sound { -- compatible = "audio-graph-card"; -- -- label = "rcar-sound"; -- -- dais = <&rsnd_port0>; -+ sndcodec: simple-audio-card,codec { -+ sound-dai = <&ak4613>; -+ }; - }; - -+ - vbus0_usb2: regulator-vbus0-usb2 { - compatible = "regulator-fixed"; - -@@ -454,12 +460,6 @@ - asahi-kasei,out4-single-end; - asahi-kasei,out5-single-end; - asahi-kasei,out6-single-end; -- -- port { -- ak4613_endpoint: endpoint { -- remote-endpoint = <&rsnd_endpoint0>; -- }; -- }; - }; - - cs2000: clk_multiplier@4f { -@@ -795,18 +795,10 @@ - <&audio_clk_c>, - <&cpg CPG_CORE CPG_AUDIO_CLK_I>; - -- ports { -- rsnd_port0: port@0 { -- rsnd_endpoint0: endpoint { -- remote-endpoint = <&ak4613_endpoint>; -- -- dai-format = "left_j"; -- bitclock-master = <&rsnd_endpoint0>; -- frame-master = <&rsnd_endpoint0>; -- -- playback = <&ssi0 &src0 &dvc0>; -- capture = <&ssi1 &src1 &dvc1>; -- }; -+ rcar_sound,dai { -+ dai0 { -+ playback = <&ssi0 &src0 &dvc0>; -+ capture = <&ssi1 &src1 &dvc1>; - }; - }; - }; --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-ADSP-add-ADSP-sound-driver-source.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-ADSP-add-ADSP-sound-driver-source.patch new file mode 100644 index 0000000..8da35f4 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-ADSP-add-ADSP-sound-driver-source.patch @@ -0,0 +1,7217 @@ +From 8fb0a86601a73224c5c0b76e3b0037a40da880fc Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Mon, 15 Oct 2018 18:00:42 +0700 +Subject: [PATCH 2/6] ADSP: add ADSP sound driver source + +Signed-off-by: tienphitran +--- + include/adsp_drv/xf-adsp-drv-ext.h | 58 + + sound/soc/adsp/Kconfig | 14 + + sound/soc/adsp/Makefile | 3 + + sound/soc/adsp/xf-adsp-alsa.c | 3936 ++++++++++++++++++++++++++++ + sound/soc/adsp/xf-adsp-base.c | 2259 ++++++++++++++++ + sound/soc/adsp/xf-adsp-base.h | 275 ++ + sound/soc/adsp/xf-adsp-config.h | 604 +++++ + 7 files changed, 7149 insertions(+) + create mode 100644 include/adsp_drv/xf-adsp-drv-ext.h + create mode 100644 sound/soc/adsp/Kconfig + create mode 100644 sound/soc/adsp/Makefile + create mode 100644 sound/soc/adsp/xf-adsp-alsa.c + create mode 100644 sound/soc/adsp/xf-adsp-base.c + create mode 100644 sound/soc/adsp/xf-adsp-base.h + create mode 100644 sound/soc/adsp/xf-adsp-config.h + +diff --git a/include/adsp_drv/xf-adsp-drv-ext.h b/include/adsp_drv/xf-adsp-drv-ext.h +new file mode 100644 +index 000000000000..6c3dbc0be1ef +--- /dev/null ++++ b/include/adsp_drv/xf-adsp-drv-ext.h +@@ -0,0 +1,58 @@ ++/***************************************************************************** ++ * \file xf-adsp-driver-ext.h ++ * \brief Header file for ADSP driver extension part ++ * \addtogroup ADSP Driver ++ ****************************************************************************** ++ * \date Oct. 21, 2017 ++ * \author Renesas Electronics Corporation ++ ****************************************************************************** ++ * \par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#ifndef __XF_ADSP_DRV_EXT_H ++#define __XF_ADSP_DRV_EXT_H ++ ++/*********************************************************** ++ * Extension client APIs ++ * ********************************************************/ ++ ++struct xf_adsp_base_cmd { ++ /* register new client for ADSP base control */ ++ int (*client_register)(void **private_data); ++ /* unregister client */ ++ int (*client_unregister)(void *private_data); ++ /* get data from proxy */ ++ int (*recv)(void *private_data, void *buf); ++ /* send data to proxy */ ++ int (*send)(void *private_data, void *buf); ++ /* wait the valid message in the response queue */ ++ int (*poll)(void *private_data, int *condition); ++}; ++ ++/* create ADSP base control data */ ++int xf_adsp_base_create(struct xf_adsp_base_cmd *cmd); ++ ++/* destroy ADSP base control data */ ++int xf_adsp_base_destroy(void); ++ ++#endif +diff --git a/sound/soc/adsp/Kconfig b/sound/soc/adsp/Kconfig +new file mode 100644 +index 000000000000..605261f0855f +--- /dev/null ++++ b/sound/soc/adsp/Kconfig +@@ -0,0 +1,14 @@ ++## SoC for ADSP driver configuration ++menu "ASoC ADSP driver" ++ ++config SND_SOC_ADSP ++ tristate "SoC Audio for R-Car ADSP" ++ select SND_SIMPLE_CARD ++ select SND_SIMPLE_SCU_CARD ++ select SND_AUDIO_GRAPH_CARD ++ select SND_AUDIO_GRAPH_SCU_CARD ++ default y ++ help ++ This option enables ALSA ADSP sound supports ADSP module ++ ++endmenu +diff --git a/sound/soc/adsp/Makefile b/sound/soc/adsp/Makefile +new file mode 100644 +index 000000000000..8277fdbc5bbe +--- /dev/null ++++ b/sound/soc/adsp/Makefile +@@ -0,0 +1,3 @@ ++## Makefile for SoC ADSP driver ++snd-soc-adsp-objs := xf-adsp-alsa.o xf-adsp-base.o ++obj-$(CONFIG_SND_SOC_ADSP) += snd-soc-adsp.o +diff --git a/sound/soc/adsp/xf-adsp-alsa.c b/sound/soc/adsp/xf-adsp-alsa.c +new file mode 100644 +index 000000000000..e602c6efcc6a +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-alsa.c +@@ -0,0 +1,3936 @@ ++/** *************************************************************************** ++ * \file xf-adsp-alsa.c ++ * \brief Source file for ADSP ALSA Driver ++ * \addtogroup ADSP Driver ++ ****************************************************************************** ++ * \date Oct. 21, 2017 ++ * \author Renesas Electronics Corporation ++ ****************************************************************************** ++ * \par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ *****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xf-adsp-base.h" ++ ++/* Name of Volume control for playback */ ++#define PLAYBACK_VOLUME_CTR_NAME "PlaybackVolume" ++ ++/* Name of Volume control for capture */ ++#define CAPTURE_VOLUME_CTR_NAME "CaptureVolume" ++ ++/* Name of Sample Rate control for playback */ ++#define PLAYBACK_OUT_RATE_CTR_NAME "PlaybackOutRate" ++ ++/* Name of Output Channel control for playback */ ++#define PLAYBACK_OUT_CHANNEL_CTR_NAME "PlaybackOutChannel" ++ ++/* Name of Sample Rate control for capture */ ++#define CAPTURE_IN_RATE_CTR_NAME "CaptureInRate" ++ ++/* Name of Equalizer parameters control for playback */ ++#define PLAYBACK_EQZ_CTR_NAME "PlaybackEQZControl" ++ ++/* Name of Equalizer parameters control for capture */ ++#define CAPTURE_EQZ_CTR_NAME "CaptureEQZControl" ++ ++/* Name of Equalizer Switch control for playback */ ++#define PLAYBACK_EQZ_SWITCH_CTR_NAME "PlaybackEQZSwitch" ++ ++/* Name of Equalizer Switch control for capture */ ++#define CAPTURE_EQZ_SWITCH_CTR_NAME "CaptureEQZSwitch" ++ ++/* Name of Volume control for TDM playback */ ++#define TDM_PLAYBACK_VOLUME_CTR_NAME "TDMPlaybackVolume" ++ ++/* Name of Volume control for TDM capture */ ++#define TDM_CAPTURE_VOLUME_CTR_NAME "TDMCaptureVolume" ++ ++/* Name of Sample Rate control for TDM playback */ ++#define TDM_PLAYBACK_OUT_RATE_CTR_NAME "TDMPlaybackOutRate" ++ ++/* Name of Sample Rate control for TDM capture */ ++#define TDM_CAPTURE_IN_RATE_CTR_NAME "TDMCaptureInRate" ++ ++/* Prefix of Playback control name */ ++#define PREFIX_OF_PLAYBACK_CTR_NAME PLAYBACK_VOLUME_CTR_NAME[0] ++ ++/* Prefix of Capture control name */ ++#define PREFIX_OF_CAPTURE_CTR_NAME CAPTURE_VOLUME_CTR_NAME[0] ++ ++/* Prefix of TDM control name */ ++#define PREFIX_OF_TDM_CTR_NAME TDM_PLAYBACK_VOLUME_CTR_NAME[0] ++ ++/* Prefix of TDM playback */ ++#define TDM_PLAYBACK TDM_PLAYBACK_VOLUME_CTR_NAME[3] ++ ++/* Prefix of TDM record */ ++#define TDM_CAPTURE TDM_CAPTURE_VOLUME_CTR_NAME[3] ++ ++/* Number of control for playback & capture */ ++#define RDR_CONTROL_NUM (9) ++ ++/* Number of controls for TDM */ ++#define TDM_CONTROL_NUM (4) ++ ++/* Indicate playback stream */ ++#define DIRECT_PLAYBACK (0) ++ ++/* Indicate capture stream */ ++#define DIRECT_CAPTURE (1) ++ ++/* Indicate stream number */ ++#define DIRECT_NUM (2) ++ ++/* Supported frame size for playback/record function in driver */ ++#define FRAME_SIZE (1024) ++ ++/* Supported frame size for TDM playback/record function in driver */ ++#define TDM_FRAME_SIZE (1024) ++ ++/* Supported sample rate in driver */ ++#define SND_ADSP_SAMPLE_RATES (SNDRV_PCM_RATE_32000 | \ ++ SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_48000) ++ ++/* Supported PCM width in driver */ ++#define SND_ADSP_PCM_WIDTHS (SNDRV_PCM_FMTBIT_S16_LE | \ ++ SNDRV_PCM_FMTBIT_S24_LE) ++ ++/* Macro to control DAI index */ ++/* DAI 0 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX0 (0) ++ ++/* DAI 1 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX1 (1) ++ ++/* DAI 2 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX2 (2) ++ ++/* DAI 3 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX3 (3) ++ ++/* DAI 4 index for playback/record functions of TDM formats */ ++#define TDM_DAI_IDX (4) ++ ++/* Maximum number of DAI supported by driver */ ++#define MAX_DAI_IDX (5) ++ ++/* Renderer/Capture software information */ ++/* Minimum channel number supported */ ++#define MIN_CHANNEL (1) ++ ++/* Maximum channel number supported */ ++#define MAX_CHANNEL (2) ++ ++/* Minimum buffer size in byte */ ++#define MIN_BUF_SIZE (FRAME_SIZE * MIN_CHANNEL * 2) ++ ++/* Maximum buffer size in byte */ ++#define MAX_BUF_SIZE (FRAME_SIZE * MAX_CHANNEL * 4) ++ ++/* Minimum numbers of period in the buffer */ ++#define MIN_PERIOD (1) ++ ++/* Maximum numbers of period in the buffer */ ++#define MAX_PERIOD (4) ++ ++/* Maximun numbers of bytes in ALSA buffer */ ++#define MAX_BUFFER_BYTES (MAX_PERIOD * MAX_BUF_SIZE) ++ ++/* TDM software information */ ++/*< Minimum channel number supported in TDM plugin */ ++#define TDM_MIN_CHANNEL (6) ++ ++/* Maximum channel number supported in TDM plugin */ ++#define TDM_MAX_CHANNEL (8) ++ ++/* Minimum buffer size in byte for TDM format */ ++#define TDM_MIN_BUF_SIZE (TDM_FRAME_SIZE * TDM_MIN_CHANNEL * 2) ++ ++/* Maximum buffer size in byte for TDM format */ ++#define TDM_MAX_BUF_SIZE (TDM_FRAME_SIZE * TDM_MAX_CHANNEL * 4) ++ ++/* Minimum numbers of period in the buffer for TDM format */ ++#define TDM_MIN_PERIOD (1) ++ ++/* Maximum numbers of period in the buffer for TDM format */ ++#define TDM_MAX_PERIOD (4) ++ ++/* Maximum numbers of bytes in ALSA buffer for TDM format */ ++#define TDM_MAX_BUFFER_BYTES (TDM_MAX_PERIOD * TDM_MAX_BUF_SIZE) ++ ++/* Volume scale used when user set */ ++#define VOLUME_SCALE (100) ++ ++/* Maximum element in Equalizer parameter control */ ++#define MAX_EQZ_PARAM_NUMBER (55) ++ ++/* Equalizer control is disabled */ ++#define EQZ_OFF (0) ++ ++/* Equalizer control is enabled */ ++#define EQZ_ON (1) ++ ++/* Component status */ ++/* Handle state is NULL */ ++#define XF_HANDLE_NULL (0) ++ ++/* Handle state is CREATED after creating handle successfully */ ++#define XF_HANDLE_CREATED BIT(0) ++ ++/* Handle state is READY after finishing handle init */ ++#define XF_HANDLE_READY BIT(1) ++ ++/* channels */ ++/* Mono stream */ ++#define MONAURAL (1) ++ ++/* Stereo stream */ ++#define STEREO (2) ++ ++/* define number of bytes in a sample of 24 bits format types */ ++/* store 24 bits data in 4 bytes LE */ ++#define FMTBIT_S24_LE_BYTES_PER_SAMPLE (4) ++ ++/* store 24 bits data in 3 bytes LE */ ++#define FMTBIT_S24_3LE_BYTES_PER_SAMPLE (3) ++ ++/* helper macro to get bytes per sample number */ ++#define BYTES_PER_SAMPLE(fmt) (FMTBIT_##fmt##_BYTES_PER_SAMPLE) ++ ++/* check component is created */ ++#define COMPONENT_IS_CREATED(n) (((n & XF_HANDLE_CREATED) != 0) ? TRUE : FALSE) ++ ++/* check component is ready */ ++#define COMPONENT_IS_READY(n) (((n & XF_HANDLE_READY) != 0) ? TRUE : FALSE) ++ ++/* indicator of stream order */ ++#define MIX_UNUSED (0) ++#define FIRST_RUN (2) ++#define SECOND_RUN (1) ++ ++/* check MIX usage */ ++#define MIX_ENABLED(mix_ctl) ((mix_ctl == SECOND_RUN) ? TRUE : FALSE) ++ ++/******************************************************************* ++ * base structures for ADSP ALSA driver ++ * ****************************************************************/ ++ ++/** \struct snd_adsp_control ++ * \brief Structure stores parameters from user ++ */ ++struct snd_adsp_control { ++ /* Volume rate for playback/record */ ++ int vol_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Volume rate for TDM playback/TDM record */ ++ int tdm_vol_rate[DIRECT_NUM]; ++ ++ /* Out sample rate with Renderer, in sample rate with Capture */ ++ int sample_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Out sample rate for TDM Renderer, in sample rate for TDM Capture */ ++ int tdm_sample_rate[DIRECT_NUM]; ++ ++ /* Output channel of playback */ ++ int rdr_out_ch[MAX_DAI_IDX - 1]; ++ ++ /* Equalizer parameters */ ++ struct xf_adsp_equalizer_params eqz_params[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Equalizer switch */ ++ int eqz_switch[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Indicator of MIX usage */ ++ int mix_usage; ++}; ++ ++/** \struct snd_adsp_base_info ++ * \brief Structure stores some base information of a stream ++ */ ++struct snd_adsp_base_info { ++ /* high resolution timer data */ ++ struct hrtimer hrtimer; ++ ++ /* kernel time value in nanosecond */ ++ ktime_t ktime; ++ ++ /* high resolution timer state */ ++ int hrt_state; ++ ++ /* target handle id of ALSA driver */ ++ int handle_id; ++ ++ /* data buffer */ ++ char *buffer[XF_BUF_POOL_SIZE]; ++ ++ /* size of each allocated data buffer */ ++ int buf_bytes; ++ ++ /* data index of buffer */ ++ int buf_idx; ++ ++ /* queue index of buffer */ ++ int buf_queue; ++ ++ /* HW index in bytes */ ++ int hw_idx; ++ ++ /* number of bytes in a period */ ++ int period_bytes; ++ ++ /* substream runtime object */ ++ struct snd_pcm_substream *substream; ++ ++ /* indirect PCM data transfer */ ++ struct snd_pcm_indirect pcm_indirect; ++ ++ /* spinlock data */ ++ spinlock_t lock; ++ ++ /* runtime error indicator */ ++ int runtime_err; ++}; ++ ++/** \struct snd_adsp_playback ++ * \brief Structure stores data for playback function ++ */ ++struct snd_adsp_playback { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* Renderer component data */ ++ struct xf_adsp_renderer *renderer; ++ ++ /* Equalizer component data */ ++ struct xf_adsp_equalizer *equalizer; ++ ++ /* Renderer component state */ ++ int rdr_state; ++ ++ /* Equalizer component state */ ++ int eqz_state; ++}; ++ ++/** \struct snd_adsp_record ++ * \brief Structure stores data for record function ++ */ ++struct snd_adsp_record { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* Capture component data */ ++ struct xf_adsp_capture *capture; ++ ++ /* Equalizer component data */ ++ struct xf_adsp_equalizer *equalizer; ++ ++ /* Capture component state */ ++ int cap_state; ++ ++ /* Equalizer component state */ ++ int eqz_state; ++}; ++ ++/** \struct snd_adsp_tdm_playback ++ * \brief Structure stores data for TDM playback function ++ */ ++struct snd_adsp_tdm_playback { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* TDM Renderer component data */ ++ struct xf_adsp_tdm_renderer *tdm_renderer; ++ ++ /* TDM Renderer component state */ ++ int state; ++}; ++ ++/** \struct snd_adsp_tdm_record ++ * \brief Structure stores data for TDM record function ++ */ ++struct snd_adsp_tdm_record { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* TDM Capture component data */ ++ struct xf_adsp_tdm_capture *tdm_capture; ++ ++ /* TDM Capture component state */ ++ int state; ++}; ++ ++/** \struct snd_adsp_card ++ * \brief Structure stores data for ALSA sound card ++ */ ++struct snd_adsp_card { ++ /* playback data */ ++ struct snd_adsp_playback *playback[MAX_DAI_IDX - 1]; ++ ++ /* record data */ ++ struct snd_adsp_record *record[MAX_DAI_IDX - 1]; ++ ++ /* TDM playback data */ ++ struct snd_adsp_tdm_playback *tdm_playback; ++ ++ /* TDM record data */ ++ struct snd_adsp_tdm_record *tdm_record; ++ ++ /* Structure contains params information for control */ ++ struct snd_adsp_control ctr_if; ++}; ++ ++/** HW configuration of ALSA ADSP card for Renderer/Capture */ ++static struct snd_pcm_hardware snd_pcm_adsp_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ ++ | SNDRV_PCM_INFO_RESUME ++ | SNDRV_PCM_INFO_BLOCK_TRANSFER ++ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SND_ADSP_PCM_WIDTHS, ++ .rates = SND_ADSP_SAMPLE_RATES, ++ .rate_min = 32000, ++ .rate_max = 48000, ++ .channels_min = MIN_CHANNEL, ++ .channels_max = MAX_CHANNEL, ++ ++ /* maximum buffer size in bytes */ ++ .buffer_bytes_max = MAX_BUFFER_BYTES, ++ ++ /* minimum size of the periods (frame) in bytes */ ++ .period_bytes_min = MIN_BUF_SIZE, ++ ++ /* maximum size of the periods (frame) in bytes */ ++ .period_bytes_max = MAX_BUF_SIZE, ++ ++ /* minimum periods (frames) in a buffer */ ++ .periods_min = MIN_PERIOD, ++ ++ /* maximum periods (frames) in a buffer */ ++ .periods_max = MAX_PERIOD, ++}; ++ ++/* HW configuration of ALSA ADSP card for TDM */ ++static struct snd_pcm_hardware snd_pcm_adsp_tdm_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ ++ | SNDRV_PCM_INFO_RESUME ++ | SNDRV_PCM_INFO_BLOCK_TRANSFER ++ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SND_ADSP_PCM_WIDTHS, ++ .rates = SND_ADSP_SAMPLE_RATES, ++ .rate_min = 32000, ++ .rate_max = 48000, ++ .channels_min = TDM_MIN_CHANNEL, ++ .channels_max = TDM_MAX_CHANNEL, ++ ++ /* maximum buffer size in bytes */ ++ .buffer_bytes_max = TDM_MAX_BUFFER_BYTES, ++ ++ /* minimum size of the periods (frame) in bytes */ ++ .period_bytes_min = TDM_MIN_BUF_SIZE, ++ ++ /* maximum size of the periods (frame) in bytes */ ++ .period_bytes_max = TDM_MAX_BUF_SIZE, ++ ++ /* minimum periods (frames) in a buffer */ ++ .periods_min = TDM_MIN_PERIOD, ++ ++ /* maximum periods (frames) in a buffer */ ++ .periods_max = TDM_MAX_PERIOD, ++}; ++ ++/******************************************************************* ++ * function declaration ++ * ****************************************************************/ ++ ++static int ++snd_adsp_rdr_empty_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_rdr_fill_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_cap_empty_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_cap_fill_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_get_dai_id_from_substream(struct snd_pcm_substream *substream); ++static void * ++snd_adsp_get_drvdata_from_substream(struct snd_pcm_substream *substream); ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_substream(struct snd_pcm_substream *substream); ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_hrt(struct hrtimer *hrt); ++static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt); ++static int snd_adsp_playback_init(struct snd_adsp_playback **data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_record_init(struct snd_adsp_record **data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_record_prepare(struct snd_adsp_record *record, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback); ++static int snd_adsp_record_deinit(struct snd_adsp_record *record); ++static int snd_adsp_tdm_playback_init(struct snd_adsp_tdm_playback **data, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_tdm_record_init(struct snd_adsp_tdm_record **data, ++ struct snd_pcm_substream *substream); ++static int ++snd_adsp_tdm_playback_prepare(struct snd_adsp_tdm_playback *tdm_playback, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_tdm_record_prepare(struct snd_adsp_tdm_record *tdm_record, ++ struct snd_pcm_substream *substream); ++static int ++snd_adsp_tdm_playback_deinit(struct snd_adsp_tdm_playback *tdm_playback); ++static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record); ++static int snd_adsp_pcm_open(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_close(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params); ++static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx); ++static snd_pcm_uframes_t ++snd_adsp_pcm_pointer(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream); ++static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, size_t bytes); ++static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int ++snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int ++snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static void snd_adsp_get_eqz_params_from_control( ++ struct xf_adsp_equalizer_params *eqz_params, ++ struct xf_adsp_equalizer_params *eqz_ctr_params, ++ bool flag); ++static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime); ++static int snd_adsp_probe(struct platform_device *pdev); ++static int snd_adsp_remove(struct platform_device *pdev); ++ ++/******************************************************************* ++ * callback function of ADSP control interface ++ * ****************************************************************/ ++/** ************************************************************************** ++ * \brief event handler callback to notify error from ADSP ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_event_handler(void *data) ++{ ++ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; ++ ++ if (base) ++ base->runtime_err = TRUE; ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief empty buf done callback for playback/TDM playback functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_rdr_empty_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; ++ ++ if (base) { ++ spin_lock(&base->lock); ++ ++ base->buf_queue++; ++ base->hw_idx += length; /* increase the DMA buffer index */ ++ ++ spin_unlock(&base->lock); ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief fill buf done callback for playback/TDM playback functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_rdr_fill_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief empty buf done callback for record/TDM record functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_cap_empty_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief fill buf done callback for record/TDM record functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_cap_fill_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; ++ ++ if (base) { ++ spin_lock(&base->lock); ++ ++ base->buf_queue++; ++ base->hw_idx += length; /* increase the DMA buffer index */ ++ ++ spin_unlock(&base->lock); ++ } ++ ++ return 0; ++} ++ ++/** callback functions for playback/TDM playback */ ++static struct xf_callback_func rdr_callbacks = /* PRQA S 3218 */ ++{ ++ .empty_buf_done = &snd_adsp_rdr_empty_buf_done, /* PRQA S 1053 2 */ ++ .fill_buf_done = &snd_adsp_rdr_fill_buf_done, ++ .event_handler = &snd_adsp_event_handler ++}; ++ ++/** callback functions for record/TDM record */ ++static struct xf_callback_func cap_callbacks = /* PRQA S 3218 */ ++{ ++ .empty_buf_done = &snd_adsp_cap_empty_buf_done, /* PRQA S 1053 2 */ ++ .fill_buf_done = &snd_adsp_cap_fill_buf_done, ++ .event_handler = &snd_adsp_event_handler ++}; ++ ++/******************************************************************* ++ * helper functions to get some internal data ++ * ****************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Get current index of CPU DAI from runtime data of substream ++ * ++ * \param[in] substream Pointer to PCM stream data ++ * \retval id Index of current CPU DAI ++ *****************************************************************************/ ++static int ++snd_adsp_get_dai_id_from_substream(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd; ++ ++ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; ++ return rtd->cpu_dai->id; ++} ++ ++/** ************************************************************************** ++ * \brief Get ADSP ALSA driver's data from runtime data of substream ++ * ++ * \param[in] substream Pointer to PCM stream data ++ * \retval pointer Pointer to driver's data ++ *****************************************************************************/ ++static void * ++snd_adsp_get_drvdata_from_substream(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd; ++ ++ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; ++ return snd_soc_dai_get_drvdata(rtd->cpu_dai); ++} ++ ++/** ************************************************************************** ++ * \brief Get base's data of playback/record from runtime data of substream ++ * ++ * \param[in] substream Pointer to PCM stream data ++ * \retval pointer Pointer to playback/record's base data ++ *****************************************************************************/ ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_substream(struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ struct snd_adsp_base_info *base; ++ int dai_idx; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ ++ /* get DAI index of substream */ ++ dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ ++ /* get base data of the substream */ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ base = !adsp_card->playback[dai_idx] ? ++ NULL : &adsp_card->playback[dai_idx]->base; ++ } else { ++ base = !adsp_card->record[dai_idx] ? ++ NULL : &adsp_card->record[dai_idx]->base; ++ } ++ } else { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ base = !adsp_card->tdm_playback ? ++ NULL : &adsp_card->tdm_playback->base; ++ } else { ++ base = !adsp_card->tdm_record ? ++ NULL : &adsp_card->tdm_record->base; ++ } ++ } ++ ++ return base; ++} ++ ++/** *************************************************************************** ++ * \brief Get playback/record/TDM playback/TDM record's base data ++ * from hr timer data ++ * ++ * \param[in] hrt Pointer to hr timer data ++ * \retval pointer Pointer to playback/record's base data ++ *****************************************************************************/ ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_hrt(struct hrtimer *hrt) ++{ ++ return (struct snd_adsp_base_info *)hrt; ++} ++ ++/***************************************************************************** ++ * hrtimer interrupt function ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Interrupt function of high resolution timer ++ * ++ * \param[in] hrt Pointer to hr timer data ++ * \retval HRTIMER_RESTART Restart the timer after expire time ++ *****************************************************************************/ ++static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt) ++{ ++ struct snd_adsp_base_info *base = snd_adsp_get_base_from_hrt(hrt); ++ ++ spin_lock(&base->lock); ++ if (base->hw_idx != 0) { ++ spin_unlock(&base->lock); ++ /* update PCM status for the next period */ ++ snd_pcm_period_elapsed(base->substream); ++ } else { ++ spin_unlock(&base->lock); ++ } ++ ++ hrtimer_forward_now(hrt, base->ktime); ++ ++ return HRTIMER_RESTART; ++} ++ ++/***************************************************************************** ++ * internal functions to manage playback and record functions ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Initialize playback data ++ * ++ * \param[out] playback_data Pointer to store playback data ++ * \param[in] eqz_flag Flag to indicate equalizer usage ++ * \param[in] substream Pointer to substream data ++ * \retval EINVAL Failed to initialize playback data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_playback_init(struct snd_adsp_playback **playback_data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_playback *playback; ++ ++ /* allocate memory for playback data */ ++ playback = kmalloc(sizeof(*playback), GFP_KERNEL); ++ if (!playback) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(playback, 0, sizeof(struct snd_adsp_playback)); ++ ++ /* save the playback data */ ++ *playback_data = playback; ++ ++ /* set handle state as NULL state */ ++ playback->rdr_state = XF_HANDLE_NULL; ++ playback->eqz_state = XF_HANDLE_NULL; ++ playback->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register renderer component */ ++ if (xf_adsp_renderer_create(&playback->renderer, ++ &rdr_callbacks, ++ (void *)&playback->base) < 0) ++ return -EINVAL; ++ ++ /* mark renderer component created */ ++ playback->rdr_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as renderer ID */ ++ playback->base.handle_id = playback->renderer->handle_id; ++ ++ if (eqz_flag == EQZ_ON) { ++ /* create equalizer component when equalizer is used */ ++ if (xf_adsp_equalizer_create(&playback->equalizer, ++ &rdr_callbacks, ++ (void *)&playback->base) < 0) ++ return -EINVAL; ++ ++ /* mark equalizer component created */ ++ playback->eqz_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as equalizer ID */ ++ playback->base.handle_id = playback->equalizer->handle_id; ++ } ++ ++ /* init lock */ ++ spin_lock_init(&playback->base.lock); ++ ++ /* save the substream data */ ++ playback->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&playback->base.hrtimer, ++ CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ playback->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ playback->base.hrt_state = XF_HANDLE_CREATED; ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Initialize record data ++ * ++ * \param[out] record_data Pointer to store record data ++ * \param[in] eqz_flag Flag to indicate equalizer usage ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to initialize record data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_record_init(struct snd_adsp_record **record_data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_record *record; ++ ++ /* allocate memory for record data */ ++ record = kmalloc(sizeof(*record), GFP_KERNEL); ++ if (!record) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(record, 0, sizeof(struct snd_adsp_record)); ++ ++ /* save the record data */ ++ *record_data = record; ++ ++ /* set handle state as NULL state */ ++ record->cap_state = XF_HANDLE_NULL; ++ record->eqz_state = XF_HANDLE_NULL; ++ record->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register capture component */ ++ if (xf_adsp_capture_create(&record->capture, ++ &cap_callbacks, ++ (void *)&record->base) < 0) ++ return -EINVAL; ++ ++ /* mark capture component created */ ++ record->cap_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as capture ID */ ++ record->base.handle_id = record->capture->handle_id; ++ ++ /* create equalizer component in case of it being used */ ++ if (eqz_flag == EQZ_ON) { ++ if (xf_adsp_equalizer_create(&record->equalizer, ++ &cap_callbacks, ++ (void *)&record->base) < 0) ++ return -EINVAL; ++ ++ /* mark equalizer component created */ ++ record->eqz_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as equalizer ID */ ++ record->base.handle_id = record->equalizer->handle_id; ++ } ++ ++ /* init lock */ ++ spin_lock_init(&record->base.lock); ++ ++ /* save the substream data */ ++ record->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&record->base.hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ record->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ record->base.hrt_state = XF_HANDLE_CREATED; ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare playback function ++ * ++ * \param[out] playback Pointer to playback data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, hw_buffer_size; ++ int out_rate; ++ struct snd_adsp_control *ctr_if; ++ struct snd_pcm_runtime *runtime; ++ struct xf_adsp_renderer *renderer; ++ struct xf_adsp_equalizer *equalizer; ++ struct snd_adsp_base_info *base; ++ int i; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ runtime = substream->runtime; ++ renderer = playback->renderer; ++ equalizer = playback->equalizer; ++ base = &playback->base; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ ch = runtime->channels; ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ vol_rate = ctr_if->vol_rate[DIRECT_PLAYBACK][dai_idx]; ++ out_rate = ctr_if->sample_rate[DIRECT_PLAYBACK][dai_idx]; ++ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ ++ if (pcm_width == 16) ++ base->buf_bytes = base->period_bytes; ++ else ++ base->buf_bytes = (base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = hw_buffer_size; ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ /* it should equal to a period size in bytes */ ++ base->pcm_indirect.hw_queue_size = base->period_bytes; ++ ++ /* set parameters when Renderer is not ready */ ++ if (COMPONENT_IS_READY(playback->rdr_state) == FALSE) { ++ struct xf_adsp_renderer_params *params = &renderer->params; ++ ++ /* apply renderer parameters */ ++ params->in_rate = fs; ++ params->channel = ch; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ if (ctr_if->mix_usage == SECOND_RUN) ++ params->mix_ctrl = ctr_if->mix_usage; ++ else ++ params->mix_ctrl = MIX_UNUSED; ++ ++ /* set flow as ADSP->PDMA0->SRC0->PDMA1->SSI0 */ ++ params->dev1 = SRC0; ++ params->dev2 = SSI00; ++ params->dma1 = PDMA_CH00; ++ params->dma2 = PDMA_CH01; ++ ++ /* when MIX is enabled, change to DMAC transfer type to save */ ++ /* hw FIFO */ ++ if (MIX_ENABLED(params->mix_ctrl) == TRUE) ++ params->dma1 = ADMAC_CH01; ++ ++ /* set volume rate if it is set by user or default value */ ++ /* is 100% */ ++ if (vol_rate >= 0) ++ params->vol_rate = vol_rate; ++ else ++ params->vol_rate = (1 << 20); ++ ++ /* set output channel if it is set by user */ ++ if (ctr_if->rdr_out_ch[dai_idx] >= MONAURAL) ++ params->out_channel = ctr_if->rdr_out_ch[dai_idx]; ++ else ++ params->out_channel = params->channel; ++ ++ /* set sample rate output if it is set by user */ ++ if (out_rate >= 0) ++ params->out_rate = out_rate; ++ ++ /* set parameters to ADSP Renderer plugin */ ++ if (xf_adsp_renderer_set_params(renderer) != 0) ++ return -EINVAL; ++ ++ /* allocate buffer pool to prepare the execution */ ++ renderer->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(renderer->buf_pool)) /* PRQA S 306*/ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ renderer->buf_pool, i); ++ ++ base->buf_queue++; ++ memset(base->buffer[i], 0, base->buf_bytes); ++ } ++ ++ /* mark Renderer ready */ ++ playback->rdr_state |= XF_HANDLE_READY; ++ ++ /* set parameters for Equalizer if it is used */ ++ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { ++ /* apply Equalizer parameter setting */ ++ equalizer->params.channel = ch; ++ equalizer->params.pcm_width = pcm_width; ++ equalizer->params.rate = fs; ++ ++ /* get equalizer parameters from control interface */ ++ /* data */ ++ snd_adsp_get_eqz_params_from_control( ++ &equalizer->params, ++ &ctr_if->eqz_params[DIRECT_PLAYBACK][dai_idx], ++ true); ++ ++ /* set parameters to Equalizer plugin */ ++ if (xf_adsp_equalizer_set_params(equalizer) != 0) ++ return -EINVAL; ++ ++ /* route Equalizer to Renderer */ ++ if (xf_adsp_route(equalizer->handle_id, ++ renderer->handle_id, ++ XF_BUF_POOL_SIZE, ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ /* mark Equalizer ready */ ++ playback->eqz_state |= XF_HANDLE_READY; ++ ++ /* prepare data before start PCM */ ++ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ /* send buffer to plugin to kick */ ++ /* init-processing */ ++ if (xf_adsp_empty_this_buffer( ++ base->handle_id, ++ base->buffer[i], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ } ++ } else { ++ /* send zero buffer to plugin to kick */ ++ /* init-processing */ ++ if (xf_adsp_empty_this_buffer(base->handle_id, ++ base->buffer[0], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ } ++ ++ /* wait until all the buffer have been consummed */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ /* reset HW index */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare record function ++ * ++ * \param[out] record Pointer to record data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_record_prepare(struct snd_adsp_record *record, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, in_rate; ++ int hw_buffer_size, hw_queue_size; ++ struct snd_adsp_control *ctr_if; ++ struct snd_pcm_runtime *runtime; ++ struct xf_adsp_capture *capture; ++ struct xf_adsp_equalizer *equalizer; ++ struct snd_adsp_base_info *base; ++ int i; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ runtime = substream->runtime; ++ capture = record->capture; ++ equalizer = record->equalizer; ++ base = &record->base; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ ch = runtime->channels; ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ vol_rate = ctr_if->vol_rate[DIRECT_CAPTURE][dai_idx]; ++ in_rate = ctr_if->sample_rate[DIRECT_CAPTURE][dai_idx]; ++ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ /* total size of allocated buffers */ ++ hw_queue_size = base->period_bytes * XF_BUF_POOL_SIZE; ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ ++ if (pcm_width == 16) ++ base->buf_bytes = base->period_bytes; ++ else ++ base->buf_bytes = ((base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = hw_buffer_size; ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ base->pcm_indirect.hw_queue_size = hw_queue_size; ++ ++ /* prepare parameters to set to Capture plugin when it is not yet */ ++ /* ready */ ++ if (COMPONENT_IS_READY(record->cap_state) == FALSE) { ++ struct xf_adsp_capture_params *params = &capture->params; ++ ++ /* apply capture parameters */ ++ params->out_rate = fs; ++ params->channel = ch; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ params->dev1 = SRC0; ++ params->dev2 = SSI10; ++ params->dma1 = PDMA_CH00; ++ params->dma2 = PDMA_CH01; ++ ++ /* set volume rate if it is set by user or default volume as */ ++ /* 100% */ ++ if (vol_rate >= 0) ++ params->vol_rate = vol_rate; ++ else ++ params->vol_rate = (1 << 20); ++ ++ /* set sample rate input if it is set by user */ ++ if (in_rate >= 0) ++ params->in_rate = in_rate; ++ ++ /* allocate buffer pool to prepare the execution */ ++ capture->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(capture->buf_pool)) /* PRQA S 306 */ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ capture->buf_pool, i); ++ ++ base->buf_queue++; ++ } ++ ++ /* set parameters to ADSP Capture plugin */ ++ if (xf_adsp_capture_set_params(capture) != 0) ++ return -EINVAL; ++ ++ /* mark Capture ready */ ++ record->cap_state |= XF_HANDLE_READY; ++ ++ /* set parameters for Equalizer if it's used */ ++ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { ++ /* apply Equalizer parameter setting */ ++ equalizer->params.channel = ch; ++ equalizer->params.pcm_width = pcm_width; ++ equalizer->params.rate = fs; ++ ++ /* get equalizer parameter from control interface */ ++ /* data */ ++ snd_adsp_get_eqz_params_from_control( ++ &equalizer->params, ++ &ctr_if->eqz_params[DIRECT_CAPTURE][dai_idx], ++ true); ++ ++ /* set parameters to Equalizer plugin */ ++ if (xf_adsp_equalizer_set_params(equalizer) != 0) ++ return -EINVAL; ++ ++ /* route Capture to Equalizer */ ++ if (xf_adsp_route(capture->handle_id, ++ equalizer->handle_id, ++ XF_BUF_POOL_SIZE, ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ /* mark Equalizer ready */ ++ record->eqz_state |= XF_HANDLE_READY; ++ } ++ ++ /* kick init process by sending a zero buffer length */ ++ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* wait until finishing initialization */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { ++ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ /* send buffer to plugin */ ++ if (xf_adsp_fill_this_buffer( ++ base->handle_id, ++ base->buffer[i], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ } ++ ++ /* wait until all the buffer have been responsed */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ } ++ ++ /* reset hw data position */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize playback function ++ * ++ * \param[out] playback Pointer to playback data ++ * \retval -EINVAL Failed to deinitialize playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if playback has been created already */ ++ if (playback) { ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(playback->rdr_state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process *//* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(playback->base.handle_id, ++ NULL, 0); ++ ++ /* free buffer pool */ /* PRQA S 3200 1 */ ++ xf_adsp_free_mem_pool(playback->renderer->buf_pool); ++ ++ /* destroy Renderer */ ++ if (xf_adsp_renderer_destroy(playback->renderer) != 0) ++ ret = -EINVAL; ++ ++ playback->renderer = NULL; ++ } ++ ++ /* destroy Equalizer if it is used */ ++ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { ++ if (xf_adsp_equalizer_destroy(playback->equalizer)) ++ ret = -EINVAL; ++ ++ playback->equalizer = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(playback->base.hrt_state) == TRUE) ++ hrtimer_cancel(&playback->base.hrtimer); ++ ++ /* free playback data */ ++ kfree(playback); ++ } ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize record function ++ * ++ * \param[out] record Pointer to record data ++ * \retval -EINVAL Failed to deinitialize record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_record_deinit(struct snd_adsp_record *record) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if record has been created already */ ++ if (!record) ++ return ret; ++ ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(record->cap_state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process *//* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(record->base.handle_id, NULL, 0); ++ ++ /* free buffer pool */ /* PRQA S 3200 1 */ ++ xf_adsp_free_mem_pool(record->capture->buf_pool); ++ ++ if (xf_adsp_capture_destroy(record->capture)) ++ ret = -EINVAL; ++ ++ record->capture = NULL; ++ } ++ ++ /* destroy Equalizer if it is used */ ++ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { ++ if (xf_adsp_equalizer_destroy(record->equalizer) != 0) ++ ret = -EINVAL; ++ ++ record->equalizer = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(record->base.hrt_state) == TRUE) ++ hrtimer_cancel(&record->base.hrtimer); ++ ++ /* free record data */ ++ kfree(record); ++ ++ return ret; ++} ++ ++/***************************************************************************** ++ * internal functions to manage TDM playback and TDM record functions ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Initialize TDM playback data ++ * ++ * \param[out] tdm_playback_data Pointer to store TDM playback data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to initialize TDM playback data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_playback_init(struct snd_adsp_tdm_playback **tdm_playback_data, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_tdm_playback *tdm_playback; ++ ++ /* allocate memory for TDM playback data */ ++ tdm_playback = kmalloc(sizeof(*tdm_playback), GFP_KERNEL); ++ ++ if (!tdm_playback) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(tdm_playback, 0, sizeof(struct snd_adsp_tdm_playback)); ++ ++ /* save the TDM playback data */ ++ *tdm_playback_data = tdm_playback; ++ ++ /* set handle state as NULL state */ ++ tdm_playback->state = XF_HANDLE_NULL; ++ tdm_playback->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register TDM renderer component */ ++ if (xf_adsp_tdm_renderer_create(&tdm_playback->tdm_renderer, ++ &rdr_callbacks, ++ (void *)&tdm_playback->base) < 0) ++ return -EINVAL; ++ ++ /* mark TDM renderer component created */ ++ tdm_playback->state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as TDM renderer ID */ ++ tdm_playback->base.handle_id = tdm_playback->tdm_renderer->handle_id; ++ ++ /* init lock */ ++ spin_lock_init(&tdm_playback->base.lock); ++ ++ /* save the substream data */ ++ tdm_playback->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&tdm_playback->base.hrtimer, ++ CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ tdm_playback->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ tdm_playback->base.hrt_state = XF_HANDLE_CREATED; ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Initialize TDM record data ++ * ++ * \param[out] tdm_record_data Pointer to store TDM record data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to initialize TDM record data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_record_init(struct snd_adsp_tdm_record **tdm_record_data, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_tdm_record *tdm_record; ++ ++ /* allocate memory for TDM record data */ ++ tdm_record = kmalloc(sizeof(*tdm_record), GFP_KERNEL); ++ if (!tdm_record) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(tdm_record, 0, sizeof(struct snd_adsp_tdm_record)); ++ ++ /* save the TDM record data */ ++ *tdm_record_data = tdm_record; ++ ++ /* set handle state as NULL state */ ++ tdm_record->state = XF_HANDLE_NULL; ++ tdm_record->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register TDM Capture component */ ++ if (xf_adsp_tdm_capture_create(&tdm_record->tdm_capture, ++ &cap_callbacks, ++ (void *)&tdm_record->base) != 0) ++ return -EINVAL; ++ ++ /* mark TDM capture component created */ ++ tdm_record->state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as TDM capture ID */ ++ tdm_record->base.handle_id = tdm_record->tdm_capture->handle_id; ++ ++ /* init lock */ ++ spin_lock_init(&tdm_record->base.lock); ++ ++ /* save the substream data */ ++ tdm_record->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&tdm_record->base.hrtimer, ++ CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ tdm_record->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ tdm_record->base.hrt_state = XF_HANDLE_CREATED; ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare TDM playback function ++ * ++ * \param[out] tdm_playback Pointer to TDM playback data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare TDM playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_playback_prepare(struct snd_adsp_tdm_playback *tdm_playback, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ struct snd_adsp_control *ctr_if; ++ struct snd_pcm_runtime *runtime; ++ struct xf_adsp_tdm_renderer *tdm_renderer; ++ struct snd_adsp_base_info *base; ++ int i; ++ int pcm_width, ch_mode, fs, frame_size, hw_buffer_size; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ runtime = substream->runtime; ++ tdm_renderer = tdm_playback->tdm_renderer; ++ base = &tdm_playback->base; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ ++ ch_mode = (runtime->channels == 8) ? ++ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; ++ ++ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ ++ if (pcm_width == 16) ++ base->buf_bytes = base->period_bytes; ++ else ++ base->buf_bytes = ((base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = hw_buffer_size; ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ /* it should equal to a period size in bytes */ ++ base->pcm_indirect.hw_queue_size = base->period_bytes; ++ ++ /* prepare parameters to set to TDM playback as it is not ready */ ++ if (COMPONENT_IS_READY(tdm_playback->state) == FALSE) { ++ struct xf_adsp_tdm_renderer_params *params; ++ ++ params = &tdm_renderer->params; ++ ++ /* apply renderer parameters */ ++ params->in_rate = fs; ++ params->ch_mode = ch_mode; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ /* setting Audio device indexes */ ++ params->dma1 = ADMAC_CH00; /* use DMAC for transfer data */ ++ params->dma2 = PDMA_CH03; ++ params->dev1 = SRC1; ++ params->dev2 = SSI30; /* set SSI index to SSI30 */ ++ ++ /* set volume rate if it is set by user or default value as */ ++ /* 100% */ ++ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] >= 0) ++ ? ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] : (1 << 20); ++ ++ /* set output sampling rate if it is set by user */ ++ if (ctr_if->tdm_sample_rate[DIRECT_PLAYBACK] >= 0) ++ params->out_rate = ++ ctr_if->tdm_sample_rate[DIRECT_PLAYBACK]; ++ ++ /* set parameters to ADSP TDM Renderer plugin */ ++ if (xf_adsp_tdm_renderer_set_params(tdm_renderer) != 0) ++ return -EINVAL; ++ ++ /* allocate buffer pool to prepare the execution */ ++ tdm_renderer->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(tdm_renderer->buf_pool)) /* PRQA S 306*/ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ tdm_renderer->buf_pool, i); ++ ++ base->buf_queue++; ++ } ++ ++ /* mark TDM Renderer created */ ++ tdm_playback->state |= XF_HANDLE_READY; ++ ++ /* send zero buffer to plugin to kick init-processing */ ++ memset(base->buffer[0], 0, base->buf_bytes); ++ ++ if (xf_adsp_empty_this_buffer(base->handle_id, base->buffer[0], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* wait until all the buffer have been consummed */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ /* reset HW index */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare TDM record function ++ * ++ * \param[out] tdm_record Pointer to TDM record data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare TDM record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_tdm_record_prepare(struct snd_adsp_tdm_record *tdm_record, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card = ++ snd_adsp_get_drvdata_from_substream(substream); ++ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct xf_adsp_tdm_capture *tdm_capture = tdm_record->tdm_capture; ++ struct snd_adsp_base_info *base = &tdm_record->base; ++ int i; ++ int pcm_width, ch_mode, fs, frame_size; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ ++ ch_mode = (runtime->channels == 8) ? ++ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; ++ ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ base->buf_bytes = (pcm_width == 16) ? ++ base->period_bytes : ((base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / ++ BYTES_PER_SAMPLE(S24_LE)); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ /* total size of allocated buffers */ ++ base->pcm_indirect.hw_queue_size = base->period_bytes * ++ XF_BUF_POOL_SIZE; ++ ++ /* prepare parameters to set to TDM Capture as it is not yet ready */ ++ if (COMPONENT_IS_READY(tdm_record->state) == FALSE) { ++ struct xf_adsp_tdm_capture_params *params; ++ ++ params = &tdm_capture->params; ++ ++ /* apply capture parameters */ ++ params->out_rate = fs; ++ params->ch_mode = ch_mode; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ /* setting Audio device indexes */ ++ params->dma1 = PDMA_CH00; ++ params->dma2 = PDMA_CH01; ++ params->dev1 = SRC0; ++ params->dev2 = SSI40; /* set input device is SSI40 */ ++ ++ /* set volume rate if it is set by user or default value as */ ++ /* 100% */ ++ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_CAPTURE] >= 0) ++ ? ctr_if->tdm_vol_rate[DIRECT_CAPTURE] : (1 << 20); ++ ++ /* set input rate if it is set by user */ ++ if (ctr_if->tdm_sample_rate[DIRECT_CAPTURE] >= 0) { ++ params->in_rate = ++ ctr_if->tdm_sample_rate[DIRECT_CAPTURE]; ++ } ++ ++ /* allocate buffer pool to prepare the execution */ ++ tdm_capture->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(tdm_capture->buf_pool)) /* PRQA S 306 */ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ tdm_capture->buf_pool, i); ++ ++ base->buf_queue++; ++ } ++ ++ /* set parameters to ADSP TDM Capture plugin */ ++ if (xf_adsp_tdm_capture_set_params(tdm_capture) != 0) ++ return -EINVAL; ++ ++ /* mark TDM Capture ready */ ++ tdm_record->state |= XF_HANDLE_READY; ++ ++ /* kick init process by sending a zero buffer length */ ++ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* wait until finishing initialization */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ /* reset hw data position */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize TDM playback function ++ * ++ * \param[out] tdm_playback Pointer to TDM playback data ++ * \retval -EINVAL Failed to deinitialize TDM playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_playback_deinit(struct snd_adsp_tdm_playback *tdm_playback) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if TDM playback has been created */ ++ if (!tdm_playback) ++ return ret; ++ ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(tdm_playback->state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process */ ++ /* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(tdm_playback->base.handle_id, ++ NULL, 0); ++ ++ /* free buffer pool *//* PRQA S 3200 2 */ ++ xf_adsp_free_mem_pool(tdm_playback->tdm_renderer->buf_pool); ++ ++ /* destroy TDM Renderer component */ ++ if (xf_adsp_tdm_renderer_destroy( ++ tdm_playback->tdm_renderer) != 0) ++ ret = -EINVAL; ++ ++ tdm_playback->tdm_renderer = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(tdm_playback->base.hrt_state) == TRUE) ++ hrtimer_cancel(&tdm_playback->base.hrtimer); ++ ++ /* free playback data */ ++ kfree(tdm_playback); ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize TDM record function ++ * ++ * \param[out] tdm_record Pointer to TDM record data ++ * \retval -EINVAL Failed to deinitialize TDM record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if TDM record has been created already */ ++ if (!tdm_record) ++ return ret; ++ ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(tdm_record->state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process */ ++ /* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(tdm_record->base.handle_id, NULL, 0); ++ ++ /* free buffer pool *//* PRQA S 3200 2 */ ++ xf_adsp_free_mem_pool(tdm_record->tdm_capture->buf_pool); ++ ++ /* destroy TDM Capture component */ ++ if (xf_adsp_tdm_capture_destroy(tdm_record->tdm_capture) != 0) ++ ret = -EINVAL; ++ ++ tdm_record->tdm_capture = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(tdm_record->base.hrt_state) == TRUE) ++ hrtimer_cancel(&tdm_record->base.hrtimer); ++ ++ /* free record data */ ++ kfree(tdm_record); ++ ++ return ret; ++} ++ ++/***************************************************************************** ++ * callback functions of ADSP ALSA driver ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Open a playback/TDM playback or record/TDM record stream ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_open(struct snd_pcm_substream *substream) ++{ ++ /* get ADSP soundcard and CPU DAI index */ ++ struct snd_adsp_card *adsp_card; ++ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ struct snd_adsp_control *ctr_if; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ /* register data for playback/record functions */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* perform playback initialization */ ++ if (snd_adsp_playback_init( ++ &adsp_card->playback[dai_idx], ++ ctr_if->eqz_switch[DIRECT_PLAYBACK][dai_idx], ++ substream) < 0) { ++ /* perform playback de-initialization when */ ++ /* the initialization fails */ ++ snd_adsp_playback_deinit( ++ adsp_card->playback[dai_idx]); ++ ++ adsp_card->playback[dai_idx] = NULL; ++ return -EINVAL; ++ } ++ } else { ++ /* perform record initialization */ ++ if (snd_adsp_record_init( ++ &adsp_card->record[dai_idx], ++ ctr_if->eqz_switch[DIRECT_CAPTURE][dai_idx], ++ substream) < 0) { ++ /* perform record de-initialization when the */ ++ /* initialization fails */ ++ snd_adsp_record_deinit( ++ adsp_card->record[dai_idx]); ++ ++ adsp_card->record[dai_idx] = NULL; ++ return -EINVAL; ++ } ++ } ++ ++ /* save the hardware parameters */ ++ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_hw); ++ ++ /* each period has a frame size */ ++ snd_pcm_hw_constraint_single(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, ++ FRAME_SIZE); ++ } else { ++ /* register data for TDM playback/record functions */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* perform TDM playback initialization */ ++ if (snd_adsp_tdm_playback_init( ++ &adsp_card->tdm_playback, ++ substream) < 0) { ++ /* perform TDM playback de-initialization */ ++ /* when the initialization fails */ ++ snd_adsp_tdm_playback_deinit( ++ adsp_card->tdm_playback); ++ ++ adsp_card->tdm_playback = NULL; ++ return -EINVAL; ++ } ++ } else { ++ /* perform TDM record initialization */ ++ if (snd_adsp_tdm_record_init(&adsp_card->tdm_record, ++ substream) < 0) { ++ /* perform TDM record de-initialization */ ++ /* when the initialization fails */ ++ snd_adsp_tdm_record_deinit( ++ adsp_card->tdm_record); ++ ++ adsp_card->tdm_record = NULL; ++ return -EINVAL; ++ } ++ } ++ ++ /* save the hardware parameters */ ++ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_tdm_hw); ++ ++ /* each period has a frame size */ ++ snd_pcm_hw_constraint_single(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, ++ TDM_FRAME_SIZE); ++ } ++ ++ snd_pcm_hw_constraint_integer(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIODS); ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Close a playback/TDM playback or record/TDM record stream ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_close(struct snd_pcm_substream *substream) ++{ ++ /* get ADSP soundcard and CPU DAI index */ ++ struct snd_adsp_card *adsp_card = ++ snd_adsp_get_drvdata_from_substream(substream); ++ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ int err = 0; ++ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ /* destroy Renderer/Capture or Equalizer (if used) */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (snd_adsp_playback_deinit( ++ adsp_card->playback[dai_idx]) < 0) ++ err = -EINVAL; ++ ++ adsp_card->playback[dai_idx] = NULL; ++ } else { ++ if (snd_adsp_record_deinit( ++ adsp_card->record[dai_idx]) < 0) ++ err = -EINVAL; ++ ++ adsp_card->record[dai_idx] = NULL; ++ } ++ } else { ++ /* destroy TDM Renderer/TDM Capture */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (snd_adsp_tdm_playback_deinit( ++ adsp_card->tdm_playback) < 0) ++ err = -EINVAL; ++ ++ adsp_card->tdm_playback = NULL; ++ } else { ++ if (snd_adsp_tdm_record_deinit( ++ adsp_card->tdm_record) < 0) ++ err = -EINVAL; ++ ++ adsp_card->tdm_record = NULL; ++ } ++ } ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ * \brief Allocate ALSA buffer and calculate expire time of hr timer ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -ENOMEM Cannot allocate ALSA buffer ++ *****************************************************************************/ ++static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params) ++{ ++ struct snd_adsp_base_info *base; ++ int err = 0; ++ ++ base = snd_adsp_get_base_from_substream(substream); ++ ++ /* set expire time of hrtimer, this value should be time for */ ++ /* transfer a frame */ ++ base->ktime = ns_to_ktime((1000000000 / params_rate(hw_params)) * ++ params_period_size(hw_params)); ++ ++ err = snd_pcm_lib_malloc_pages(substream, ++ params_buffer_bytes(hw_params)); ++ ++ /* reset DMA buffer area */ ++ memset(substream->runtime->dma_area, 0, substream->runtime->dma_bytes); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ * \brief Free the allocated ALSA buffer ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Cannot deallocate buffer ++ *****************************************************************************/ ++static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++/** ************************************************************************** ++ * \brief Prepare playback/TDM playback or record/TDM record function ++ * before transferring data ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ /* get ADSP soundcard and CPU DAI index */ ++ struct snd_adsp_card * ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ int err = 0; ++ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ /* get playback prepared to execute */ ++ err = snd_adsp_playback_prepare( ++ adsp_card->playback[dai_idx], substream); ++ else ++ /* get record prepared to execute */ ++ err = snd_adsp_record_prepare( ++ adsp_card->record[dai_idx], substream); ++ } else { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ /* get TDM playback prepared to execute */ ++ err = snd_adsp_tdm_playback_prepare( ++ adsp_card->tdm_playback, substream); ++ else ++ /* get TDM record prepared to execute */ ++ err = snd_adsp_tdm_record_prepare( ++ adsp_card->tdm_record, substream); ++ } ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ * \brief Trigger playback/TDM playback or record/TDM record stream ++ * to go to next phase ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ ++ switch (idx) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ /* start high-resolution timer */ ++ hrtimer_start(&base->hrtimer, base->ktime, HRTIMER_MODE_REL); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ int buf_queue = 0; ++ ++ /* get current available buffer */ ++ spin_lock(&base->lock); ++ buf_queue = base->buf_queue; ++ spin_unlock(&base->lock); ++ ++ /* send all available buffer to plugin to */ ++ /* get data */ ++ for (; buf_queue > 0; buf_queue--) { ++ if (xf_adsp_fill_this_buffer( ++ base->handle_id, ++ base->buffer[base->buf_idx], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ base->buf_idx++; ++ ++ if (base->buf_idx >= XF_BUF_POOL_SIZE) ++ base->buf_idx = 0; ++ } ++ } ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Return HW data position ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval position HW data position ++ *****************************************************************************/ ++static snd_pcm_uframes_t ++snd_adsp_pcm_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ unsigned int hw_idx, hw_buffer_size; ++ snd_pcm_uframes_t pointer; ++ ++ /* convert hw index to correct as submitted bytes */ ++ spin_lock(&base->lock); ++ hw_idx = (base->hw_idx / base->buf_bytes) * base->period_bytes; ++ spin_unlock(&base->lock); ++ ++ hw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ if (hw_idx >= hw_buffer_size) { ++ spin_lock(&base->lock); ++ ++ base->hw_idx -= (hw_buffer_size / base->period_bytes) * ++ base->buf_bytes; ++ ++ spin_unlock(&base->lock); ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ pointer = snd_pcm_indirect_playback_pointer(substream, ++ &base->pcm_indirect, ++ hw_idx); ++ else ++ pointer = snd_pcm_indirect_capture_pointer(substream, ++ &base->pcm_indirect, ++ hw_idx); ++ ++ return pointer; ++} ++ ++/** ************************************************************************** ++ * \brief Call read/write process to transfer data ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ ++ if (base->runtime_err) ++ return -EINVAL; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ snd_pcm_indirect_playback_transfer(substream, ++ &base->pcm_indirect, ++ snd_adsp_pcm_transfer); ++ else ++ snd_pcm_indirect_capture_transfer(substream, ++ &base->pcm_indirect, ++ snd_adsp_pcm_transfer); ++ ++ return 0; ++} ++ ++/** *************************************************************************** ++ * \brief Copy data from source buffer to destination buffer ++ * ++ * \params[in] dst Destination buffer pointer ++ * \params[out] src Source buffer pointer ++ * \params[in] dst_size Destination buffer size in byte ++ * \params[in] src_size Source buffer size in byte ++ * \retval None ++ *****************************************************************************/ ++static inline void ++snd_adsp_copy_data(void *dst, void *src, int dst_size, int src_size) ++{ ++ unsigned char *data_dst = dst; ++ unsigned char *data_src = src; ++ int i; ++ ++ if (dst_size == src_size) { ++ /* src and dst bufs are same size, does not need to convert */ ++ memcpy(data_dst, data_src, dst_size); ++ ++ } else if (dst_size < src_size) { ++ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_3LE)); ++ i += BYTES_PER_SAMPLE(S24_3LE)) { ++ *(u32 *)data_dst = *(u32 *)data_src; ++ ++ data_dst += BYTES_PER_SAMPLE(S24_3LE); ++ data_src += BYTES_PER_SAMPLE(S24_LE); ++ } ++ ++ /* copy a S24_3LE sample from S24_LE sample */ ++ data_dst[0] = data_src[0]; ++ data_dst[1] = data_src[1]; ++ data_dst[2] = data_src[2]; ++ ++ } else { ++ unsigned int tmp; ++ ++ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_LE)); ++ i += BYTES_PER_SAMPLE(S24_LE)) { ++ tmp = *(u32 *)data_src; ++ *(u32 *)data_dst = tmp & 0x0FFFFFF; ++ ++ data_dst += BYTES_PER_SAMPLE(S24_LE); ++ data_src += BYTES_PER_SAMPLE(S24_3LE); ++ } ++ ++ /* copy a S24_LE sample from S24_3LE sample */ ++ data_dst[0] = data_src[0]; ++ data_dst[1] = data_src[1]; ++ data_dst[2] = data_src[2]; ++ data_dst[3] = 0; ++ } ++} ++ ++/** ************************************************************************** ++ * \brief Transfer data process between ALSA buffer and ADSP buffer ++ * ++ * \param[in] substream Pointer to substream object ++ * \param[in] rec Pointer to indirect PCM data ++ * \param[in] bytes Number of byte need to be transferred ++ * \retval None ++ *****************************************************************************/ ++static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, ++ size_t bytes) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ int direct = substream->stream; ++ int trans_bytes = bytes; ++ int buf_bytes, period_bytes; ++ void *dma_buf, *data_buff; ++ ++ /* get the DMA buffer pointer */ ++ dma_buf = (void *)(substream->runtime->dma_area + rec->sw_data); ++ ++ /* get information from base */ ++ buf_bytes = base->buf_bytes; ++ period_bytes = base->period_bytes; ++ ++ /* make sure the available buffer and transfer size - TBD */ ++ while (trans_bytes > 0) { ++ spin_lock(&base->lock); ++ if (base->buf_queue > 0 && trans_bytes >= period_bytes) { ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* get the buffer pointer from stream */ ++ data_buff = base->buffer[base->buf_idx]; ++ ++ if (direct == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* copy data from user *//* PRQA S 3200 2 */ ++ snd_adsp_copy_data(data_buff, dma_buf, ++ buf_bytes, period_bytes); ++ ++ /* send buffer to plugin */ ++ if (xf_adsp_empty_this_buffer(base->handle_id, ++ data_buff, ++ buf_bytes) < 0) ++ base->runtime_err = TRUE; ++ } else { ++ /* copy data to user *//* PRQA S 3200 2 */ ++ snd_adsp_copy_data(dma_buf, data_buff, ++ period_bytes, buf_bytes); ++ ++ /* send buffer to plugin */ ++ if (xf_adsp_fill_this_buffer(base->handle_id, ++ data_buff, ++ buf_bytes) < 0) ++ base->runtime_err = TRUE; ++ } ++ ++ base->buf_idx++; ++ if (base->buf_idx >= XF_BUF_POOL_SIZE) ++ base->buf_idx = 0; ++ } else { ++ spin_unlock(&base->lock); ++ break; ++ } ++ ++ trans_bytes -= period_bytes; ++ } ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Volume control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of volume control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = -1; ++ uinfo->value.integer.max = 799; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get volume value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to volume value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; ++ int handle_state, handle_id; ++ int volume, cmd_idx, direction; ++ unsigned int index; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* determine command index, direction, handle state, handle ID */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ handle_id = ++ adsp_card->playback[index]->renderer->handle_id; ++ } ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ handle_id = ++ adsp_card->record[index]->capture->handle_id; ++ } ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) { ++ handle_state = adsp_card->tdm_playback->state; ++ ++ handle_id = ++ adsp_card->tdm_playback->tdm_renderer->handle_id; ++ } ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) { ++ handle_state = adsp_card->tdm_record->state; ++ ++ handle_id = ++ adsp_card->tdm_record->tdm_capture->handle_id; ++ } ++ } ++ } ++ ++ /* get the volume's value */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* get the volume's value from the plugin */ ++ if (xf_adsp_get_param(handle_id, cmd_idx, &volume) != 0) ++ return -EINVAL; ++ ++ /* check the value after getting it and adjust it */ ++ ucontrol->value.integer.value[0] = (volume == 0xFFFFFFFF) ? ++ (-1) : (volume * VOLUME_SCALE) >> 20; ++ } else { ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ ucontrol->value.integer.value[0] = ++ (ctr_if->vol_rate[direction][index] * ++ VOLUME_SCALE) >> 20; ++ else ++ ucontrol->value.integer.value[0] = ++ (ctr_if->tdm_vol_rate[direction] * ++ VOLUME_SCALE) >> 20; ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set volume value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to volume value ++ * \retval 1 Volume change ++ * \retval 0 Volume does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1*/ ++static int ++snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; ++ int volume; ++ int ret; ++ int handle_state, handle_id, cmd_idx, volume_get; ++ int direction; ++ unsigned int index; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state and handle ID */ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* get the value to set */ ++ if (ucontrol->value.integer.value[0] == -1) { ++ volume = 0xFFFFFFFF; ++ } else { ++ /* round up the value if needed */ ++ volume = (ucontrol->value.integer.value[0] * (1 << 20)) / ++ VOLUME_SCALE; ++ ++ if ((ucontrol->value.integer.value[0] * (1 << 20)) > ++ (VOLUME_SCALE * volume)) ++ volume += 1; ++ } ++ ++ /* determine command index, direction, handle state, handle ID */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ handle_id = ++ adsp_card->playback[index]->renderer->handle_id; ++ } ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ handle_id = ++ adsp_card->record[index]->capture->handle_id; ++ } ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) { ++ handle_state = adsp_card->tdm_playback->state; ++ ++ handle_id = ++ adsp_card->tdm_playback->tdm_renderer->handle_id; ++ } ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) { ++ handle_state = adsp_card->tdm_record->state; ++ ++ handle_id = ++ adsp_card->tdm_record->tdm_capture->handle_id; ++ } ++ } ++ } ++ ++ /* set volume to plugin */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* TDM does not support set volume in runtime state */ ++ if (kcontrol->id.name[0] == PREFIX_OF_TDM_CTR_NAME) ++ return -EINVAL; ++ ++ /* apply set volume value to ADSP from user setting */ ++ if (xf_adsp_set_param(handle_id, cmd_idx, volume) != 0) ++ return -EINVAL; ++ ++ /* get volume from ADSP after setting to confirm */ ++ if (xf_adsp_get_param(handle_id, cmd_idx, &volume_get) != 0) ++ return -EINVAL; ++ ++ /* check if the value has changed */ ++ ret = (volume_get == volume) ? 1 : 0; ++ } else { ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ ctr_if->vol_rate[direction][index] = volume; ++ else ++ ctr_if->tdm_vol_rate[direction] = volume; ++ ++ ret = 1; ++ } ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Sample Rate Converter control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of sample rate ++ * converter control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = -1; ++ uinfo->value.integer.max = 48000; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get sample rate value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to sample rate value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int *rate; ++ int handle_id, handle_state, cmd_idx, direction; ++ unsigned int index; ++ ++ rate = (int *)&ucontrol->value.integer.value[0]; /* PRQA S 310 */ ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state and handle ID */ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* determine command, direction, handle state, handle ID */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ handle_id = ++ adsp_card->playback[index]->renderer->handle_id; ++ } ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ handle_id = ++ adsp_card->record[index]->capture->handle_id; ++ } ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) { ++ handle_state = adsp_card->tdm_playback->state; ++ ++ handle_id = ++ adsp_card->tdm_playback->tdm_renderer->handle_id; ++ } ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) { ++ handle_state = adsp_card->tdm_record->state; ++ ++ handle_id = ++ adsp_card->tdm_record->tdm_capture->handle_id; ++ } ++ } ++ } ++ ++ /* get parameter from plugin */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ if (xf_adsp_get_param(handle_id, cmd_idx, rate) != 0) ++ return -EINVAL; ++ } else { ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ *rate = adsp_card->ctr_if.sample_rate[direction][index]; ++ else ++ *rate = adsp_card->ctr_if.tdm_sample_rate[direction]; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set sample rate value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to sample rate value ++ * \retval 1 Sample rate change ++ * \retval 0 Sample rate does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1 */ ++static int ++snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ unsigned int index; ++ int rate; ++ int handle_state, cmd_idx, direction; ++ int ret = 1; ++ ++ rate = (int)ucontrol->value.integer.value[0]; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* determine command, direction and handle state */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) ++ handle_state = adsp_card->tdm_playback->state; ++ ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) ++ handle_state = adsp_card->tdm_record->state; ++ } ++ } ++ ++ /* get the value to set */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) ++ return -EINVAL; ++ ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ adsp_card->ctr_if.sample_rate[direction][index] = rate; ++ else ++ adsp_card->ctr_if.tdm_sample_rate[direction] = rate; ++ ++ ret = 1; ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Equalizer control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of Equalizer control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = MAX_EQZ_PARAM_NUMBER; ++ uinfo->value.integer.min = -1; ++ uinfo->value.integer.max = 0x7fffffff; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get equalizer parameters value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer parameters value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int handle_state, direction; ++ int i, j, filter_index; ++ unsigned int index; ++ struct xf_adsp_equalizer *equalizer; ++ struct xf_adsp_equalizer_params *eqz_params; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determin direction of stream */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* set handle state as NULL state, handle ID, equalizer pointer */ ++ handle_state = XF_HANDLE_NULL; ++ equalizer = NULL; ++ ++ /* get component's state */ ++ if (direction == DIRECT_PLAYBACK) { ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->eqz_state; ++ equalizer = adsp_card->playback[index]->equalizer; ++ } ++ } else { ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->eqz_state; ++ equalizer = adsp_card->record[index]->equalizer; ++ } ++ } ++ ++ /* perform parameters' values getting */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* get equalizer's parameters */ ++ if (xf_adsp_equalizer_get_params(equalizer) != 0) ++ return -EINVAL; ++ ++ eqz_params = &equalizer->params; ++ } else { ++ eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; ++ } ++ ++ /* get equalizer type: PARAMETRIC or GRAPHIC */ ++ ucontrol->value.integer.value[0] = eqz_params->eqz_type; ++ ++ /* get parameters' value from Equalizer plugin */ ++ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { ++ for (i = 0, filter_index = 1; ++ filter_index <= XA_REL_EQZ_FILTER_NUM; ++ i++, filter_index++) { ++ /* get filter index */ ++ ucontrol->value.integer.value[(i * 6) + 1] = ++ filter_index; ++ ++ /* get frequency centre */ ++ ucontrol->value.integer.value[(i * 6) + 2] = ++ eqz_params->p_coef.fc[i]; ++ ++ /* get bandwidth */ ++ ucontrol->value.integer.value[(i * 6) + 3] = ++ eqz_params->p_coef.band_width[i]; ++ ++ /* get filter type */ ++ ucontrol->value.integer.value[(i * 6) + 4] = ++ eqz_params->p_coef.type[i]; ++ ++ /* get gain base */ ++ ucontrol->value.integer.value[(i * 6) + 5] = ++ eqz_params->p_coef.gain_base[i]; ++ ++ /* get gain */ ++ ucontrol->value.integer.value[(i * 6) + 6] = ++ eqz_params->p_coef.gain[i]; ++ } ++ } else { ++ for (i = 0, filter_index = 1; ++ filter_index <= XA_REL_EQZ_GRAPHIC_BAND_NUM; ++ i++, filter_index++) { ++ /* get band index */ ++ ucontrol->value.integer.value[(i * 2) + 1] = ++ filter_index; ++ ++ /* get graphic gain */ ++ ucontrol->value.integer.value[(i * 2) + 2] = ++ eqz_params->g_coef.gain_g[i]; ++ } ++ ++ j = (i * 2) + 1; ++ ++ /* make the rest of values silent */ ++ while (j < MAX_EQZ_PARAM_NUMBER) { ++ ucontrol->value.integer.value[j] = -1; ++ j++; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set equalizer parameters value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer parameters value ++ * \retval 1 Equalizer parameters change ++ * \retval 0 Equalizer parameters does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1*/ ++static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int handle_state, direction, filter_idx; ++ int i; ++ int index; ++ struct xf_adsp_equalizer_params *eqz_params = NULL; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determine the direction */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* get the handle state */ ++ if (direction == DIRECT_PLAYBACK) { ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->eqz_state; ++ } else { ++ if (adsp_card->record[index]) ++ handle_state = adsp_card->record[index]->eqz_state; ++ } ++ ++ /* perform equalizer's parameters setting */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) ++ return -EINVAL; ++ ++ /* PRQA S 310 1*/ ++ eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; ++ ++ i = 0; ++ /* PRQA S 3440 1*/ ++ eqz_params->eqz_type = ucontrol->value.integer.value[i]; ++ i++; ++ filter_idx = 0; ++ ++ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { ++ while (i < MAX_EQZ_PARAM_NUMBER) { ++ /* get index filter */ ++ /* PRQA S 3440*/ ++ filter_idx = ucontrol->value.integer.value[i]; ++ i++; ++ ++ /* valid index filter is range */ ++ /* (1 to XA_REL_EQZ_FILTER_NUM) */ ++ if (filter_idx >= 1 && ++ filter_idx <= XA_REL_EQZ_FILTER_NUM) { ++ /* PRQA S 3440 5*/ ++ eqz_params->p_coef.fc[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.band_width[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.type[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.gain_base[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.gain[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ } ++ /* index filter = -1 means that user */ ++ /* does not set this filter */ ++ else if (filter_idx == -1 || filter_idx == 0) { ++ i += 5; ++ } else { ++ return -EINVAL; ++ } ++ } ++ } else if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_GRAPHIC) { ++ while (i < ((XA_REL_EQZ_GRAPHIC_BAND_NUM * 2) + 1)) { ++ /*get index filter */ ++ /* PRQA S 3440 */ ++ filter_idx = ucontrol->value.integer.value[i++]; ++ ++ if (filter_idx >= 1 && ++ filter_idx <= XA_REL_EQZ_GRAPHIC_BAND_NUM) { ++ eqz_params->g_coef.gain_g[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ i++; ++ ++ } else if (filter_idx == -1 || filter_idx == 0) { ++ i += 1; ++ } else { ++ return -EINVAL; ++ } ++ } ++ } else { ++ return -EINVAL; ++ } ++ ++ return 1; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Equalizer Switch control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of Equalizer ++ * Switch control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 1; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get equalizer switch value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer switch value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int ++snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int direction; ++ unsigned int index; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determine the direction */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* get the Equalizer switch status */ ++ ucontrol->value.integer.value[0] = ++ adsp_card->ctr_if.eqz_switch[direction][index]; ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set equalizer switch value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer switch value ++ * \retval 1 Equalizer switch change ++ * \retval 0 Equalizer switch does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1 */ ++static int ++snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int eqz_switch; ++ int handle_state, direction; ++ unsigned int index; ++ int ret = 0; ++ ++ eqz_switch = ucontrol->value.integer.value[0]; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determine the direction */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* determine handle state */ ++ if (direction == DIRECT_PLAYBACK) { ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->rdr_state; ++ } else { ++ if (adsp_card->record[index]) ++ handle_state = adsp_card->record[index]->cap_state; ++ } ++ ++ /* set the status of Equalizer */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* runtime setting is not supported */ ++ ret = -EINVAL; ++ } else { ++ adsp_card->ctr_if.eqz_switch[direction][index] = eqz_switch; ++ ret = 1; ++ } ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Renderer output channel ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of Renderer output channel ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_control_rdr_out_channel_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = MONAURAL; ++ uinfo->value.integer.max = STEREO; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get Renderer output channel's value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to Renderer output channel value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int ++snd_adsp_control_rdr_out_channel_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int rdr_out_ch; ++ unsigned int index; ++ int handle_state, handle_id; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* determine handle state and handle ID */ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ handle_id = adsp_card->playback[index]->renderer->handle_id; ++ } ++ ++ /* get Renderer output channel's value */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* get Renderer output channel's value from Renderer plugin */ ++ if (xf_adsp_get_param(handle_id, ++ XA_RDR_CONFIG_PARAM_OUT_CHANNELS, ++ &rdr_out_ch) != 0) { ++ return -EINVAL; ++ } ++ ++ ucontrol->value.integer.value[0] = rdr_out_ch; ++ } else { ++ ucontrol->value.integer.value[0] = ++ adsp_card->ctr_if.rdr_out_ch[index]; ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set Renderer output channel's value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to Renderer output channel value ++ * \retval 1 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int ++snd_adsp_control_rdr_out_channel_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ unsigned int index; ++ int handle_state; ++ int ret = 1; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* determine handle state and handle ID */ ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ /* get Renderer output channel's value */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) ++ /* not support runtime setting */ ++ ret = -EINVAL; ++ else ++ adsp_card->ctr_if.rdr_out_ch[index] = ++ ucontrol->value.integer.value[0]; ++ ++ return ret; ++} ++ ++/** control interface for playback's volume rate */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_playback_volume_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ } ++}; ++ ++/** control interface for Capture's volume rate */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_capture_volume_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ } ++}; ++ ++/** control interface for playback's output sample rate */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_playback_sample_rate_out_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ } ++}; ++ ++/** control interface for Capture's input sample rate */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_capture_sample_rate_in_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ } ++}; ++ ++/** control interface for Equalizer parameters in playback */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_playback_equalizer_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ } ++}; ++ ++/** control interface for Equalizer parameters in record */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_capture_equalizer_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ } ++}; ++ ++/** control interface for Equalizer usage in playback */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_playback_equalizer_switch_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ } ++}; ++ ++/** control interface for Equalizer usage in record */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_capture_equalizer_switch_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ } ++}; ++ ++/** control interface for playback's output channel */ ++static struct snd_kcontrol_new ++snd_adsp_playback_out_channel_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ } ++}; ++ ++/** control interface for TDM playback's volume rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_playback_volume_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++}; ++ ++/** control interface for TDM capture's volume rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_capture_volume_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++}; ++ ++/** control interface for TDM playback's output sample rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_playback_sample_rate_out_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++}; ++ ++/** control interface for TDM capture's input sample rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_capture_sample_rate_in_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++}; ++ ++/** PCM callback function of the sound card */ ++static struct snd_pcm_ops snd_adsp_pcm_ops = { ++ .open = &snd_adsp_pcm_open, /* PRQA S 1053 10 */ ++ .close = &snd_adsp_pcm_close, ++ .ioctl = &snd_pcm_lib_ioctl, ++ .hw_params = &snd_adsp_pcm_hw_params, ++ .hw_free = &snd_adsp_pcm_hw_free, ++ .prepare = &snd_adsp_pcm_prepare, ++ .trigger = &snd_adsp_pcm_trigger, ++ .pointer = &snd_adsp_pcm_pointer, ++ .ack = &snd_adsp_pcm_ack ++}; ++ ++/******************************************************************* ++ * Internal functions ++ * ****************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Process information get from control structure ++ * ++ * \param[in] eqz_params Equalizer parameters object ++ * \param[in] eqz_ctr_params Equalizer parameters stored in control object ++ * \param[in] flag Indicate playback or capture stream ++ *****************************************************************************/ ++static void snd_adsp_get_eqz_params_from_control( ++ struct xf_adsp_equalizer_params *eqz_params, ++ struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag) ++{ ++ int filter_idx; ++ ++ if (flag) { ++ if (eqz_ctr_params->eqz_type >= 0) ++ eqz_params->eqz_type = eqz_ctr_params->eqz_type; ++ ++ for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; ++ filter_idx++) { ++ if (eqz_ctr_params->p_coef.fc[filter_idx] >= 0) ++ eqz_params->p_coef.fc[filter_idx] = ++ eqz_ctr_params->p_coef.fc[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.band_width[filter_idx] >= 0) ++ eqz_params->p_coef.band_width[filter_idx] = ++ eqz_ctr_params->p_coef.band_width[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.type[filter_idx] >= 0) ++ eqz_params->p_coef.type[filter_idx] = ++ eqz_ctr_params->p_coef.type[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.gain_base[filter_idx] >= 0) ++ eqz_params->p_coef.gain_base[filter_idx] = ++ eqz_ctr_params->p_coef.gain_base[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.gain[filter_idx] >= 0) ++ eqz_params->p_coef.gain[filter_idx] = ++ eqz_ctr_params->p_coef.gain[filter_idx]; ++ } ++ for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; ++ filter_idx++) { ++ if (eqz_ctr_params->g_coef.gain_g[filter_idx] >= 0) ++ eqz_params->g_coef.gain_g[filter_idx] = ++ eqz_ctr_params->g_coef.gain_g[filter_idx]; ++ } ++ } else { ++ memcpy(eqz_ctr_params, eqz_params, sizeof(*eqz_params)); ++ } ++} ++ ++/******************************************************************* ++ * ALSA ADSP Platform driver interface ++ * ****************************************************************/ ++ ++/** **************************************************************************** ++ * \brief Register control interface and preallocate ALSA buffer ++ * ++ * \param[in] runtime Pointer to runtime PCM data ++ * \retval 0 Success ++ * \retval -EINVAL Cannot register control interface ++ ******************************************************************************/ ++static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime) ++{ ++ int i = 0, err = 0; ++ int id; ++ struct snd_card *card; ++ struct snd_adsp_card *adsp_card; ++ int alsa_buf_sz = 0; ++ ++ /* get sound card data */ ++ card = runtime->card->snd_card; ++ ++ /* get driver data */ ++ adsp_card = snd_soc_dai_get_drvdata(runtime->cpu_dai); ++ ++ /* get the ID of CPU DAI */ ++ id = runtime->cpu_dai->id; ++ ++ /* register control interfaces */ ++ if (id == RDR_DAI_IDX0 || id == RDR_DAI_IDX1 || ++ id == RDR_DAI_IDX2 || id == RDR_DAI_IDX3) { ++ struct snd_kcontrol *kctl[RDR_CONTROL_NUM]; ++ void *rdr_ctr[RDR_CONTROL_NUM] = { ++ &snd_adsp_playback_volume_control[id], /* PRQA S 1031 */ ++ &snd_adsp_capture_volume_control[id], ++ &snd_adsp_playback_sample_rate_out_control[id], ++ &snd_adsp_capture_sample_rate_in_control[id], ++ &snd_adsp_playback_equalizer_control[id], ++ &snd_adsp_capture_equalizer_control[id], ++ &snd_adsp_playback_equalizer_switch_control[id], ++ &snd_adsp_capture_equalizer_switch_control[id], ++ &snd_adsp_playback_out_channel_control[id] ++ }; ++ ++ /* add basic control instance */ ++ for (i = 0; i < RDR_CONTROL_NUM; i++) { ++ kctl[i] = snd_ctl_new1(rdr_ctr[i], adsp_card); ++ err = snd_ctl_add(card, kctl[i]); ++ if (err < 0) ++ return -EINVAL; ++ } ++ ++ /* assign ALSA buffer size */ ++ alsa_buf_sz = MAX_BUFFER_BYTES; ++ ++ /* enable MIX feature from the 2nd playback/record stream */ ++ if (adsp_card->ctr_if.mix_usage == MIX_UNUSED) ++ adsp_card->ctr_if.mix_usage = FIRST_RUN; ++ else if (adsp_card->ctr_if.mix_usage == FIRST_RUN) ++ adsp_card->ctr_if.mix_usage = SECOND_RUN; ++ ++ } else { ++ struct snd_kcontrol *kctl[TDM_CONTROL_NUM]; ++ void *tdm_ctr[TDM_CONTROL_NUM] = { ++ &snd_adsp_tdm_playback_volume_control, ++ &snd_adsp_tdm_playback_sample_rate_out_control, ++ &snd_adsp_tdm_capture_volume_control, ++ &snd_adsp_tdm_capture_sample_rate_in_control ++ }; ++ ++ /* add basic control instances */ ++ for (i = 0; i < TDM_CONTROL_NUM; i++) { ++ kctl[i] = snd_ctl_new1(tdm_ctr[i], adsp_card); ++ err = snd_ctl_add(card, kctl[i]); ++ if (err < 0) ++ return -EINVAL; ++ } ++ ++ /* assign ALSA buffer size */ ++ alsa_buf_sz = TDM_MAX_BUFFER_BYTES; ++ } ++ ++ return snd_pcm_lib_preallocate_pages_for_all(runtime->pcm, ++ SNDRV_DMA_TYPE_CONTINUOUS, ++ snd_dma_continuous_data(GFP_KERNEL), ++ alsa_buf_sz, alsa_buf_sz); ++} ++ ++/* **************************************************************************** ++ * ALSA ADSP DAI register ++ * ***************************************************************************/ ++ ++/** callback function of platform driver */ ++static struct snd_soc_platform_driver snd_adsp_platform = { ++ .pcm_new = &snd_adsp_pcm_new, /* PRQA S 1053 *//* PRQA S 0674 */ ++ .ops = &snd_adsp_pcm_ops, ++}; ++ ++/** component information of driver */ ++static const struct snd_soc_component_driver snd_adsp_component = { ++ .name = "snd_adsp", /* PRQA S 1053 */ ++}; ++ ++/** DAI information of ADSP ALSA driver */ ++static struct snd_soc_dai_driver snd_adsp_dai[MAX_DAI_IDX] = { ++ { ++ /* PRQA S 1053 */ ++ .id = RDR_DAI_IDX0, ++ .name = "adsp-dai.0", ++ .playback.stream_name = "Playback0", ++ .capture.stream_name = "Capture0", ++ }, ++ { ++ .id = RDR_DAI_IDX1, ++ .name = "adsp-dai.1", ++ .playback.stream_name = "Playback1", ++ .capture.stream_name = "Capture1", ++ }, ++ { ++ .id = RDR_DAI_IDX2, ++ .name = "adsp-dai.2", ++ .playback.stream_name = "Playback2", ++ .capture.stream_name = "Capture2", ++ }, ++ { ++ .id = RDR_DAI_IDX3, ++ .name = "adsp-dai.3", ++ .playback.stream_name = "Playback3", ++ .capture.stream_name = "Capture3", ++ }, ++ { ++ .id = TDM_DAI_IDX, ++ .name = "adsp-tdm-dai", ++ .playback.stream_name = "TDM Playback", ++ .capture.stream_name = "TDM Capture", ++ } ++}; ++ ++/** *************************************************************************** ++ * \brief Register platform driver and ADSP ALSA sound card ++ * ++ * \param[in] pdev Pointer to platform driver data ++ * \retval 0 Success ++ * \retval -ENOMEM Cannot allocate driver's data ++ * \retval -EINVAL Cannot register platform driver or sound card ++ ****************************************************************************/ ++static int snd_adsp_probe(struct platform_device *pdev) ++{ ++ struct snd_adsp_card *adsp_card; ++ int i; ++ ++ /* allocate a card data structure */ ++ adsp_card = kmalloc(sizeof(*adsp_card), GFP_KERNEL); ++ if (!adsp_card) ++ return -ENOMEM; ++ ++ /* init parameters */ ++ memset(adsp_card, 0, sizeof(*adsp_card)); /* PRQA S 3200 */ ++ ++ /* PRQA S 3200 1*/ ++ memset(&adsp_card->ctr_if, -1, sizeof(struct snd_adsp_control)); ++ ++ /* disable Equalizer for all streams */ ++ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { ++ adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][i] = 0; ++ adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][i] = 0; ++ } ++ ++ /* disable MIX function for all */ ++ adsp_card->ctr_if.mix_usage = MIX_UNUSED; ++ ++ /* save driver data */ ++ dev_set_drvdata(&pdev->dev, adsp_card); ++ ++ /* register platform device */ ++ if (snd_soc_register_platform(&pdev->dev, &snd_adsp_platform) < 0) { ++ snd_soc_unregister_platform(&pdev->dev); ++ return -EINVAL; ++ } ++ ++ /* fill format information of sound DAI driver for Rdr/Cap function */ ++ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { ++ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].playback.channels_min = MIN_CHANNEL; ++ snd_adsp_dai[i].playback.channels_max = MAX_CHANNEL; ++ ++ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].capture.channels_min = MIN_CHANNEL; ++ snd_adsp_dai[i].capture.channels_max = MAX_CHANNEL; ++ } ++ ++ /* fill format information of sound DAI driver for TDM function */ ++ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].playback.channels_min = TDM_MIN_CHANNEL; ++ snd_adsp_dai[i].playback.channels_max = TDM_MAX_CHANNEL; ++ ++ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].capture.channels_min = TDM_MIN_CHANNEL; ++ snd_adsp_dai[i].capture.channels_max = TDM_MAX_CHANNEL; ++ ++ /* register CPU dai */ ++ if (snd_soc_register_component(&pdev->dev, &snd_adsp_component, ++ snd_adsp_dai, ++ ARRAY_SIZE(snd_adsp_dai)) < 0) { ++ snd_soc_unregister_platform(&pdev->dev); ++ return -EINVAL; ++ } ++ ++ dev_info(&pdev->dev, "probed\n"); ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Unregister platform driver and ADSP ALSA sound card ++ * ++ * \param[in] pdev Pointer platform driver data ++ * \retval 0 Success ++ * \retval -EINVAL Invalid driver's data ++ *****************************************************************************/ ++static int snd_adsp_remove(struct platform_device *pdev) ++{ ++ /* get ADSP sound card data */ ++ struct snd_adsp_card *adsp_card = dev_get_drvdata(&pdev->dev); ++ ++ if (!adsp_card) ++ return -ENODEV; ++ ++ /* release the ADSP sound card */ ++ kfree(adsp_card); ++ ++ /* unregister platform driver */ ++ snd_soc_unregister_component(&pdev->dev); ++ snd_soc_unregister_platform(&pdev->dev); ++ ++ /* success */ ++ return 0; ++} ++ ++/** ADSP ALSA driver information */ ++static const struct of_device_id snd_adsp_id[] = { ++ { .compatible = "renesas,rcar_adsp_sound_gen3", }, /* PRQA S 1053 */ ++}; ++MODULE_DEVICE_TABLE(of, snd_adsp_id); ++ ++/** platform driver of ADSP ALSA sound card */ ++static struct platform_driver snd_adsp_driver = { ++ .driver = { /* PRQA S 1053 */ ++ .name = "rcar_adsp_sound", ++ .of_match_table = snd_adsp_id, ++ }, ++ .probe = snd_adsp_probe, ++ .remove = snd_adsp_remove, ++}; ++module_platform_driver(snd_adsp_driver); /* PRQA S 0651 */ ++ ++MODULE_AUTHOR("Renesas AudioDSP"); ++MODULE_DESCRIPTION("Platform driver for ADSP"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:ADSP-PCM-AUDIO"); +diff --git a/sound/soc/adsp/xf-adsp-base.c b/sound/soc/adsp/xf-adsp-base.c +new file mode 100644 +index 000000000000..3ad944583800 +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-base.c +@@ -0,0 +1,2259 @@ ++/** *************************************************************************** ++ *\file xf-adsp-base.c ++ *\brief Source file for ADSP Base Control layer ++ *\addtogroup ADSP Driver ++ ****************************************************************************** ++ *\date Oct. 21, 2017 ++ *\author Renesas Electronics Corporation ++ ****************************************************************************** ++ *\par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++ ++#include "xf-adsp-base.h" ++ ++#define XF_AUX_POOL_SIZE (16) /**< size of auxiliary pool*/ ++#define XF_AUX_POOL_MSG_LENGTH (256) /**< size of auxiliary buffer */ ++ ++#define XF_PROXY_ALIGN (64) /**< proxy alignment */ ++ ++/** \def XF_ALIGNED(size) ++ * Get properly aligned buffer length ++ */ ++#define XF_ALIGNED(size)\ ++((((size) + XF_PROXY_ALIGN) - 1) & ~(XF_PROXY_ALIGN - 1)) /* PRQA S 3453 */ ++ ++#ifndef offset_of ++/** \def offset_of(type, member) ++ * Return the offset of member in type structuer in byte ++ */ ++#define offset_of(type, member) \ ++ ((int)(long int)&(((const type *)(0))->member)) /* PRQA S 3453 */ ++#endif ++ ++/************************************************* ++ * Variable and and function declaration ++ * **********************************************/ ++ ++/** ADSP base control data */ ++static struct xf_adsp_base *base; ++ ++/* function declaration */ ++static int xf_adsp_base_register_handle(void *private_data, ++ struct xf_callback_func *cb, ++ int comp_id); ++static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id); ++static int xf_adsp_base_free_handle(int handle_id); ++static void xf_adsp_base_init_handle(void); ++static int xf_adsp_base_get_valid_handle(void); ++static int xf_send_and_receive(struct xf_message *msg); ++static int xf_response_thread(void *data); ++static void xf_buffer_put(struct xf_buffer *buffer); ++static u32 xf_buffer_length(struct xf_buffer *b); ++static struct xf_buffer *xf_buffer_get(struct xf_pool *pool); ++static void *xf_buffer_data(struct xf_buffer *b); ++static int xf_adsp_unregister(int comp_id); ++static int xf_adsp_register(char *name, int *comp_id); ++ ++/************************************************* ++ * Helper function to process pool data ++ * **********************************************/ ++ ++/** *********************************************************** ++ * \brief get buffer from given pool ++ * ++ * \param[in] pool Data pool address ++ * \retval b Pointer to buffer address in pool ++ **************************************************************/ ++static struct xf_buffer *xf_buffer_get(struct xf_pool *pool) ++{ ++ struct xf_buffer *b; ++ ++ b = pool->free; ++ if (b) { ++ pool->free = b->link.next; ++ b->link.pool = pool; ++ } ++ return b; ++} ++ ++/*********************************************************** ++ *\brief return buffer back to pool ++ * ++ *\param[in] buffer Pointer to the buffer data ++ ************************************************************/ ++static void xf_buffer_put(struct xf_buffer *buffer) ++{ ++ struct xf_pool *pool = buffer->link.pool; ++ ++ buffer->link.next = pool->free; ++ pool->free = buffer; ++} ++ ++/*********************************************************** ++ *\brief get the address of the given buffer data ++ * ++ *\param[in] b Pointer to the buffer data ++ *\retval address Address of buffer data ++ ************************************************************/ ++static void *xf_buffer_data(struct xf_buffer *b) ++{ ++ return b->address; ++} ++ ++/************************************************************ ++ *\brief get the length of the given buffer data ++ * ++ *\param[in] b Pointer to the buffer data ++ *\retval length Size of buffer data ++ ************************************************************/ ++static u32 xf_buffer_length(struct xf_buffer *b) /* PRQA S 3673 */ ++{ ++ return b->link.pool->length; ++} ++ ++/************************************************************ ++ *\brief set data to the given command message ++ * ++ *\param[out] m Pointer to the command message ++ *\param[in] id Message ID ++ *\param[in] opcode Message opcode ++ *\param[in] length Message length ++ *\param[in] buf Pointer to the buffer data ++ *\param[in] next Pointer to the next message ++ *\retval m Pointer to the command message ++ ************************************************************/ ++static inline struct xf_message * ++xf_create_msg(struct xf_message *m, u32 id, u32 opcode, u32 length, void *buf, ++ struct xf_message *next) ++{ ++ if (m) { ++ m->id = id; ++ m->opcode = opcode; ++ m->length = length; ++ m->buffer = buf; ++ m->next = next; ++ } ++ ++ return m; ++} ++ ++/***************************************************************** ++ *\brief synchronous send and wait for response message from proxy ++ * ++ *\param[in] msg Pointer to the command message ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ ****************************************************************/ ++static int xf_send_and_receive(struct xf_message *msg) ++{ ++ int err; ++ int opcode = msg->opcode; ++ ++ /* reset the base flag */ ++ spin_lock(&base->lock); ++ base->base_flag = FALSE; ++ spin_unlock(&base->lock); ++ ++ err = base->cmd.send(base->client, (void *)msg); ++ if (err != 0) ++ return err; ++ ++ /* sleep and wait for the response wake up event */ ++ if (wait_event_interruptible(base->base_wait, ++ base->base_flag || base->err_flag)) { ++ return -EINVAL; ++ } ++ ++ if (base->err_flag != 0) { ++ spin_lock(&base->lock); ++ base->err_flag = FALSE; ++ spin_unlock(&base->lock); ++ return -EINVAL; ++ } ++ ++ /* save the response message */ ++ /* PRQA S 3200 */ ++ memcpy(msg, &base->base_msg, sizeof(struct xf_message)); ++ ++ /* check if the reponsed message is right */ ++ if (msg->opcode != opcode) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/************************************************************* ++ *\brief send a message to proxy ++ * ++ *\param[in] msg Pointer to the command message ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++static inline int xf_send(struct xf_message *msg) ++{ ++ return base->cmd.send(base->client, (void *)msg); ++} ++ ++/** *********************************************************** ++ *\brief receive message from proxy ++ * ++ *\param[in] msg Pointer to store the response message ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++static inline int xf_receive(struct xf_message *msg) ++{ ++ /* do not wait here */ ++ return base->cmd.recv(base->client, (void *)msg); ++} ++ ++/** *********************************************************** ++ *\brief thread for receive response data ++ **************************************************************/ ++static int xf_response_thread(void *data) ++{ ++ struct xf_message msg; ++ struct xf_handle *handle; ++ int id; ++ ++ /* set polling to wait the response message */ ++ spin_lock(&base->lock); ++ base->wait_flag = FALSE; ++ spin_unlock(&base->lock); ++ ++ while (!kthread_should_stop()) { ++ if (base->cmd.poll(base->client, &base->wait_flag) != 0) ++ continue; ++ ++ if (xf_receive(&msg) != 0) ++ continue; ++ ++ /* get the handle id */ ++ id = XF_AP_CLIENT(msg.id); ++ ++ /* check the destination of the response message */ ++ if (id == 0) { ++ /* message is from base control */ ++ /* PRQA S 3200 1*/ ++ memcpy(&base->base_msg, &msg, ++ sizeof(struct xf_message)); ++ ++ spin_lock(&base->lock); ++ base->base_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ wake_up(&base->base_wait); ++ continue; ++ } ++ ++ /* get handle data */ ++ handle = xf_adsp_base_get_handle(id); ++ ++ if (handle == 0) ++ continue; ++ ++ switch (msg.opcode) { ++ case XF_EMPTY_THIS_BUFFER: /* PRQA S 0594 */ ++ handle->cb->empty_buf_done(handle->private_data, ++ msg.opcode, ++ msg.length, ++ msg.buffer); ++ break; ++ case XF_FILL_THIS_BUFFER: /* PRQA S 0594 */ ++ handle->cb->fill_buf_done(handle->private_data, ++ msg.opcode, ++ msg.length, ++ msg.buffer); ++ break; ++ case XF_SET_PARAM: /* PRQA S 0594 4 */ ++ case XF_GET_PARAM: ++ case XF_ROUTE: ++ case XF_UNROUTE: ++ /* message is from base control */ ++ memcpy(&base->base_msg, &msg, ++ sizeof(struct xf_message)); /* PRQA S 3200 */ ++ ++ spin_lock(&base->lock); ++ base->base_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ wake_up(&base->base_wait); ++ break; ++ default: ++ /* error has occurred */ ++ handle->cb->event_handler(handle->private_data); ++ ++ xf_adsp_base_free_handle(id); /* PRQA S 3200 */ ++ ++ spin_lock(&base->lock); ++ base->err_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ wake_up(&base->base_wait); ++ break; ++ } ++ } ++ ++ pr_info("ADSP base thread was exited\n"); ++ ++ do_exit(0); ++ return 0; ++} ++ ++/************************************************************* ++ * \brief register component to ADSP ++ * ++ * \param[in] name Name string of component ++ * \param[out] comp_id Store the registered component ID ++ * \retval 0 Success ++ * \retval -EINVAL Failed ++ **************************************************************/ ++static int xf_adsp_register(char *name, int *comp_id) /* PRQA S 3673 */ ++{ ++ struct xf_message msg; ++ struct xf_buffer *b = xf_buffer_get(base->aux_pool); ++ int err = 0; ++ ++ msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); ++ msg.opcode = XF_REGISTER; ++ msg.length = strlen(name) + 1; ++ msg.buffer = xf_buffer_data(b); ++ ++ /* copy identify name of ADSP component */ ++ if (msg.length <= xf_buffer_length(b)) ++ strncpy(msg.buffer, name, msg.length); /* PRQA S 3200 */ ++ else ++ strncpy(msg.buffer, name, xf_buffer_length(b));/* PRQA S 3200 */ ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the registered component ID */ ++ *comp_id = XF_MSG_SRC(msg.id); ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ * \brief unregister component from ADSP ++ * \param[in] comp_id Registered component ID ++ * \retval 0 Success ++ * \retval -EINVAL Failed ++ **************************************************************/ ++static int xf_adsp_unregister(int comp_id) ++{ ++ struct xf_message msg; ++ ++ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), comp_id), ++ XF_UNREGISTER, 0, NULL, NULL); /* PRQA S 3200 */ ++ ++ return xf_send_and_receive(&msg); ++} ++ ++/*************************************************************** ++ * APIs for ADSP component helper ++ * ************************************************************/ ++/** *********************************************************** ++ * \brief allocate memory pool from shared memory ++ * \param[in] pool_size Number of buffer need to allocate ++ * \param[in] buf_length Size of each buffer in bytes ++ * \retval pool Pointer to allocated pool ++ * \retval -EINVAL Invalid base data ++ * \retval -ENOMEM Out of memory resource ++ **************************************************************/ ++struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length) ++{ ++ void *data; ++ u32 number; ++ struct xf_buffer *b; ++ struct xf_message msg; ++ struct xf_pool *pool; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return ERR_PTR(-EINVAL); /* PRQA S 0306 */ ++ ++ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), ++ XF_ALLOC, ++ buf_length * pool_size, NULL, NULL); /* PRQA S 3200 */ ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ ++ ++ /* PRQA S 0306 1 */ ++ pool = kmalloc(offset_of(struct xf_pool, buffer) + ++ (pool_size * sizeof(struct xf_buffer)), GFP_KERNEL); ++ ++ if (!pool) ++ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ ++ ++ pool->length = buf_length; ++ pool->number = pool_size; ++ pool->p = msg.buffer; ++ ++ number = pool_size; ++ for (pool->free = b = &pool->buffer[0], data = pool->p; ++ number > 0; number--, b++) { /* PRQA S 2462,3418,0489 */ ++ /* set address of the buffer */ ++ b->address = data; ++ ++ /* fill buffer into free list */ ++ if (number == 1) ++ b->link.next = NULL; ++ else ++ b->link.next = b + 1; /* PRQA S 0489 */ ++ ++ /* advance data pointer in contigous buffer */ ++ data += buf_length; /* PRQA S 0550 */ ++ } ++ ++ return pool; ++} ++ ++/** *********************************************************** ++ *\brief return memory to shared memory ++ *\param[in] pool Data pool address ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or pool data ++ **************************************************************/ ++int xf_adsp_free_mem_pool(struct xf_pool *pool) ++{ ++ struct xf_message msg; ++ ++ /* check the sane ADSP base pool data*/ ++ if (!base || !pool) ++ return -EINVAL; ++ ++ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), ++ XF_FREE, pool->number * pool->length, ++ pool->p, NULL); /* PRQA S 3200 */ ++ ++ xf_send_and_receive(&msg); /* PRQA S 3200 */ ++ ++ kfree(pool); ++ ++ return 0; ++} ++ ++/** *********************************************************** ++ *\brief get buffer from given pool ++ * ++ *\param[in] pool Data pool address ++ *\param[in] index Buffer index ++ *\retval b Pointer to buffer address in pool ++ *\retval -EINVAL Invalid pool or index ++ **************************************************************/ ++char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index) ++{ ++ struct xf_buffer *buf[XF_BUF_POOL_SIZE] = {0}; ++ char *data; ++ int i; ++ ++ /* check the sane pool data*/ ++ if (!pool) ++ return ERR_PTR(-EINVAL); /* PRQA S 306 */ ++ ++ /* check the index is valid */ ++ if (index > (pool->number - 1)) ++ return ERR_PTR(-EINVAL); /* PRQA S 306 */ ++ ++ /* get buffer from pool */ ++ for (i = 0; i <= index; i++) ++ buf[i] = xf_buffer_get(pool); ++ ++ /* get data from buffer */ ++ data = xf_buffer_data(buf[index]); ++ ++ /* return buffer to pool */ ++ for (i = index; i >= 0; i--) ++ xf_buffer_put(buf[i]); ++ ++ return data; ++} ++ ++/** *********************************************************** ++ *\brief send empty this buffer command to ADSP framework ++ * ++ *\param[in] handle_id ID of the registered handle ++ *\param[in] buffer Pointer to data buffer ++ *\param[in] length Size of buffer in bytes ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length) ++{ ++ struct xf_message msg; ++ struct xf_handle *handle; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ /* submit message to port 0 of component */ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_EMPTY_THIS_BUFFER, length, buffer, NULL); ++ ++ xf_send(&msg); /* PRQA S 3200 */ ++ ++ return 0; ++} ++ ++/** *********************************************************** ++ *\brief send fill this buffer command to ADSP framework ++ * ++ *\param[in] handle_id ID of the registered handle ++ *\param[in] buffer Pointer to data buffer ++ *\param[in] length Size of buffer in bytes ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length) ++{ ++ struct xf_message msg; ++ struct xf_handle *handle; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ /* submit message to port 1 of component */ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 1)), ++ XF_FILL_THIS_BUFFER, length, buffer, NULL); ++ ++ xf_send(&msg); /* PRQA S 3200 */ ++ ++ return 0; ++} ++ ++/** *********************************************************** ++ *\brief route data between two registered ADSP plugins ++ * ++ *\param[in] src_handle_id Handle ID of source plugin ++ *\param[in] dst_handle_id Handle ID of sink plugin ++ *\param[in] buf_cnt Number of buffer in tunnel ++ *\param[in] buf_size Size of each buffer in tunnel ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int ++xf_adsp_route(int src_handle_id, int dst_handle_id, int buf_cnt, int buf_size) ++{ ++ struct xf_route_port_msg *route_msg; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ struct xf_handle *dst_handle, *src_handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ /* get handle data */ ++ dst_handle = xf_adsp_base_get_handle(dst_handle_id); ++ src_handle = xf_adsp_base_get_handle(src_handle_id); ++ ++ if (!dst_handle || !src_handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ route_msg = xf_buffer_data(b); ++ ++ /* route information */ ++ route_msg->dst = __XF_PORT_SPEC2(dst_handle->comp_id, 0); ++ route_msg->alloc_align = 4; ++ route_msg->alloc_number = buf_cnt; ++ route_msg->alloc_size = buf_size; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, src_handle_id), ++ __XF_PORT_SPEC2(src_handle->comp_id, 1)), ++ XF_ROUTE, sizeof(*route_msg), route_msg, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief set a single parameter ++ * ++ *\param[in] handle_id ID of registered handle ++ *\param[in] index Sub-command index of parameter ++ *\param[in] value the setting value ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_set_param(int handle_id, int index, int value) ++{ ++ struct xf_message msg; ++ struct xf_buffer *b; ++ struct xf_set_param_msg *msg_params; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ msg_params->item[0].id = index; ++ msg_params->item[0].value = value; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(1), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get a single parameter ++ * ++ *\param[in] handle_id ID of registered handle ++ *\param[in] index Sub-command index of parameter ++ *\param[out] value Store the getting value ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_get_param(int handle_id, int index, int *value) ++{ ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base and value data */ ++ if (!base || !value) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ msg_params->c.id[0] = index; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(1), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ *value = msg_params->r.value[0]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/*************************************************** ++ * APIs for ADSP base control ++ * ************************************************/ ++ ++/** *********************************************************** ++ *\brief initialize ADSP base's instance ++ * ++ *\retval 0 Success ++ *\retval -EINVAL ADSP base's instance has been initialized ++ *\retval -ENOMEM Cannot allocate memory for ADSP base ++ *\retval -EBUSY Cannot register client to proxy ++ **************************************************************/ ++int xf_adsp_base_create(struct xf_adsp_base_cmd *cmd) ++{ ++ int err = 0; ++ ++ if (base != 0) ++ return -EINVAL; ++ ++ if (!cmd || !cmd->recv || !cmd->send || !cmd->poll || ++ !cmd->client_register || !cmd->client_unregister) ++ return -EINVAL; ++ ++ base = kmalloc(sizeof(*base), GFP_KERNEL); ++ if (!base) ++ return -ENOMEM; ++ ++ memset(base, 0, sizeof(struct xf_adsp_base)); /* PRQA S 3200 */ ++ ++ /* store the proxy command */ ++ memcpy(&base->cmd, cmd, sizeof(struct xf_adsp_base_cmd)); ++ ++ /* create client to connect from proxy driver */ ++ err = base->cmd.client_register(&base->client); ++ if (err != 0) ++ goto err3; /* PRQA S 2001 */ ++ ++ /* initialize waiting queue */ ++ init_waitqueue_head(&base->base_wait); ++ ++ /* initialize handle */ ++ xf_adsp_base_init_handle(); ++ ++ /* create thread to get the responsed message from proxy */ ++ base->rsp_thread = kthread_run(&xf_response_thread, ++ (void *)base, "adsp base"); ++ ++ if (base->rsp_thread != 0) { ++ pr_info("ADSP base thread has been started.\n"); ++ } else { ++ pr_info("Failed in create base thread\n"); ++ err = -ENOMEM; ++ goto err2; /* PRQA S 2001 */ ++ } ++ ++ /* allocate auxiliary pool for component usage */ ++ base->aux_pool = xf_adsp_allocate_mem_pool( ++ XF_AUX_POOL_SIZE, ++ XF_ALIGNED(XF_AUX_POOL_MSG_LENGTH)); ++ ++ if (IS_ERR(base->aux_pool)) { /* PRQA S 306 */ ++ err = -ENOMEM; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ pr_info("ADSP base was created\n"); ++ return 0; ++ ++err1: ++ /* cancel the waitting queue */ ++ spin_lock(&base->lock); ++ base->wait_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ /* stop thread inadvance */ ++ kthread_stop(base->rsp_thread); ++ ++err2: ++ base->cmd.client_unregister(base->client); ++ ++err3: ++ kfree(base); ++ base = NULL; ++ ++ return err; ++} ++EXPORT_SYMBOL(xf_adsp_base_create); /* PRQA S 0651 */ ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP base's instance ++ * ++ *\retval 0 Success ++ *\retval -EINVAL Invalid ADSP base's instance ++ **************************************************************/ ++int xf_adsp_base_destroy(void) ++{ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ /* free auxiliary pool to shared memory */ ++ xf_adsp_free_mem_pool(base->aux_pool); /* PRQA S 3200 */ ++ ++ /* cancel wait the response message, go to stop process */ ++ spin_lock(&base->lock); ++ base->wait_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ /* stop response thread */ ++ kthread_stop(base->rsp_thread); ++ ++ /* unregister client */ ++ base->cmd.client_unregister(base->client); ++ ++ kfree(base); ++ base = NULL; ++ ++ pr_info("ADSP base was destroyed\n"); ++ return 0; ++} ++EXPORT_SYMBOL(xf_adsp_base_destroy); /* PRQA S 0651 */ ++ ++/** *********************************************************** ++ * \brief initialize handle instance ++ **************************************************************/ ++static inline void xf_adsp_base_init_handle(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_HANDLE; i++) ++ base->handle[i] = NULL; ++} ++ ++/** *********************************************************** ++ *\brief get the next available handle ID for register ++ * ++ *\retval -1 Unavailable handle ID ++ *\retval 0 to 255 Available handle ID ++ **************************************************************/ ++static inline int xf_adsp_base_get_valid_handle(void) ++{ ++ int id = -1; ++ int i; ++ ++ for (i = 0; i < MAX_HANDLE; i++) { ++ /* get the id of the first available handler */ ++ if (!base->handle[i]) { ++ id = i; ++ break; ++ } ++ } ++ ++ return id; ++} ++ ++/** *********************************************************** ++ *\brief register a handle instance for component usage ++ * ++ *\param[in] private_data Private data of this component ++ *\param[in] cb Callback function ++ *\param[in] comp_id ID of register component ++ *\retval id ID of registered handle ++ *\retval -EINVAL Cannot get the handle instance ++ *\retval -ENOMEM Cannot allocate handle memory ++ **************************************************************/ ++static int xf_adsp_base_register_handle(void *private_data, ++ struct xf_callback_func *cb, ++ int comp_id) ++{ ++ struct xf_handle *handle; ++ int id; ++ ++ /* get the next handle id */ ++ id = xf_adsp_base_get_valid_handle(); ++ ++ /* check available handle in base */ ++ if (id < 0) ++ return -EINVAL; ++ ++ /* allocate handle data */ ++ handle = kmalloc(sizeof(*handle), GFP_KERNEL); ++ if (!handle) ++ return -ENOMEM; ++ ++ /* save handle data */ ++ handle->private_data = private_data; ++ handle->cb = cb; ++ handle->comp_id = comp_id; ++ ++ /* save the hanle data */ ++ base->handle[id] = handle; ++ ++ /* return the id numbering in base handle */ ++ return (id + 1); ++} ++ ++/** *********************************************************** ++ *\brief get handle instance from handle ID ++ * ++ *\param[in] handle_id ID of registered handle ++ *\retval handle Pointer to handle instance ++ **************************************************************/ ++static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id) ++{ ++ return base->handle[handle_id - 1]; ++} ++ ++/** *********************************************************** ++ *\brief free the registered handle instance ++ * ++ *\param[in] handle_id ID of registered handle ++ *\retval 0 Success ++ *\retval -EINVAL Invalid handle ID ++ **************************************************************/ ++static int xf_adsp_base_free_handle(int handle_id) ++{ ++ if (handle_id < 1 || handle_id > MAX_HANDLE) ++ return -EINVAL; ++ ++ kfree(base->handle[handle_id - 1]); ++ base->handle[handle_id - 1] = NULL; ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for Renderer component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP Renderer parameters ++ * ++ *\param[in] renderer Pointer to Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_renderer_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !renderer) ++ return -EINVAL; ++ ++ params = &renderer->params; ++ ++ /* get Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_CHANNELS; ++ msg_params->item[i++].value = params->channel; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; ++ msg_params->item[i++].value = params->out_channel; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_MIX_CONTROL; ++ msg_params->item[i++].value = params->mix_ctrl; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_STATE; ++ msg_params->item[i++].value = params->state; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP Renderer parameters ++ * ++ *\param[in] renderer Pointer to Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 */ ++int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer) ++{ ++ struct xf_adsp_renderer_params *rdr_params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !renderer) ++ return -EINVAL; ++ ++ rdr_params = &renderer->params; ++ ++ /* get Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 13 1*/ ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_CHANNELS; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_MIX_CONTROL; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_STATE; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ rdr_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ ++ rdr_params->channel = msg_params->r.value[i++]; ++ rdr_params->pcm_width = msg_params->r.value[i++]; ++ rdr_params->frame_size = msg_params->r.value[i++]; ++ rdr_params->dev1 = msg_params->r.value[i++]; ++ rdr_params->dev2 = msg_params->r.value[i++]; ++ rdr_params->dma1 = msg_params->r.value[i++]; ++ rdr_params->dma2 = msg_params->r.value[i++]; ++ rdr_params->out_rate = msg_params->r.value[i++]; ++ rdr_params->vol_rate = msg_params->r.value[i++]; ++ rdr_params->out_channel = msg_params->r.value[i++]; ++ rdr_params->mix_ctrl = msg_params->r.value[i++]; ++ rdr_params->state = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create Renderer component ++ * ++ *\param[in,out] renderer Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Renderer instance ++ *****************************************************************************/ ++int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_renderer *rdr; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ rdr = kmalloc(sizeof(*rdr), GFP_KERNEL); ++ if (!rdr) ++ return -ENOMEM; ++ ++ memset(rdr, 0, sizeof(struct xf_adsp_renderer)); /* PRQA S 3200 */ ++ ++ /* register renderer component */ ++ err = xf_adsp_register("renderer", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register Renderer to ADSP base control */ ++ rdr->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (rdr->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from Renderer plugin */ ++ err = xf_adsp_renderer_get_params(rdr); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save renderer compoent data */ ++ *renderer = rdr; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(rdr); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP Renderer component ++ * ++ *\param[in] renderer Pointer to Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Renderer data ++ **************************************************************/ ++/* PRQA S 3673 */ ++int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !renderer) ++ return -EINVAL; ++ ++ handle_id = renderer->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(renderer); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for Capture component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP Capture parameters ++ * ++ *\param[in] capture Pointer to Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_capture_set_params(struct xf_adsp_capture *capture) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_capture_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !capture) ++ return -EINVAL; ++ ++ params = &capture->params; ++ ++ /* get Capture's handle data */ ++ handle = xf_adsp_base_get_handle(capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_CHANNELS; ++ msg_params->item[i++].value = params->channel; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_STATE; ++ msg_params->item[i++].value = params->state; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP Capture parameters ++ * ++ *\param[in] capture Pointer to Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 */ ++int xf_adsp_capture_get_params(struct xf_adsp_capture *capture) ++{ ++ struct xf_adsp_capture_params *cap_params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !capture) ++ return -EINVAL; ++ ++ cap_params = &capture->params; ++ ++ /* get Capture's handle data */ ++ handle = xf_adsp_base_get_handle(capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 11 1*/ ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_CHANNELS; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_STATE; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ cap_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 11 */ ++ cap_params->channel = msg_params->r.value[i++]; ++ cap_params->pcm_width = msg_params->r.value[i++]; ++ cap_params->frame_size = msg_params->r.value[i++]; ++ cap_params->dev1 = msg_params->r.value[i++]; ++ cap_params->dev2 = msg_params->r.value[i++]; ++ cap_params->dma1 = msg_params->r.value[i++]; ++ cap_params->dma2 = msg_params->r.value[i++]; ++ cap_params->out_rate = msg_params->r.value[i++]; ++ cap_params->vol_rate = msg_params->r.value[i++]; ++ cap_params->state = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create Capture component ++ * ++ *\param[in,out] capture Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Capture instance ++ *****************************************************************************/ ++int xf_adsp_capture_create(struct xf_adsp_capture **capture, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_capture *cap; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ cap = kmalloc(sizeof(*cap), GFP_KERNEL); ++ if (!cap) ++ return -ENOMEM; ++ ++ memset(cap, 0, sizeof(struct xf_adsp_capture)); /* PRQA S 3200 */ ++ ++ /* register capture component */ ++ err = xf_adsp_register("capture", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register capture to ADSP base control */ ++ cap->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (cap->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from capture plugin */ ++ err = xf_adsp_capture_get_params(cap); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save capture compoent data */ ++ *capture = cap; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(cap); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP Capture component ++ * ++ *\param[in] capture Pointer to Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Capture data ++ **************************************************************/ ++int xf_adsp_capture_destroy(struct xf_adsp_capture *capture) /* PRQA S 3673 */ ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !capture) ++ return -EINVAL; ++ ++ handle_id = capture->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(capture); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for Equalizer component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP Equalizer parameters ++ * ++ *\param[in] equalizer Pointer to Equalizer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_equalizer_params *params; ++ struct xf_buffer *b; ++ int i, n; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !equalizer) ++ return -EINVAL; ++ ++ params = &equalizer->params; ++ ++ /* get Equalizer's handle data */ ++ handle = xf_adsp_base_get_handle(equalizer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_COEF_FS; ++ msg_params->item[i++].value = params->rate; ++ ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_CH; ++ msg_params->item[i++].value = params->channel; ++ ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; ++ msg_params->item[i++].value = params->eqz_type; ++ ++ if (params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { ++ struct xf_equalizer_parametric_coef *coef = ¶ms->p_coef; ++ ++ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; ++ msg_params->item[i++].value = coef->type[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; ++ msg_params->item[i++].value = coef->fc[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; ++ msg_params->item[i++].value = coef->band_width[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; ++ msg_params->item[i++].value = coef->gain[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; ++ msg_params->item[i++].value = coef->gain_base[n]; ++ } ++ } else { ++ struct xf_equalizer_graphic_coef *coef = ¶ms->g_coef; ++ ++ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; ++ msg_params->item[i++].value = coef->gain_g[n]; ++ } ++ } ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP Equalizer parameters ++ * ++ *\param[in] equalizer Pointer to Equalizer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 1*/ ++int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer) ++{ ++ struct xf_adsp_equalizer_params *eqz_params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i, n; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !equalizer) ++ return -EINVAL; ++ ++ eqz_params = &equalizer->params; ++ ++ /* get Equalizer's handle data */ ++ handle = xf_adsp_base_get_handle(equalizer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_COEF_FS; /* PRQA S 3440 4 */ ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_CH; ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; ++ ++ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { ++ /* PRQA S 3440 5 */ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; ++ } ++ ++ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) ++ /* PRQA S 3440 1 */ ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ eqz_params->rate = msg_params->r.value[i++]; /* PRQA S 3440 4 */ ++ eqz_params->channel = msg_params->r.value[i++]; ++ eqz_params->pcm_width = msg_params->r.value[i++]; ++ eqz_params->eqz_type = msg_params->r.value[i++]; ++ ++ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { ++ /* PRQA S 3440 5 */ ++ eqz_params->p_coef.type[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.fc[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.band_width[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.gain[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.gain_base[n] = msg_params->r.value[i++]; ++ } ++ ++ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { ++ /* PRQA S 3440 1 */ ++ eqz_params->g_coef.gain_g[n] = msg_params->r.value[i++]; ++ } ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create Equalizer component ++ * ++ *\param[in,out] equalizer Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Equalier instance ++ *****************************************************************************/ ++int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_equalizer *eqz; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ eqz = kmalloc(sizeof(*eqz), GFP_KERNEL); ++ if (!eqz) ++ return -ENOMEM; ++ ++ memset(eqz, 0, sizeof(struct xf_adsp_equalizer)); /* PRQA S 3200 */ ++ ++ /* register equalizer component */ ++ err = xf_adsp_register("equalizer", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register equalizer to ADSP base control */ ++ eqz->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (eqz->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from equalizer plugin */ ++ err = xf_adsp_equalizer_get_params(eqz); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save equalizer compoent data */ ++ *equalizer = eqz; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(eqz); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP Equalizer component ++ * ++ *\param[in] equalizer Pointer to Equalizer component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Equalizer data ++ **************************************************************/ ++/* PRQA S 3673 */ ++int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base and Equalizer data */ ++ if (!base || !equalizer) ++ return -EINVAL; ++ ++ handle_id = equalizer->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(equalizer); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for TDM Renderer component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP TDM Renderer parameters ++ * ++ *\param[in] tdm_renderer Pointer to TDM Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_tdm_renderer_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_renderer) ++ return -EINVAL; ++ ++ params = &tdm_renderer->params; ++ ++ /* get TDM Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->item[i++].value = params->ch_mode; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP TDM Renderer parameters ++ * ++ *\param[in] tdm_renderer Pointer to TDM Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 1*/ ++int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer) ++{ ++ struct xf_adsp_tdm_renderer_params *params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_renderer) ++ return -EINVAL; ++ ++ params = &tdm_renderer->params; ++ ++ /* get TDM Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 13 1*/ ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ ++ params->ch_mode = msg_params->r.value[i++]; ++ params->pcm_width = msg_params->r.value[i++]; ++ params->frame_size = msg_params->r.value[i++]; ++ params->dev1 = msg_params->r.value[i++]; ++ params->dev2 = msg_params->r.value[i++]; ++ params->dma1 = msg_params->r.value[i++]; ++ params->dma2 = msg_params->r.value[i++]; ++ params->out_rate = msg_params->r.value[i++]; ++ params->vol_rate = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create TDM Renderer component ++ * ++ *\param[in,out] tdm_renderer Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Renderer instance ++ *****************************************************************************/ ++int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer, ++ struct xf_callback_func *cb, ++ void *private_data) ++{ ++ struct xf_adsp_tdm_renderer *tdm_rdr; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ tdm_rdr = kmalloc(sizeof(*tdm_rdr), GFP_KERNEL); ++ if (!tdm_rdr) ++ return -ENOMEM; ++ ++ /* PRQA S 3200 */ ++ memset(tdm_rdr, 0, sizeof(struct xf_adsp_tdm_renderer)); ++ ++ /* register TDM Renderer component */ ++ err = xf_adsp_register("tdm-renderer", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register TDM Renderer to ADSP base control */ ++ tdm_rdr->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (tdm_rdr->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from plugin */ ++ err = xf_adsp_tdm_renderer_get_params(tdm_rdr); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save compoent data */ ++ *tdm_renderer = tdm_rdr; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(tdm_rdr); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP TDM Renderer component ++ * ++ *\param[in] tdm_renderer Pointer to TDM Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Renderer data ++ **************************************************************/ ++/* PRQA S 3673 1*/ ++int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_renderer) ++ return -EINVAL; ++ ++ handle_id = tdm_renderer->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(tdm_renderer); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for TDM Capture component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP TDM Capture parameters ++ * ++ *\param[in] tdm_capture Pointer to TDM Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_tdm_capture_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_capture) ++ return -EINVAL; ++ ++ params = &tdm_capture->params; ++ ++ /* get TDM Capture's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->item[i++].value = params->ch_mode; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP TDM Capture parameters ++ * ++ *\param[in] tdm_capture Pointer to TDM Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 1*/ ++int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture) ++{ ++ struct xf_adsp_tdm_capture_params *params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_capture) ++ return -EINVAL; ++ ++ params = &tdm_capture->params; ++ ++ /* get TDM Capture's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 13 1*/ ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ ++ params->ch_mode = msg_params->r.value[i++]; ++ params->pcm_width = msg_params->r.value[i++]; ++ params->frame_size = msg_params->r.value[i++]; ++ params->dev1 = msg_params->r.value[i++]; ++ params->dev2 = msg_params->r.value[i++]; ++ params->dma1 = msg_params->r.value[i++]; ++ params->dma2 = msg_params->r.value[i++]; ++ params->out_rate = msg_params->r.value[i++]; ++ params->vol_rate = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create TDM Capture component ++ * ++ *\param[in,out] tdm_capture Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Renderer instance ++ *****************************************************************************/ ++int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_tdm_capture *tdm_cap; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ tdm_cap = kmalloc(sizeof(*tdm_cap), GFP_KERNEL); ++ if (!tdm_cap) ++ return -ENOMEM; ++ ++ /* PRQA S 3200 */ ++ memset(tdm_cap, 0, sizeof(struct xf_adsp_tdm_capture)); ++ ++ /* register TDM Capture component */ ++ err = xf_adsp_register("tdm-capture", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register TDM Capture to ADSP base control */ ++ tdm_cap->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (tdm_cap->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from plugin */ ++ err = xf_adsp_tdm_capture_get_params(tdm_cap); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save compoent data */ ++ *tdm_capture = tdm_cap; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(tdm_cap); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP TDM Capture component ++ * ++ *\param[in] tdm_capture Pointer to TDM Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Renderer data ++ **************************************************************/ ++/* PRQA S 3673 */ ++int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_capture) ++ return -EINVAL; ++ ++ handle_id = tdm_capture->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(tdm_capture); ++ ++ return 0; ++} +diff --git a/sound/soc/adsp/xf-adsp-base.h b/sound/soc/adsp/xf-adsp-base.h +new file mode 100644 +index 000000000000..27eb084a99a5 +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-base.h +@@ -0,0 +1,275 @@ ++/** ************************************************************************* ++ *\file xf-adsp-base.h ++ *\brief Header file for ADSP Base Control layer ++ *\addtogroup ADSP Driver ++ **************************************************************************** ++ *\date Oct. 21, 2017 ++ *\author Renesas Electronics Corporation ++ **************************************************************************** ++ *\par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#ifndef __XF_ADSP_BASE_H ++#define __XF_ADSP_BASE_H ++ ++#include "xf-adsp-config.h" ++#include ++ ++#define XF_BUF_POOL_SIZE (4) /**< number of buffer in a data pool */ ++ ++/**< maximum number of DSP component can be registered */ ++#define MAX_HANDLE (256) ++ ++/* define boolean */ ++#define TRUE (1) ++#define FALSE (0) ++ ++/** \struct xf_callback_func ++ * \brief callback function for ADSP's response message ++ */ ++struct xf_callback_func { ++ /** callback for empty buffer done message */ ++ int (*empty_buf_done)(void *data, int opcode, int length, char *buffer); ++ ++ /** callback for fill buffer done message */ ++ int (*fill_buf_done)(void *data, int opcode, int length, char *buffer); ++ ++ /** callback for event handler */ ++ int (*event_handler)(void *data); ++}; ++ ++/** \struct xf_adsp_renderer_params ++ * \brief parameter structure for Renderer component ++ */ ++struct xf_adsp_renderer_params { ++ int channel; /**< channel number */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++ int out_channel; /**< output channels */ ++ int mix_ctrl; /**< mix control flag */ ++ int state; /**< operation state */ ++}; ++ ++/** \struct xf_adsp_renderer ++ * \brief Renderer component structure ++ */ ++struct xf_adsp_renderer { ++ struct xf_adsp_renderer_params params; /**< parameter structure*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle*/ ++}; ++ ++/** \struct xf_adsp_capture_params ++ *\brief parameter structure of Capture component ++ */ ++struct xf_adsp_capture_params { ++ int channel; /**< channel number */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++ int state; /**< operation state */ ++}; ++ ++/** \struct xf_adsp_capture ++ * \brief Capture component structure ++ */ ++struct xf_adsp_capture { ++ struct xf_adsp_capture_params params; /**< parameter structuer*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle*/ ++}; ++ ++/** \struct xf_equalizer_parametric_coef ++ *\brief Parametric Equalizer type's parameters ++ */ ++struct xf_equalizer_parametric_coef { ++ int type[XA_REL_EQZ_FILTER_NUM]; /**< Filter type */ ++ int fc[XA_REL_EQZ_FILTER_NUM]; /**< Filter center frequency */ ++ int gain[XA_REL_EQZ_FILTER_NUM]; /**< Filter gain */ ++ int band_width[XA_REL_EQZ_FILTER_NUM]; /**< Filter band width */ ++ int gain_base[XA_REL_EQZ_FILTER_NUM]; /**< Filter base gain */ ++}; ++ ++/** \struct xf_equalizer_graphic_coef ++ * \brief Graphic Equalizer type's parameters ++ */ ++struct xf_equalizer_graphic_coef { ++ int gain_g[XA_REL_EQZ_GRAPHIC_BAND_NUM];/**< Graphic equalizer gain */ ++}; ++ ++/** \struct xf_adsp_equalizer_params ++ *\brief Equalizer parameters ++ */ ++struct xf_adsp_equalizer_params { ++ int channel; /**< channel number */ ++ int pcm_width; /**< PCM width */ ++ int rate; /**< sampling rate */ ++ int eqz_type; /**< Equalizer type */ ++ struct xf_equalizer_parametric_coef p_coef; /**< Parametric params */ ++ struct xf_equalizer_graphic_coef g_coef; /**< Graphic params */ ++}; ++ ++/** \struct xf_adsp_equalizer ++ * \brief Equalizer component's structure ++ */ ++struct xf_adsp_equalizer { ++ struct xf_adsp_equalizer_params params;/**< Equalizer parameters */ ++ struct xf_pool *buf_pool; /**< buffer pool for transfer data */ ++ int handle_id; /**< ID of registered handle */ ++}; ++ ++/** \struct xf_adsp_tdm_renderer_params ++ * \brief parameter structure for TDM Renderer component ++ */ ++struct xf_adsp_tdm_renderer_params { ++ int ch_mode; /**< channel mode */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++}; ++ ++/** \struct xf_adsp_tdm_renderer ++ * \brief TDM Renderer component structure ++ */ ++struct xf_adsp_tdm_renderer { ++ struct xf_adsp_tdm_renderer_params params; /**< parameter structure*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle */ ++}; ++ ++/** \struct xf_adsp_tdm_capture_params ++ * \brief parameter structure for TDM Capture component ++ */ ++struct xf_adsp_tdm_capture_params { ++ int ch_mode; /**< channel mode */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++}; ++ ++/** \struct xf_adsp_tdm_capture ++ * \brief TDM Capture component structure ++ */ ++struct xf_adsp_tdm_capture { ++ struct xf_adsp_tdm_capture_params params; /**< parameter structure*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle*/ ++}; ++ ++/** \struct xf_handle ++ * \brief Handle struct for each ADSP component ++ */ ++struct xf_handle { ++ int comp_id;/**< ADSP component ID */ ++ struct xf_callback_func *cb;/**< callback functions */ ++ void *private_data; /**< private data for callback functions*/ ++}; ++ ++/** \struct xf_adsp_base ++ * \brief Base component structure ++ */ ++struct xf_adsp_base { ++ struct xf_adsp_base_cmd cmd; /**< proxy commands */ ++ void *client; /**< client data which registered to proxy */ ++ struct xf_pool *aux_pool; /**< auxiliary buffer pool data */ ++ struct xf_handle *handle[MAX_HANDLE]; /**< handler data */ ++ struct task_struct *rsp_thread;/**< thread for response message*/ ++ wait_queue_head_t base_wait; /**< ADSP base's waiting queue */ ++ struct xf_message base_msg; /**< ADSP base's response message */ ++ int base_flag; /**< flag to control its waiting queue */ ++ int err_flag; /**< flag to indicate a error from plugins */ ++ int wait_flag; /**< flag to control the polling waiting*/ ++ spinlock_t lock; /**< spinlock data */ ++}; ++ ++struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length); ++int xf_adsp_free_mem_pool(struct xf_pool *pool); ++char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index); ++ ++int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length); ++int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length); ++ ++int xf_adsp_route(int src_handle_id, int dst_handle_id ++ , int buf_cnt, int buf_size); ++ ++int xf_adsp_set_param(int handle_id, int index, int value); ++int xf_adsp_get_param(int handle_id, int index, int *value); ++ ++int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer, ++ struct xf_callback_func *cb, void *private_data); ++int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer); ++int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer); ++int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer); ++ ++int xf_adsp_capture_create(struct xf_adsp_capture **capture, ++ struct xf_callback_func *cb, void *private_data); ++int xf_adsp_capture_destroy(struct xf_adsp_capture *capture); ++int xf_adsp_capture_set_params(struct xf_adsp_capture *capture); ++int xf_adsp_capture_get_params(struct xf_adsp_capture *capture); ++ ++int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer, ++ struct xf_callback_func *cb, void *private_data); ++int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer); ++int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer); ++int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer); ++ ++int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer, ++ struct xf_callback_func *cb, ++ void *private_data); ++int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer); ++int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer); ++int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer); ++ ++int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture, ++ struct xf_callback_func *cb, ++ void *private_data); ++int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture); ++int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture); ++int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture); ++ ++#endif +diff --git a/sound/soc/adsp/xf-adsp-config.h b/sound/soc/adsp/xf-adsp-config.h +new file mode 100644 +index 000000000000..818a46a66600 +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-config.h +@@ -0,0 +1,604 @@ ++/** **************************************************************************** ++ *\file xf-adsp-config.h ++ *\brief Header file for ADSP configuration ++ *\addtogroup ADSP Driver ++ ******************************************************************************* ++ *\date Oct. 21, 2017 ++ *\author Renesas Electronics Corporation ++ ******************************************************************************* ++ *\par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#ifndef __XF_ADSP_CONFIG_H ++#define __XF_ADSP_CONFIG_H ++ ++/* Equalizer definition */ ++#define XA_REL_EQZ_FILTER_NUM (9) /**< number of filter */ ++#define XA_REL_EQZ_GRAPHIC_BAND_NUM (5) /**< number of graphic band */ ++ ++struct xf_buffer { ++ void *address; ++ union { /* PRQA S 750 3 */ ++ struct xf_buffer *next; ++ struct xf_pool *pool; ++ } link; ++}; ++ ++struct xf_pool { ++ /* length of individual buffer in a pool */ ++ u32 length; ++ ++ /* number of buffer in a pool */ ++ u32 number; ++ ++ /* pointer to pool memory */ ++ void *p; ++ ++ /* pointer to first free buffer in a pool */ ++ struct xf_buffer *free; ++ ++ /* individual buffer */ ++ struct xf_buffer buffer[0]; /* PRQA S 1037 */ ++}; ++ ++struct xf_message { ++ /* pointer to the next item in the list */ ++ struct xf_message *next; ++ ++ /* shmem session_id */ ++ u32 id; ++ ++ /* operation code */ ++ u32 opcode; ++ ++ /* length of attached message buffer */ ++ u32 length; ++ ++ /* message buffer */ ++ void *buffer; ++}; ++ ++/******************************************************************************* ++ * XF_GET_PARAM message ++ ******************************************************************************/ ++ ++/* ...message body (command/response) */ ++union xf_get_param_msg { /* PRQA S 750 18 */ ++ /* ...command structure */ ++ struct { ++ /* ...array of parameters requested */ ++ u32 id[0]; /* PRQA S 1037 */ ++ ++ } __attribute__((__packed__)) c; ++ ++ /* ...response structure */ ++ struct { ++ /* ...array of parameters values */ ++ u32 value[0];/* PRQA S 1037 */ ++ ++ } __attribute__((__packed__)) r; ++ ++}; ++ ++/* ...length of the XF_GET_PARAM command/response */ ++/* PRQA S 3453 2 */ ++#define XF_GET_PARAM_CMD_LEN(params) (sizeof(u32) * (params)) ++#define XF_GET_PARAM_RSP_LEN(params) (sizeof(u32) * (params)) ++ ++/******************************************************************************* ++ * XF_SET_PARAM message ++ ******************************************************************************/ ++ ++/* ...component initialization parameter */ ++struct xf_set_param_item { ++ /* ...index of parameter passed to SET_CONFIG_PARAM call */ ++ u32 id; ++ ++ /* ...value of parameter */ ++ u32 value; ++ ++} __attribute__ ((__packed__)); ++ ++/* ...message body (no response message? - tbd) */ ++struct xf_set_param_msg { ++ /* ...command message */ ++ struct xf_set_param_item item[0]; /* PRQA S 1037 */ ++ ++} __attribute__ ((__packed__)); ++ ++/* ...length of the command message */ ++/* PRQA S 3453 */ ++#define XF_SET_PARAM_CMD_LEN(params) \ ++ (sizeof(struct xf_set_param_item) * (params)) ++ ++/******************************************************************************* ++ * XF_ROUTE definition ++ ******************************************************************************/ ++ ++/* ...port routing command */ ++struct xf_route_port_msg { ++ /* ...source port specification */ ++ u32 src; ++ ++ /* ...destination port specification */ ++ u32 dst; ++ ++ /* ...number of buffers to allocate */ ++ u32 alloc_number; ++ ++ /* ...length of buffer to allocate */ ++ u32 alloc_size; ++ ++ /* ...alignment restriction for a buffer */ ++ u32 alloc_align; ++ ++} __attribute__((__packed__)); ++ ++/******************************************************************************* ++ * XF_UNROUTE definition ++ ******************************************************************************/ ++ ++/* ...port unrouting command */ ++struct xf_unroute_port_msg { ++ /* ...source port specification */ ++ u32 src; ++ ++ /* ...destination port specification */ ++ u32 dst; ++ ++} __attribute__((__packed__)); ++ ++/* ...Capture states */ ++enum xa_capture_state { ++ XA_CAP_STATE_RUN = 0, ++ XA_CAP_STATE_IDLE = 1, ++ XA_CAP_STATE_PAUSE = 2 ++}; ++ ++/* ...Renderer states */ ++enum xa_renderer_state { ++ XA_RDR_STATE_RUN = 0, ++ XA_RDR_STATE_IDLE = 1, ++ XA_RDR_STATE_PAUSE = 2 ++}; ++ ++/******************************************************************************* ++ * Message routing composition - move somewhere else - tbd ++ ******************************************************************************/ ++ ++/* ...adjust IPC client of message going from user-space */ ++#define XF_MSG_AP_FROM_USER(id, client) \ ++ (((id) & ~(0xF << 2)) | ((client) << 2)) ++ ++/* ...wipe out IPC client from message going to user-space */ ++#define XF_MSG_AP_TO_USER(id) \ ++ ((id) & ~(0xF << 18)) ++ ++/* ...port specification (12 bits) */ ++#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8)) ++#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8)) ++#define XF_PORT_CORE(spec) ((spec) & 0x3) ++#define XF_PORT_CLIENT(spec) (((spec) >> 2) & 0x3F) ++#define XF_PORT_ID(spec) (((spec) >> 8) & 0xF) ++ ++/* ...message id contains source and destination ports specification */ ++#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) ++#define XF_MSG_SRC(id) (((id) >> 0) & 0xFFFF) ++#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3) ++#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F) ++#define XF_MSG_SRC_PORT(id) (((id) >> 8) & 0xF) ++#define XF_MSG_SRC_PROXY(id) (((id) >> 15) & 0x1) ++#define XF_MSG_DST(id) (((id) >> 16) & 0xFFFF) ++#define XF_MSG_DST_CORE(id) (((id) >> 16) & 0x3) ++#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F) ++#define XF_MSG_DST_PORT(id) (((id) >> 24) & 0xF) ++#define XF_MSG_DST_PROXY(id) (((id) >> 31) & 0x1) ++ ++/* ...special treatment of AP-proxy destination field */ ++#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) ++#define XF_AP_CLIENT(id) (((id) >> 22) & 0x1FF) ++#define __XF_AP_PROXY(core) ((core) | 0x8000) ++#define __XF_DSP_PROXY(core) ((core) | 0x8000) ++#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 0x8000) ++ ++/******************************************************************************* ++ * Opcode composition ++ ******************************************************************************/ ++ ++/* ...opcode composition with command/response data tags */ ++#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) ++ ++/* ...accessors */ ++#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31)) ++#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30)) ++#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F)) ++ ++/******************************************************************************* ++ * Opcode types ++ ******************************************************************************/ ++ ++/* ...unregister client */ ++#define XF_UNREGISTER __XF_OPCODE(0, 0, 0) ++ ++/* ...register client at proxy */ ++#define XF_REGISTER __XF_OPCODE(1, 0, 1) ++ ++/* ...port routing command */ ++#define XF_ROUTE __XF_OPCODE(1, 0, 2) ++ ++/* ...port unrouting command */ ++#define XF_UNROUTE __XF_OPCODE(1, 0, 3) ++ ++/* ...shared buffer allocation */ ++#define XF_ALLOC __XF_OPCODE(0, 0, 4) ++ ++/* ...shared buffer freeing */ ++#define XF_FREE __XF_OPCODE(0, 0, 5) ++ ++/* ...set component parameters */ ++#define XF_SET_PARAM __XF_OPCODE(1, 0, 6) ++ ++/* ...get component parameters */ ++#define XF_GET_PARAM __XF_OPCODE(1, 1, 7) ++ ++/* ...input buffer reception */ ++#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8) ++ ++/* ...output buffer reception */ ++#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9) ++ ++/* ...flush specific port */ ++#define XF_FLUSH __XF_OPCODE(0, 0, 10) ++ ++/* ...start component operation */ ++#define XF_START __XF_OPCODE(0, 0, 11) ++ ++/* ...stop component operation */ ++#define XF_STOP __XF_OPCODE(0, 0, 12) ++ ++/* ...pause component operation */ ++#define XF_PAUSE __XF_OPCODE(0, 0, 13) ++ ++/* ...resume component operation */ ++#define XF_RESUME __XF_OPCODE(0, 0, 14) ++ ++/* ...total amount of supported decoder commands */ ++#define __XF_OP_NUM (15) ++ ++/************************************************* ++ * Renderer - specific configuration parameters ++ * **********************************************/ ++ ++enum xa_config_param_renderer { ++ XA_RDR_CONFIG_PARAM_STATE = 0, ++ XA_RDR_CONFIG_PARAM_PCM_WIDTH = 1, ++ XA_RDR_CONFIG_PARAM_CHANNELS = 2, ++ XA_RDR_CONFIG_PARAM_SAMPLE_RATE = 3, ++ XA_RDR_CONFIG_PARAM_FRAME_SIZE = 4, ++ XA_RDR_CONFIG_PARAM_OUTPUT1 = 5, ++ XA_RDR_CONFIG_PARAM_DMACHANNEL1 = 6, ++ XA_RDR_CONFIG_PARAM_OUTPUT2 = 7, ++ XA_RDR_CONFIG_PARAM_DMACHANNEL2 = 8, ++ XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 9, ++ XA_RDR_CONFIG_PARAM_VOLUME_RATE = 10, ++ XA_RDR_CONFIG_PARAM_OUT_CHANNELS = 11, ++ XA_RDR_CONFIG_PARAM_MIX_CONTROL = 12, ++ XA_RDR_CONFIG_PARAM_NUM = 13 ++}; ++ ++/************************************************* ++ * Capture - specific configuration parameters ++ * **********************************************/ ++ ++enum xa_config_param_capture { ++ XA_CAP_CONFIG_PARAM_CB = 0, ++ XA_CAP_CONFIG_PARAM_STATE = 1, ++ XA_CAP_CONFIG_PARAM_PCM_WIDTH = 2, ++ XA_CAP_CONFIG_PARAM_CHANNELS = 3, ++ XA_CAP_CONFIG_PARAM_SAMPLE_RATE = 4, ++ XA_CAP_CONFIG_PARAM_FRAME_SIZE = 5, ++ XA_CAP_CONFIG_PARAM_INPUT1 = 6, ++ XA_CAP_CONFIG_PARAM_DMACHANNEL1 = 7, ++ XA_CAP_CONFIG_PARAM_INPUT2 = 8, ++ XA_CAP_CONFIG_PARAM_DMACHANNEL2 = 9, ++ XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 10, ++ XA_CAP_CONFIG_PARAM_VOLUME_RATE = 11, ++ XA_CAP_CONFIG_PARAM_NUM = 12 ++}; ++ ++/************************************************* ++ * Equalizer - specific configuration parameters ++ * **********************************************/ ++ ++enum xa_rel_eqz_filter_type { ++ XA_REL_EQZ_TYPE_THROUGH = 0, ++ XA_REL_EQZ_TYPE_PEAK = 1, ++ XA_REL_EQZ_TYPE_BASS = 2, ++ XA_REL_EQZ_TYPE_TREBLE = 3 ++}; ++ ++enum xa_rel_eqz_type { ++ XA_REL_EQZ_TYPE_PARAMETRIC = 0, ++ XA_REL_EQZ_TYPE_GRAPHIC = 1 ++}; ++ ++/*****************************************************************************/ ++/* Additional subcommand indices */ ++/*****************************************************************************/ ++ ++enum xa_add_cmd_type_generic { ++ /* XA_API_CMD_SET_CONFIG_PARAM indices */ ++ XA_EQZ_CONFIG_PARAM_COEF_FS = 0x0000, ++ XA_EQZ_CONFIG_PARAM_PCM_WIDTH = 0x0001, ++ XA_EQZ_CONFIG_PARAM_CH = 0x0002, ++ XA_EQZ_CONFIG_PARAM_EQZ_TYPE = 0x0003, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC = 0x0010, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_FC = 0x0011, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_FC = 0x0012, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_FC = 0x0013, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_FC = 0x0014, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_FC = 0x0015, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_FC = 0x0016, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_FC = 0x0017, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_FC = 0x0018, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE = 0x0020, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_TYPE = 0x0021, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_TYPE = 0x0022, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_TYPE = 0x0023, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_TYPE = 0x0024, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_TYPE = 0x0025, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_TYPE = 0x0026, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_TYPE = 0x0027, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_TYPE = 0x0028, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW = 0x0030, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BW = 0x0031, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BW = 0x0032, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BW = 0x0033, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BW = 0x0034, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BW = 0x0035, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BW = 0x0036, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BW = 0x0037, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BW = 0x0038, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA = 0x0040, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_GA = 0x0041, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_GA = 0x0042, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_GA = 0x0043, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_GA = 0x0044, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_GA = 0x0045, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_GA = 0x0046, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_GA = 0x0047, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_GA = 0x0048, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA = 0x0050, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BA = 0x0051, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BA = 0x0052, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BA = 0x0053, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BA = 0x0054, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BA = 0x0055, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BA = 0x0056, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BA = 0x0057, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BA = 0x0058, ++ ++ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA = 0x0060, ++ XA_EQZ_CONFIG_PARAM_BAND_1_GCOEF_GA = 0x0061, ++ XA_EQZ_CONFIG_PARAM_BAND_2_GCOEF_GA = 0x0062, ++ XA_EQZ_CONFIG_PARAM_BAND_3_GCOEF_GA = 0x0063, ++ XA_EQZ_CONFIG_PARAM_BAND_4_GCOEF_GA = 0x0064 ++}; ++ ++/* ...tdm-renderer-specific configuration parameters */ ++enum xa_config_param_tdm_renderer { ++ XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH = 0, ++ XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE = 1, ++ XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE = 2, ++ XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE = 3, ++ XA_TDM_RDR_CONFIG_PARAM_OUTPUT1 = 4, ++ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1 = 5, ++ XA_TDM_RDR_CONFIG_PARAM_OUTPUT2 = 6, ++ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2 = 7, ++ XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, ++ XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE = 9 ++}; ++ ++enum xa_rel_tdm_renderer_channel_mode { ++ XA_TDM_RDR_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ ++ XA_TDM_RDR_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ ++ /**< 1 six-channels plus 1 two-channels TDM data */ ++ XA_TDM_RDR_CHANNEL_MODE_6_2 = 2, ++ XA_TDM_RDR_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ ++ XA_TDM_RDR_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ ++}; ++ ++/* ...TDM Capture-specific configuration parameters */ ++enum xa_config_param_tdm_capture { ++ XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH = 0, ++ XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE = 1, ++ XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE = 2, ++ XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE = 3, ++ XA_TDM_CAP_CONFIG_PARAM_INPUT1 = 4, ++ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1 = 5, ++ XA_TDM_CAP_CONFIG_PARAM_INPUT2 = 6, ++ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2 = 7, ++ XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, ++ XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE = 9 ++}; ++ ++enum xa_rel_tdm_capture_channel_mode { ++ XA_TDM_CAP_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ ++ XA_TDM_CAP_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ ++ /**< 1 six-channels plus 1 two-channels TDM data */ ++ XA_TDM_CAP_CHANNEL_MODE_6_2 = 2, ++ XA_TDM_CAP_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ ++ XA_TDM_CAP_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ ++}; ++ ++/*****************************************************************************/ ++/* HW supported */ ++/*****************************************************************************/ ++/* ...SSI modules supported by HW */ ++enum ssi_module { ++ SSI00 = 0, ++ SSI01 = 1, ++ SSI02 = 2, ++ SSI03 = 3, ++ SSI04 = 4, ++ SSI05 = 5, ++ SSI06 = 6, ++ SSI07 = 7, ++ SSI10 = 10, ++ SSI11 = 11, ++ SSI12 = 12, ++ SSI13 = 13, ++ SSI14 = 14, ++ SSI15 = 15, ++ SSI16 = 16, ++ SSI17 = 17, ++ SSI20 = 20, ++ SSI21 = 21, ++ SSI22 = 22, ++ SSI23 = 23, ++ SSI24 = 24, ++ SSI25 = 25, ++ SSI26 = 26, ++ SSI27 = 27, ++ SSI30 = 30, ++ SSI31 = 31, ++ SSI32 = 32, ++ SSI33 = 33, ++ SSI34 = 34, ++ SSI35 = 35, ++ SSI36 = 36, ++ SSI37 = 37, ++ SSI40 = 40, ++ SSI41 = 41, ++ SSI42 = 42, ++ SSI43 = 43, ++ SSI44 = 44, ++ SSI45 = 45, ++ SSI46 = 46, ++ SSI47 = 47, ++ SSI5 = 50, ++ SSI6 = 60, ++ SSI7 = 70, ++ SSI8 = 80, ++ SSI90 = 90, ++ SSI91 = 91, ++ SSI92 = 92, ++ SSI93 = 93, ++ SSI94 = 94, ++ SSI95 = 95, ++ SSI96 = 96, ++ SSI97 = 97 ++}; ++ ++/* ...SRC modules supported by HW */ ++enum src_module { ++ SRC0 = 110, /* SRC0 */ ++ SRC1 = 111, /* SRC1 */ ++ SRC2 = 112, /* SRC2 */ ++ SRC3 = 113, /* SRC3 */ ++ SRC4 = 114, /* SRC4 */ ++ SRC5 = 115, /* SRC5 */ ++ SRC6 = 116, /* SRC6 */ ++ SRC7 = 117, /* SRC7 */ ++ SRC8 = 118, /* SRC8 */ ++ SRC9 = 119, /* SRC9 */ ++ SRCMAX = 120 /* Maximum number of SRC modules */ ++}; ++ ++/* ...PDMA supported by HW */ ++enum { ++ PDMA_CH00 = 0, ++ PDMA_CH01 = 1, ++ PDMA_CH02 = 2, ++ PDMA_CH03 = 3, ++ PDMA_CH04 = 4, ++ PDMA_CH05 = 5, ++ PDMA_CH06 = 6, ++ PDMA_CH07 = 7, ++ PDMA_CH08 = 8, ++ PDMA_CH09 = 9, ++ PDMA_CH10 = 10, ++ PDMA_CH11 = 11, ++ PDMA_CH12 = 12, ++ PDMA_CH13 = 13, ++ PDMA_CH14 = 14, ++ PDMA_CH15 = 15, ++ PDMA_CH16 = 16, ++ PDMA_CH17 = 17, ++ PDMA_CH18 = 18, ++ PDMA_CH19 = 19, ++ PDMA_CH20 = 20, ++ PDMA_CH21 = 21, ++ PDMA_CH22 = 22, ++ PDMA_CH23 = 23, ++ PDMA_CH24 = 24, ++ PDMA_CH25 = 25, ++ PDMA_CH26 = 26, ++ PDMA_CH27 = 27, ++ PDMA_CH28 = 28, ++ PDMA_CHMAX = 29 ++}; ++ ++/* ...DMAC supported by HW */ ++enum { ++ ADMAC_CH00 = PDMA_CHMAX + 0, ++ ADMAC_CH01 = PDMA_CHMAX + 1, ++ ADMAC_CH02 = PDMA_CHMAX + 2, ++ ADMAC_CH03 = PDMA_CHMAX + 3, ++ ADMAC_CH04 = PDMA_CHMAX + 4, ++ ADMAC_CH05 = PDMA_CHMAX + 5, ++ ADMAC_CH06 = PDMA_CHMAX + 6, ++ ADMAC_CH07 = PDMA_CHMAX + 7, ++ ADMAC_CH08 = PDMA_CHMAX + 8, ++ ADMAC_CH09 = PDMA_CHMAX + 9, ++ ADMAC_CH10 = PDMA_CHMAX + 10, ++ ADMAC_CH11 = PDMA_CHMAX + 11, ++ ADMAC_CH12 = PDMA_CHMAX + 12, ++ ADMAC_CH13 = PDMA_CHMAX + 13, ++ ADMAC_CH14 = PDMA_CHMAX + 14, ++ ADMAC_CH15 = PDMA_CHMAX + 15, ++ ADMAC_CH16 = PDMA_CHMAX + 16, ++ ADMAC_CH17 = PDMA_CHMAX + 17, ++ ADMAC_CH18 = PDMA_CHMAX + 18, ++ ADMAC_CH19 = PDMA_CHMAX + 19, ++ ADMAC_CH20 = PDMA_CHMAX + 20, ++ ADMAC_CH21 = PDMA_CHMAX + 21, ++ ADMAC_CH22 = PDMA_CHMAX + 22, ++ ADMAC_CH23 = PDMA_CHMAX + 23, ++ ADMAC_CH24 = PDMA_CHMAX + 24, ++ ADMAC_CH25 = PDMA_CHMAX + 25, ++ ADMAC_CH26 = PDMA_CHMAX + 26, ++ ADMAC_CH27 = PDMA_CHMAX + 27, ++ ADMAC_CH28 = PDMA_CHMAX + 28, ++ ADMAC_CH29 = PDMA_CHMAX + 29, ++ ADMAC_CH30 = PDMA_CHMAX + 30, ++ ADMAC_CH31 = PDMA_CHMAX + 31, ++ ADMAC_CHMAX = PDMA_CHMAX + 32 ++}; ++ ++#endif +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-Add-document-file-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-Add-document-file-for-ADSP-sound-driver.patch deleted file mode 100644 index f4305ad..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-Add-document-file-for-ADSP-sound-driver.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 35f2052da7ebf049daaf85ff8c8eb8d31617c80f Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 17:59:33 +0700 -Subject: [PATCH 2/4] Add document file for ADSP sound driver - -Signed-off-by: tienphitran - -diff --git a/Documentation/devicetree/bindings/sound/renesas,adsp.txt b/Documentation/devicetree/bindings/sound/renesas,adsp.txt -new file mode 100644 -index 0000000..b529bca ---- /dev/null -+++ b/Documentation/devicetree/bindings/sound/renesas,adsp.txt -@@ -0,0 +1,11 @@ -+Renesas ADSP sound driver -+ -+Required properties: -+- compatible : "renesas,rcar_adsp_sound_gen3" -+ -+Example: -+ -+rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+}; --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch deleted file mode 100644 index e7c17d6..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d25996a812524c338423b9da86233564d18f0042 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:41 +0900 -Subject: [PATCH 2/6] arm64: dts: r8a7796-salvator-xs: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts -index 2f4bd3ae3678..ba040341aa26 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts -@@ -101,11 +101,6 @@ - "dclkin.0", "dclkin.1", "dclkin.2"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1>; /* HDMI0 */ --}; -- - &hdmi0 { - status = "okay"; - --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-ADSP-add-build-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-ADSP-add-build-for-ADSP-sound-driver.patch new file mode 100644 index 0000000..ecab412 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-ADSP-add-build-for-ADSP-sound-driver.patch @@ -0,0 +1,35 @@ +From 3ae5cb9feda031f660becc94f5496d5ee9b90e22 Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Mon, 15 Oct 2018 17:57:56 +0700 +Subject: [PATCH 3/6] ADSP: add build for ADSP sound driver + +Signed-off-by: tienphitran +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig +index c0abad2067e1..f5f6abbd6e14 100644 +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -71,6 +71,7 @@ source "sound/soc/txx9/Kconfig" + source "sound/soc/ux500/Kconfig" + source "sound/soc/xtensa/Kconfig" + source "sound/soc/zte/Kconfig" ++source "sound/soc/adsp/Kconfig" + + # Supported codecs + source "sound/soc/codecs/Kconfig" +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index bf8c1e2ce0bf..6e77abba2b01 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -52,3 +52,4 @@ obj-$(CONFIG_SND_SOC) += txx9/ + obj-$(CONFIG_SND_SOC) += ux500/ + obj-$(CONFIG_SND_SOC) += xtensa/ + obj-$(CONFIG_SND_SOC) += zte/ ++obj-$(CONFIG_SND_SOC) += adsp/ +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-Add-ADSP-sound-driver-source.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-Add-ADSP-sound-driver-source.patch deleted file mode 100644 index d25c2b1..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-Add-ADSP-sound-driver-source.patch +++ /dev/null @@ -1,7172 +0,0 @@ -From 1705856b55d8f93a22843a9577eadac4212342e7 Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 18:00:42 +0700 -Subject: [PATCH 3/4] Add ADSP sound driver source - -Signed-off-by: tienphitran - -diff --git a/include/adsp_drv/xf-adsp-drv-ext.h b/include/adsp_drv/xf-adsp-drv-ext.h -new file mode 100644 -index 0000000..6e56b45 ---- /dev/null -+++ b/include/adsp_drv/xf-adsp-drv-ext.h -@@ -0,0 +1,60 @@ -+/***************************************************************************** -+ * \file xf-adsp-driver-ext.h -+ * \brief Header file for ADSP driver extension part -+ * \addtogroup ADSP Driver -+ ****************************************************************************** -+ * \date Oct. 21, 2017 -+ * \author Renesas Electronics Corporation -+ ****************************************************************************** -+ * \par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#ifndef __XF_ADSP_DRV_EXT_H -+#define __XF_ADSP_DRV_EXT_H -+ -+/*********************************************************** -+ * Extension client APIs -+ * ********************************************************/ -+ -+typedef struct xf_adsp_base_cmd xf_adsp_base_cmd_t; -+ -+struct xf_adsp_base_cmd { -+ /* register new client for ADSP base control */ -+ int (*client_register)(void **private_data); -+ /* unregister client */ -+ int (*client_unregister)(void *private_data); -+ /* get data from proxy */ -+ int (*recv)(void *private_data, void *buf); -+ /* send data to proxy */ -+ int (*send)(void *private_data, void *buf); -+ /* wait the valid message in the response queue */ -+ int (*poll)(void *private_data, volatile int *condition); -+}; -+ -+/* create ADSP base control data */ -+int xf_adsp_base_create(xf_adsp_base_cmd_t *cmd); -+ -+/* destroy ADSP base control data */ -+int xf_adsp_base_destroy(void); -+ -+#endif -diff --git a/sound/soc/adsp/Kconfig b/sound/soc/adsp/Kconfig -new file mode 100644 -index 0000000..605261f ---- /dev/null -+++ b/sound/soc/adsp/Kconfig -@@ -0,0 +1,14 @@ -+## SoC for ADSP driver configuration -+menu "ASoC ADSP driver" -+ -+config SND_SOC_ADSP -+ tristate "SoC Audio for R-Car ADSP" -+ select SND_SIMPLE_CARD -+ select SND_SIMPLE_SCU_CARD -+ select SND_AUDIO_GRAPH_CARD -+ select SND_AUDIO_GRAPH_SCU_CARD -+ default y -+ help -+ This option enables ALSA ADSP sound supports ADSP module -+ -+endmenu -diff --git a/sound/soc/adsp/Makefile b/sound/soc/adsp/Makefile -new file mode 100644 -index 0000000..8277fdb ---- /dev/null -+++ b/sound/soc/adsp/Makefile -@@ -0,0 +1,3 @@ -+## Makefile for SoC ADSP driver -+snd-soc-adsp-objs := xf-adsp-alsa.o xf-adsp-base.o -+obj-$(CONFIG_SND_SOC_ADSP) += snd-soc-adsp.o -diff --git a/sound/soc/adsp/xf-adsp-alsa.c b/sound/soc/adsp/xf-adsp-alsa.c -new file mode 100644 -index 0000000..b6c5752 ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-alsa.c -@@ -0,0 +1,3924 @@ -+/** *************************************************************************** -+ * \file xf-adsp-alsa.c -+ * \brief Source file for ADSP ALSA Driver -+ * \addtogroup ADSP Driver -+ ****************************************************************************** -+ * \date Oct. 21, 2017 -+ * \author Renesas Electronics Corporation -+ ****************************************************************************** -+ * \par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ *****************************************************************************/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xf-adsp-base.h" -+ -+ -+/* Name of Volume control for playback */ -+#define PLAYBACK_VOLUME_CTR_NAME "PlaybackVolume" -+ -+/* Name of Volume control for capture */ -+#define CAPTURE_VOLUME_CTR_NAME "CaptureVolume" -+ -+/* Name of Sample Rate control for playback */ -+#define PLAYBACK_OUT_RATE_CTR_NAME "PlaybackOutRate" -+ -+/* Name of Output Channel control for playback */ -+#define PLAYBACK_OUT_CHANNEL_CTR_NAME "PlaybackOutChannel" -+ -+/* Name of Sample Rate control for capture */ -+#define CAPTURE_IN_RATE_CTR_NAME "CaptureInRate" -+ -+/* Name of Equalizer parameters control for playback */ -+#define PLAYBACK_EQZ_CTR_NAME "PlaybackEQZControl" -+ -+/* Name of Equalizer parameters control for capture */ -+#define CAPTURE_EQZ_CTR_NAME "CaptureEQZControl" -+ -+/* Name of Equalizer Switch control for playback */ -+#define PLAYBACK_EQZ_SWITCH_CTR_NAME "PlaybackEQZSwitch" -+ -+/* Name of Equalizer Switch control for capture */ -+#define CAPTURE_EQZ_SWITCH_CTR_NAME "CaptureEQZSwitch" -+ -+/* Name of Volume control for TDM playback */ -+#define TDM_PLAYBACK_VOLUME_CTR_NAME "TDMPlaybackVolume" -+ -+/* Name of Volume control for TDM capture */ -+#define TDM_CAPTURE_VOLUME_CTR_NAME "TDMCaptureVolume" -+ -+/* Name of Sample Rate control for TDM playback */ -+#define TDM_PLAYBACK_OUT_RATE_CTR_NAME "TDMPlaybackOutRate" -+ -+/* Name of Sample Rate control for TDM capture */ -+#define TDM_CAPTURE_IN_RATE_CTR_NAME "TDMCaptureInRate" -+ -+/* Prefix of Playback control name */ -+#define PREFIX_OF_PLAYBACK_CTR_NAME PLAYBACK_VOLUME_CTR_NAME[0] -+ -+/* Prefix of Capture control name */ -+#define PREFIX_OF_CAPTURE_CTR_NAME CAPTURE_VOLUME_CTR_NAME[0] -+ -+/* Prefix of TDM control name */ -+#define PREFIX_OF_TDM_CTR_NAME TDM_PLAYBACK_VOLUME_CTR_NAME[0] -+ -+/* Prefix of TDM playback */ -+#define TDM_PLAYBACK TDM_PLAYBACK_VOLUME_CTR_NAME[3] -+ -+/* Prefix of TDM record */ -+#define TDM_CAPTURE TDM_CAPTURE_VOLUME_CTR_NAME[3] -+ -+/* Number of control for playback & capture */ -+#define RDR_CONTROL_NUM (9) -+ -+/* Number of controls for TDM */ -+#define TDM_CONTROL_NUM (4) -+ -+/* Indicate playback stream */ -+#define DIRECT_PLAYBACK (0) -+ -+/* Indicate capture stream */ -+#define DIRECT_CAPTURE (1) -+ -+/* Indicate stream number */ -+#define DIRECT_NUM (2) -+ -+/* Supported frame size for playback/record function in driver */ -+#define FRAME_SIZE (1024) -+ -+/* Supported frame size for TDM playback/record function in driver */ -+#define TDM_FRAME_SIZE (1024) -+ -+/* Supported sample rate in driver */ -+#define SND_ADSP_SAMPLE_RATES (SNDRV_PCM_RATE_32000 | \ -+ SNDRV_PCM_RATE_44100 | \ -+ SNDRV_PCM_RATE_48000) -+ -+/* Supported PCM width in driver */ -+#define SND_ADSP_PCM_WIDTHS (SNDRV_PCM_FMTBIT_S16_LE | \ -+ SNDRV_PCM_FMTBIT_S24_LE) -+ -+/* Macro to control DAI index */ -+/* DAI 0 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX0 (0) -+ -+/* DAI 1 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX1 (1) -+ -+/* DAI 2 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX2 (2) -+ -+/* DAI 3 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX3 (3) -+ -+/* DAI 4 index for playback/record functions of TDM formats */ -+#define TDM_DAI_IDX (4) -+ -+/* Maximum number of DAI supported by driver */ -+#define MAX_DAI_IDX (5) -+ -+/* Renderer/Capture software information */ -+/* Minimum channel number supported */ -+#define MIN_CHANNEL (1) -+ -+/* Maximum channel number supported */ -+#define MAX_CHANNEL (2) -+ -+/* Minimum buffer size in byte */ -+#define MIN_BUF_SIZE (FRAME_SIZE * MIN_CHANNEL * 2) -+ -+/* Maximum buffer size in byte */ -+#define MAX_BUF_SIZE (FRAME_SIZE * MAX_CHANNEL * 4) -+ -+/* Minimum numbers of period in the buffer */ -+#define MIN_PERIOD (1) -+ -+/* Maximum numbers of period in the buffer */ -+#define MAX_PERIOD (4) -+ -+/* Maximun numbers of bytes in ALSA buffer */ -+#define MAX_BUFFER_BYTES (MAX_PERIOD * MAX_BUF_SIZE) -+ -+/* TDM software information */ -+/*< Minimum channel number supported in TDM plugin */ -+#define TDM_MIN_CHANNEL (6) -+ -+/* Maximum channel number supported in TDM plugin */ -+#define TDM_MAX_CHANNEL (8) -+ -+/* Minimum buffer size in byte for TDM format */ -+#define TDM_MIN_BUF_SIZE (TDM_FRAME_SIZE * TDM_MIN_CHANNEL * 2) -+ -+/* Maximum buffer size in byte for TDM format */ -+#define TDM_MAX_BUF_SIZE (TDM_FRAME_SIZE * TDM_MAX_CHANNEL * 4) -+ -+/* Minimum numbers of period in the buffer for TDM format */ -+#define TDM_MIN_PERIOD (1) -+ -+/* Maximum numbers of period in the buffer for TDM format */ -+#define TDM_MAX_PERIOD (4) -+ -+/* Maximum numbers of bytes in ALSA buffer for TDM format */ -+#define TDM_MAX_BUFFER_BYTES (TDM_MAX_PERIOD * TDM_MAX_BUF_SIZE) -+ -+/* Volume scale used when user set */ -+#define VOLUME_SCALE (100) -+ -+/* Maximum element in Equalizer parameter control */ -+#define MAX_EQZ_PARAM_NUMBER (55) -+ -+/* Equalizer control is disabled */ -+#define EQZ_OFF (0) -+ -+/* Equalizer control is enabled */ -+#define EQZ_ON (1) -+ -+/* Component status */ -+/* Handle state is NULL */ -+#define XF_HANDLE_NULL (0) -+ -+/* Handle state is CREATED after creating handle successfully */ -+#define XF_HANDLE_CREATED (1 << 0) -+ -+/* Handle state is READY after finishing handle init */ -+#define XF_HANDLE_READY (1 << 1) -+ -+/* channels */ -+/* Mono stream */ -+#define MONAURAL (1) -+ -+/* Stereo stream */ -+#define STEREO (2) -+ -+/* define number of bytes in a sample of 24 bits format types */ -+/* store 24 bits data in 4 bytes LE */ -+#define FMTBIT_S24_LE_BYTES_PER_SAMPLE (4) -+ -+/* store 24 bits data in 3 bytes LE */ -+#define FMTBIT_S24_3LE_BYTES_PER_SAMPLE (3) -+ -+/* helper macro to get bytes per sample number */ -+#define BYTES_PER_SAMPLE(fmt) (FMTBIT_##fmt##_BYTES_PER_SAMPLE) -+ -+/* copy a sample from S24_LE format to S24_3LE format type */ -+#define SAMPLE_COPY_FROM_S24_LE_TO_S24_3LE(dst, src) \ -+ do { \ -+ dst[0] = src[0]; \ -+ dst[1] = src[1]; \ -+ dst[2] = src[2]; \ -+ } while (0) -+ -+/* copy a sample from S24_3LE format to S24_LE format type */ -+#define SAMPLE_COPY_FROM_S24_3LE_TO_S24_LE(dst, src) \ -+ do { \ -+ dst[0] = src[0]; \ -+ dst[1] = src[1]; \ -+ dst[2] = src[2]; \ -+ dst[3] = 0; \ -+ } while (0) -+ -+/* helper macro to copy a sample from difference format data */ -+#define SAMPLE_COPY(dst, src, dst_fmt, src_fmt) \ -+ SAMPLE_COPY_FROM_##src_fmt##_TO_##dst_fmt(dst, src) -+ -+/* check if data is valid */ -+#define IS_VALID(data) (data != NULL) -+ -+/* check component is created */ -+#define COMPONENT_IS_CREATED(n) (((n & XF_HANDLE_CREATED) != 0) ? TRUE : FALSE) -+ -+/* check component is ready */ -+#define COMPONENT_IS_READY(n) (((n & XF_HANDLE_READY) != 0) ? TRUE : FALSE) -+ -+/* indicator of stream order */ -+#define MIX_UNUSED (0) -+#define FIRST_RUN (2) -+#define SECOND_RUN (1) -+ -+/* check MIX usage */ -+#define MIX_ENABLED(mix_ctl) ((mix_ctl == SECOND_RUN) ? TRUE : FALSE) -+ -+/******************************************************************* -+ * base structures for ADSP ALSA driver -+ * ****************************************************************/ -+ -+/** \struct snd_adsp_control -+ * \brief Structure stores parameters from user -+ */ -+struct snd_adsp_control { -+ /* Volume rate for playback/record */ -+ int vol_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Volume rate for TDM playback/TDM record */ -+ int tdm_vol_rate[DIRECT_NUM]; -+ -+ /* Out sample rate with Renderer, in sample rate with Capture */ -+ int sample_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Out sample rate for TDM Renderer, in sample rate for TDM Capture */ -+ int tdm_sample_rate[DIRECT_NUM]; -+ -+ /* Output channel of playback */ -+ int rdr_out_ch[MAX_DAI_IDX - 1]; -+ -+ /* Equalizer parameters */ -+ struct xf_adsp_equalizer_params eqz_params[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Equalizer switch */ -+ int eqz_switch[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Indicator of MIX usage */ -+ int mix_usage; -+}; -+ -+/** \struct snd_adsp_base_info -+ * \brief Structure stores some base information of a stream -+ */ -+struct snd_adsp_base_info { -+ /* high resolution timer data */ -+ struct hrtimer hrtimer; -+ -+ /* kernel time value in nanosecond */ -+ ktime_t ktime; -+ -+ /* high resolution timer state */ -+ int hrt_state; -+ -+ /* target handle id of ALSA driver */ -+ int handle_id; -+ -+ /* data buffer */ -+ char *buffer[XF_BUF_POOL_SIZE]; -+ -+ /* size of each allocated data buffer */ -+ int buf_bytes; -+ -+ /* data index of buffer */ -+ int buf_idx; -+ -+ /* queue index of buffer */ -+ int buf_queue; -+ -+ /* HW index in bytes */ -+ int hw_idx; -+ -+ /* number of bytes in a period */ -+ int period_bytes; -+ -+ /* substream runtime object */ -+ struct snd_pcm_substream *substream; -+ -+ /* indirect PCM data transfer */ -+ struct snd_pcm_indirect pcm_indirect; -+ -+ /* spinlock data */ -+ spinlock_t lock; -+ -+ /* runtime error indicator */ -+ int runtime_err; -+}; -+ -+/** \struct snd_adsp_playback -+ * \brief Structure stores data for playback function -+ */ -+struct snd_adsp_playback { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* Renderer component data */ -+ struct xf_adsp_renderer *renderer; -+ -+ /* Equalizer component data */ -+ struct xf_adsp_equalizer *equalizer; -+ -+ /* Renderer component state */ -+ int rdr_state; -+ -+ /* Equalizer component state */ -+ int eqz_state; -+}; -+ -+/** \struct snd_adsp_record -+ * \brief Structure stores data for record function -+ */ -+struct snd_adsp_record { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* Capture component data */ -+ struct xf_adsp_capture *capture; -+ -+ /* Equalizer component data */ -+ struct xf_adsp_equalizer *equalizer; -+ -+ /* Capture component state */ -+ int cap_state; -+ -+ /* Equalizer component state */ -+ int eqz_state; -+}; -+ -+/** \struct snd_adsp_tdm_playback -+ * \brief Structure stores data for TDM playback function -+ */ -+struct snd_adsp_tdm_playback { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* TDM Renderer component data */ -+ struct xf_adsp_tdm_renderer *tdm_renderer; -+ -+ /* TDM Renderer component state */ -+ int state; -+}; -+ -+/** \struct snd_adsp_tdm_record -+ * \brief Structure stores data for TDM record function -+ */ -+struct snd_adsp_tdm_record { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* TDM Capture component data */ -+ struct xf_adsp_tdm_capture *tdm_capture; -+ -+ /* TDM Capture component state */ -+ int state; -+}; -+ -+/** \struct snd_adsp_card -+ * \brief Structure stores data for ALSA sound card -+ */ -+struct snd_adsp_card { -+ /* playback data */ -+ struct snd_adsp_playback *playback[MAX_DAI_IDX - 1]; -+ -+ /* record data */ -+ struct snd_adsp_record *record[MAX_DAI_IDX - 1]; -+ -+ /* TDM playback data */ -+ struct snd_adsp_tdm_playback *tdm_playback; -+ -+ /* TDM record data */ -+ struct snd_adsp_tdm_record *tdm_record; -+ -+ /* Structure contains params information for control */ -+ struct snd_adsp_control ctr_if; -+}; -+ -+/** HW configuration of ALSA ADSP card for Renderer/Capture */ -+static struct snd_pcm_hardware snd_pcm_adsp_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ -+ | SNDRV_PCM_INFO_RESUME -+ | SNDRV_PCM_INFO_BLOCK_TRANSFER -+ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = SND_ADSP_PCM_WIDTHS, -+ .rates = SND_ADSP_SAMPLE_RATES, -+ .rate_min = 32000, -+ .rate_max = 48000, -+ .channels_min = MIN_CHANNEL, -+ .channels_max = MAX_CHANNEL, -+ -+ /* maximum buffer size in bytes */ -+ .buffer_bytes_max = MAX_BUFFER_BYTES, -+ -+ /* minimum size of the periods (frame) in bytes */ -+ .period_bytes_min = MIN_BUF_SIZE, -+ -+ /* maximum size of the periods (frame) in bytes */ -+ .period_bytes_max = MAX_BUF_SIZE, -+ -+ /* minimum periods (frames) in a buffer */ -+ .periods_min = MIN_PERIOD, -+ -+ /* maximum periods (frames) in a buffer */ -+ .periods_max = MAX_PERIOD, -+}; -+ -+/* HW configuration of ALSA ADSP card for TDM */ -+static struct snd_pcm_hardware snd_pcm_adsp_tdm_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ -+ | SNDRV_PCM_INFO_RESUME -+ | SNDRV_PCM_INFO_BLOCK_TRANSFER -+ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = SND_ADSP_PCM_WIDTHS, -+ .rates = SND_ADSP_SAMPLE_RATES, -+ .rate_min = 32000, -+ .rate_max = 48000, -+ .channels_min = TDM_MIN_CHANNEL, -+ .channels_max = TDM_MAX_CHANNEL, -+ -+ /* maximum buffer size in bytes */ -+ .buffer_bytes_max = TDM_MAX_BUFFER_BYTES, -+ -+ /* minimum size of the periods (frame) in bytes */ -+ .period_bytes_min = TDM_MIN_BUF_SIZE, -+ -+ /* maximum size of the periods (frame) in bytes */ -+ .period_bytes_max = TDM_MAX_BUF_SIZE, -+ -+ /* minimum periods (frames) in a buffer */ -+ .periods_min = TDM_MIN_PERIOD, -+ -+ /* maximum periods (frames) in a buffer */ -+ .periods_max = TDM_MAX_PERIOD, -+}; -+ -+/******************************************************************* -+ * function declaration -+ * ****************************************************************/ -+ -+static int snd_adsp_rdr_empty_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_rdr_fill_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_cap_empty_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_cap_fill_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_get_dai_id_from_substream -+ (struct snd_pcm_substream *substream); -+static void *snd_adsp_get_drvdata_from_substream -+ (struct snd_pcm_substream *substream); -+static struct snd_adsp_base_info *snd_adsp_get_base_from_substream -+ (struct snd_pcm_substream *substream); -+static struct snd_adsp_base_info *snd_adsp_get_base_from_hrt -+ (struct hrtimer *hrt); -+static enum hrtimer_restart snd_adsp_hrtimer_func -+ (struct hrtimer *hrt); -+static int snd_adsp_playback_init -+ (struct snd_adsp_playback **data, int eqz_flag, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_record_init -+ (struct snd_adsp_record **data, int eqz_flag, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_playback_prepare -+ (struct snd_adsp_playback *playback, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_record_prepare -+ (struct snd_adsp_record *record, struct snd_pcm_substream *substream); -+static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback); -+static int snd_adsp_record_deinit(struct snd_adsp_record *record); -+static int snd_adsp_tdm_playback_init -+ (struct snd_adsp_tdm_playback **data, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_record_init -+ (struct snd_adsp_tdm_record **data, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_playback_prepare -+ (struct snd_adsp_tdm_playback *tdm_playback, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_record_prepare -+ (struct snd_adsp_tdm_record *tdm_record, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_playback_deinit -+ (struct snd_adsp_tdm_playback *tdm_playback); -+static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record); -+static int snd_adsp_pcm_open(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_close(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_hw_params -+ (struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params); -+static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx); -+static snd_pcm_uframes_t snd_adsp_pcm_pointer -+ (struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream); -+static void snd_adsp_pcm_transfer -+ (struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes); -+static int snd_adsp_control_volume_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_volume_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_volume_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_eqz_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_switch_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_switch_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_sample_rate_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_sample_rate_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_sample_rate_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_switch_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static void snd_adsp_get_eqz_params_from_control -+ (struct xf_adsp_equalizer_params *eqz_params, -+ struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag); -+static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime); -+static int snd_adsp_probe(struct platform_device *pdev); -+static int snd_adsp_remove(struct platform_device *pdev); -+ -+/******************************************************************* -+ * callback function of ADSP control interface -+ * ****************************************************************/ -+/** ************************************************************************** -+ * \brief event handler callback to notify error from ADSP -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_event_handler(void *data) -+{ -+ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; -+ -+ if (base != NULL) -+ base->runtime_err = TRUE; -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief empty buf done callback for playback/TDM playback functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_rdr_empty_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; -+ -+ if (base != NULL) { -+ spin_lock(&base->lock); -+ -+ base->buf_queue++; -+ base->hw_idx += length; /* increase the DMA buffer index */ -+ -+ spin_unlock(&base->lock); -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief fill buf done callback for playback/TDM playback functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_rdr_fill_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief empty buf done callback for record/TDM record functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_cap_empty_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief fill buf done callback for record/TDM record functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_cap_fill_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; -+ -+ if (base != NULL) { -+ spin_lock(&base->lock); -+ -+ base->buf_queue++; -+ base->hw_idx += length; /* increase the DMA buffer index */ -+ -+ spin_unlock(&base->lock); -+ } -+ -+ return 0; -+} -+ -+/** callback functions for playback/TDM playback */ -+static struct xf_callback_func rdr_callbacks = /* PRQA S 3218 */ -+{ -+ .empty_buf_done = &snd_adsp_rdr_empty_buf_done, /* PRQA S 1053 2 */ -+ .fill_buf_done = &snd_adsp_rdr_fill_buf_done, -+ .event_handler = &snd_adsp_event_handler -+}; -+ -+/** callback functions for record/TDM record */ -+static struct xf_callback_func cap_callbacks = /* PRQA S 3218 */ -+{ -+ .empty_buf_done = &snd_adsp_cap_empty_buf_done, /* PRQA S 1053 2 */ -+ .fill_buf_done = &snd_adsp_cap_fill_buf_done, -+ .event_handler = &snd_adsp_event_handler -+}; -+ -+/******************************************************************* -+ * helper functions to get some internal data -+ * ****************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Get current index of CPU DAI from runtime data of substream -+ * -+ * \param[in] substream Pointer to PCM stream data -+ * \retval id Index of current CPU DAI -+ *****************************************************************************/ -+static int snd_adsp_get_dai_id_from_substream -+ (struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; -+ return rtd->cpu_dai->id; -+} -+ -+/** ************************************************************************** -+ * \brief Get ADSP ALSA driver's data from runtime data of substream -+ * -+ * \param[in] substream Pointer to PCM stream data -+ * \retval pointer Pointer to driver's data -+ *****************************************************************************/ -+static void *snd_adsp_get_drvdata_from_substream -+ (struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; -+ return snd_soc_dai_get_drvdata(rtd->cpu_dai); -+} -+ -+/** ************************************************************************** -+ * \brief Get base's data of playback/record from runtime data of substream -+ * -+ * \param[in] substream Pointer to PCM stream data -+ * \retval pointer Pointer to playback/record's base data -+ *****************************************************************************/ -+static struct snd_adsp_base_info *snd_adsp_get_base_from_substream -+ (struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ struct snd_adsp_base_info *base; -+ int dai_idx; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ -+ /* get DAI index of substream */ -+ dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ -+ /* get base data of the substream */ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ base = (adsp_card->playback[dai_idx] == NULL) ? -+ NULL : &adsp_card->playback[dai_idx]->base; -+ } else { -+ base = (adsp_card->record[dai_idx] == NULL) ? -+ NULL : &adsp_card->record[dai_idx]->base; -+ } -+ } else { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ base = (adsp_card->tdm_playback == NULL) ? -+ NULL : &adsp_card->tdm_playback->base; -+ } else { -+ base = (adsp_card->tdm_record == NULL) ? -+ NULL : &adsp_card->tdm_record->base; -+ } -+ } -+ -+ return base; -+} -+ -+/** *************************************************************************** -+ * \brief Get playback/record/TDM playback/TDM record's base data -+ * from hr timer data -+ * -+ * \param[in] hrt Pointer to hr timer data -+ * \retval pointer Pointer to playback/record's base data -+ *****************************************************************************/ -+static struct snd_adsp_base_info *snd_adsp_get_base_from_hrt -+ (struct hrtimer *hrt) -+{ -+ return (struct snd_adsp_base_info *)hrt; -+} -+ -+/***************************************************************************** -+ * hrtimer interrupt function -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Interrupt function of high resolution timer -+ * -+ * \param[in] hrt Pointer to hr timer data -+ * \retval HRTIMER_RESTART Restart the timer after expire time -+ *****************************************************************************/ -+static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt) -+{ -+ struct snd_adsp_base_info *base = snd_adsp_get_base_from_hrt(hrt); -+ -+ spin_lock(&base->lock); -+ if (base->hw_idx != 0) { -+ /* update PCM status for the next period */ -+ spin_unlock(&base->lock); -+ snd_pcm_period_elapsed(base->substream); -+ } else { -+ spin_unlock(&base->lock); -+ } -+ -+ hrtimer_forward_now(hrt, base->ktime); -+ -+ return HRTIMER_RESTART; -+} -+ -+/***************************************************************************** -+ * internal functions to manage playback and record functions -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Initialize playback data -+ * -+ * \param[out] playback_data Pointer to store playback data -+ * \param[in] eqz_flag Flag to indicate equalizer usage -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize playback data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_playback_init -+ (struct snd_adsp_playback **playback_data, int eqz_flag, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_playback *playback; -+ -+ /* allocate memory for playback data */ -+ playback = kmalloc(sizeof(struct snd_adsp_playback), GFP_KERNEL); -+ if (playback == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(playback, 0, sizeof(struct snd_adsp_playback)); -+ -+ /* save the playback data */ -+ *playback_data = playback; -+ -+ /* set handle state as NULL state */ -+ playback->rdr_state = XF_HANDLE_NULL; -+ playback->eqz_state = XF_HANDLE_NULL; -+ playback->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register renderer component */ -+ if (xf_adsp_renderer_create(&playback->renderer, &rdr_callbacks, -+ (void *)&playback->base) < 0) -+ return -EINVAL; -+ -+ /* mark renderer component created */ -+ playback->rdr_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as renderer ID */ -+ playback->base.handle_id = playback->renderer->handle_id; -+ -+ if (eqz_flag == EQZ_ON) { -+ /* create equalizer component when equalizer is used */ -+ if (xf_adsp_equalizer_create(&playback->equalizer, -+ &rdr_callbacks, -+ (void *)&playback->base) < 0) -+ return -EINVAL; -+ -+ /* mark equalizer component created */ -+ playback->eqz_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as equalizer ID */ -+ playback->base.handle_id = playback->equalizer->handle_id; -+ } -+ -+ /* init lock */ -+ spin_lock_init(&playback->base.lock); -+ -+ /* save the substream data */ -+ playback->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&playback->base.hrtimer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ playback->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ playback->base.hrt_state = XF_HANDLE_CREATED; -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Initialize record data -+ * -+ * \param[out] record_data Pointer to store record data -+ * \param[in] eqz_flag Flag to indicate equalizer usage -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize record data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_record_init(struct snd_adsp_record **record_data, -+ int eqz_flag, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_record *record; -+ -+ /* allocate memory for record data */ -+ record = kmalloc(sizeof(struct snd_adsp_record), GFP_KERNEL); -+ if (record == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(record, 0, sizeof(struct snd_adsp_record)); -+ -+ /* save the record data */ -+ *record_data = record; -+ -+ /* set handle state as NULL state */ -+ record->cap_state = XF_HANDLE_NULL; -+ record->eqz_state = XF_HANDLE_NULL; -+ record->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register capture component */ -+ if (xf_adsp_capture_create(&record->capture, -+ &cap_callbacks, -+ (void *)&record->base) < 0) -+ return -EINVAL; -+ -+ /* mark capture component created */ -+ record->cap_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as capture ID */ -+ record->base.handle_id = record->capture->handle_id; -+ -+ /* create equalizer component in case of it being used */ -+ if (eqz_flag == EQZ_ON) { -+ if (xf_adsp_equalizer_create(&record->equalizer, -+ &cap_callbacks, -+ (void *)&record->base) < 0) -+ return -EINVAL; -+ -+ /* mark equalizer component created */ -+ record->eqz_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as equalizer ID */ -+ record->base.handle_id = record->equalizer->handle_id; -+ } -+ -+ /* init lock */ -+ spin_lock_init(&record->base.lock); -+ -+ /* save the substream data */ -+ record->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&record->base.hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ record->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ record->base.hrt_state = XF_HANDLE_CREATED; -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare playback function -+ * -+ * \param[out] playback Pointer to playback data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, hw_buffer_size; -+ int out_rate; -+ struct snd_adsp_control *ctr_if; -+ struct snd_pcm_runtime *runtime; -+ struct xf_adsp_renderer *renderer; -+ struct xf_adsp_equalizer *equalizer; -+ struct snd_adsp_base_info *base; -+ int i; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ ctr_if = &adsp_card->ctr_if; -+ runtime = substream->runtime; -+ renderer = playback->renderer; -+ equalizer = playback->equalizer; -+ base = &playback->base; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ ch = runtime->channels; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ vol_rate = ctr_if->vol_rate[DIRECT_PLAYBACK][dai_idx]; -+ out_rate = ctr_if->sample_rate[DIRECT_PLAYBACK][dai_idx]; -+ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ -+ if (pcm_width == 16) -+ base->buf_bytes = base->period_bytes; -+ else -+ base->buf_bytes = (base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = hw_buffer_size; -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ /* it should equal to a period size in bytes */ -+ base->pcm_indirect.hw_queue_size = base->period_bytes; -+ -+ /* set parameters when Renderer is not ready */ -+ if (COMPONENT_IS_READY(playback->rdr_state) == FALSE) { -+ struct xf_adsp_renderer_params *params = &renderer->params; -+ -+ /* apply renderer parameters */ -+ params->in_rate = fs; -+ params->channel = ch; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ if (ctr_if->mix_usage == SECOND_RUN) -+ params->mix_ctrl = ctr_if->mix_usage; -+ else -+ params->mix_ctrl = MIX_UNUSED; -+ -+ /* set flow as ADSP->PDMA0->SRC0->PDMA1->SSI0 */ -+ params->dev1 = SRC0; -+ params->dev2 = SSI00; -+ params->dma1 = PDMA_CH00; -+ params->dma2 = PDMA_CH01; -+ -+ /* when MIX is enabled, change to DMAC transfer type to save */ -+ /* hw FIFO */ -+ if (MIX_ENABLED(params->mix_ctrl) == TRUE) -+ params->dma1 = ADMAC_CH01; -+ -+ /* set volume rate if it is set by user or default value */ -+ /* is 100% */ -+ if (vol_rate >= 0) -+ params->vol_rate = vol_rate; -+ else -+ params->vol_rate = (1 << 20); -+ -+ /* set output channel if it is set by user */ -+ if (ctr_if->rdr_out_ch[dai_idx] >= MONAURAL) -+ params->out_channel = ctr_if->rdr_out_ch[dai_idx]; -+ else -+ params->out_channel = params->channel; -+ -+ /* set sample rate output if it is set by user */ -+ if (out_rate >= 0) -+ params->out_rate = out_rate; -+ -+ /* set parameters to ADSP Renderer plugin */ -+ if (xf_adsp_renderer_set_params(renderer) != 0) -+ return -EINVAL; -+ -+ /* allocate buffer pool to prepare the execution */ -+ renderer->buf_pool = xf_adsp_allocate_mem_pool( -+ XF_BUF_POOL_SIZE, base->buf_bytes); -+ if (IS_ERR(renderer->buf_pool)) /* PRQA S 306*/ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = xf_adsp_get_data_from_pool( -+ renderer->buf_pool, i); -+ base->buf_queue++; -+ memset(base->buffer[i], 0, base->buf_bytes); -+ } -+ -+ /* mark Renderer ready */ -+ playback->rdr_state |= XF_HANDLE_READY; -+ -+ /* set parameters for Equalizer if it is used */ -+ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { -+ /* apply Equalizer parameter setting */ -+ equalizer->params.channel = ch; -+ equalizer->params.pcm_width = pcm_width; -+ equalizer->params.rate = fs; -+ -+ /* get equalizer parameters from control interface */ -+ /* data */ -+ snd_adsp_get_eqz_params_from_control( -+ &equalizer->params, -+ &ctr_if->eqz_params[DIRECT_PLAYBACK][dai_idx], -+ true); -+ -+ /* set parameters to Equalizer plugin */ -+ if (xf_adsp_equalizer_set_params(equalizer) != 0) -+ return -EINVAL; -+ -+ /* route Equalizer to Renderer */ -+ if (xf_adsp_route(equalizer->handle_id, -+ renderer->handle_id, -+ XF_BUF_POOL_SIZE, -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ /* mark Equalizer ready */ -+ playback->eqz_state |= XF_HANDLE_READY; -+ -+ /* prepare data before start PCM */ -+ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ /* send buffer to plugin to kick */ -+ /* init-processing */ -+ if (xf_adsp_empty_this_buffer(base->handle_id, -+ base->buffer[i], base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ } -+ } else { -+ /* send zero buffer to plugin to kick */ -+ /* init-processing */ -+ if (xf_adsp_empty_this_buffer(base->handle_id, -+ base->buffer[0], base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ } -+ -+ /* wait until all the buffer have been consummed */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ /* reset HW index */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare record function -+ * -+ * \param[out] record Pointer to record data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_record_prepare(struct snd_adsp_record *record, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, in_rate; -+ int hw_buffer_size, hw_queue_size; -+ struct snd_adsp_control *ctr_if; -+ struct snd_pcm_runtime *runtime; -+ struct xf_adsp_capture *capture; -+ struct xf_adsp_equalizer *equalizer; -+ struct snd_adsp_base_info *base; -+ int i; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ ctr_if = &adsp_card->ctr_if; -+ runtime = substream->runtime; -+ capture = record->capture; -+ equalizer = record->equalizer; -+ base = &record->base; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ ch = runtime->channels; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ vol_rate = ctr_if->vol_rate[DIRECT_CAPTURE][dai_idx]; -+ in_rate = ctr_if->sample_rate[DIRECT_CAPTURE][dai_idx]; -+ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ /* total size of allocated buffers */ -+ hw_queue_size = base->period_bytes * XF_BUF_POOL_SIZE; -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ -+ if (pcm_width == 16) -+ base->buf_bytes = base->period_bytes; -+ else -+ base->buf_bytes = ((base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = hw_buffer_size; -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ base->pcm_indirect.hw_queue_size = hw_queue_size; -+ -+ /* prepare parameters to set to Capture plugin when it is not yet */ -+ /* ready */ -+ if (COMPONENT_IS_READY(record->cap_state) == FALSE) { -+ struct xf_adsp_capture_params *params = &capture->params; -+ -+ /* apply capture parameters */ -+ params->out_rate = fs; -+ params->channel = ch; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ params->dev1 = SRC0; -+ params->dev2 = SSI10; -+ params->dma1 = PDMA_CH00; -+ params->dma2 = PDMA_CH01; -+ -+ /* set volume rate if it is set by user or default volume as */ -+ /* 100% */ -+ if (vol_rate >= 0) -+ params->vol_rate = vol_rate; -+ else -+ params->vol_rate = (1 << 20); -+ -+ /* set sample rate input if it is set by user */ -+ if (in_rate >= 0) -+ params->in_rate = in_rate; -+ -+ /* allocate buffer pool to prepare the execution */ -+ capture->buf_pool = xf_adsp_allocate_mem_pool(XF_BUF_POOL_SIZE, -+ base->buf_bytes); -+ if (IS_ERR(capture->buf_pool)) /* PRQA S 306 */ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = xf_adsp_get_data_from_pool( -+ capture->buf_pool, i); -+ base->buf_queue++; -+ } -+ -+ /* set parameters to ADSP Capture plugin */ -+ if (xf_adsp_capture_set_params(capture) != 0) -+ return -EINVAL; -+ -+ /* mark Capture ready */ -+ record->cap_state |= XF_HANDLE_READY; -+ -+ /* set parameters for Equalizer if it's used */ -+ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { -+ /* apply Equalizer parameter setting */ -+ equalizer->params.channel = ch; -+ equalizer->params.pcm_width = pcm_width; -+ equalizer->params.rate = fs; -+ -+ /* get equalizer parameter from control interface */ -+ /* data */ -+ snd_adsp_get_eqz_params_from_control( -+ &equalizer->params, -+ &ctr_if->eqz_params[DIRECT_CAPTURE][dai_idx], -+ true); -+ -+ /* set parameters to Equalizer plugin */ -+ if (xf_adsp_equalizer_set_params(equalizer) != 0) -+ return -EINVAL; -+ -+ /* route Capture to Equalizer */ -+ if (xf_adsp_route(capture->handle_id, -+ equalizer->handle_id, -+ XF_BUF_POOL_SIZE, -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ -+ /* mark Equalizer ready */ -+ record->eqz_state |= XF_HANDLE_READY; -+ } -+ -+ /* kick init process by sending a zero buffer length */ -+ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* wait until finishing initialization */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { -+ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ /* send buffer to plugin */ -+ if (xf_adsp_fill_this_buffer( -+ base->handle_id, -+ base->buffer[i], -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ } -+ -+ /* wait until all the buffer have been responsed */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ } -+ -+ /* reset hw data position */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize playback function -+ * -+ * \param[out] playback Pointer to playback data -+ * \retval -EINVAL Failed to deinitialize playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if playback has been created already */ -+ if (IS_VALID(playback)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(playback->rdr_state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process *//* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(playback->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool */ /* PRQA S 3200 1 */ -+ xf_adsp_free_mem_pool(playback->renderer->buf_pool); -+ -+ /* destroy Renderer */ -+ if (xf_adsp_renderer_destroy(playback->renderer) != 0) -+ ret = -EINVAL; -+ -+ playback->renderer = NULL; -+ } -+ -+ /* destroy Equalizer if it is used */ -+ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { -+ if (xf_adsp_equalizer_destroy(playback->equalizer)) -+ ret = -EINVAL; -+ -+ playback->equalizer = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(playback->base.hrt_state) == TRUE) -+ hrtimer_cancel(&playback->base.hrtimer); -+ -+ /* free playback data */ -+ kfree(playback); -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize record function -+ * -+ * \param[out] record Pointer to record data -+ * \retval -EINVAL Failed to deinitialize record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_record_deinit(struct snd_adsp_record *record) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if record has been created already */ -+ if (IS_VALID(record)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(record->cap_state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process *//* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(record->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool */ /* PRQA S 3200 1 */ -+ xf_adsp_free_mem_pool(record->capture->buf_pool); -+ -+ if (xf_adsp_capture_destroy(record->capture)) -+ ret = -EINVAL; -+ -+ record->capture = NULL; -+ } -+ -+ /* destroy Equalizer if it is used */ -+ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { -+ if (xf_adsp_equalizer_destroy(record->equalizer) != 0) -+ ret = -EINVAL; -+ -+ record->equalizer = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(record->base.hrt_state) == TRUE) -+ hrtimer_cancel(&record->base.hrtimer); -+ -+ /* free record data */ -+ kfree(record); -+ } -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * internal functions to manage TDM playback and TDM record functions -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Initialize TDM playback data -+ * -+ * \param[out] tdm_playback_data Pointer to store TDM playback data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize TDM playback data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_playback_init( -+ struct snd_adsp_tdm_playback **tdm_playback_data, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_tdm_playback *tdm_playback; -+ -+ /* allocate memory for TDM playback data */ -+ tdm_playback = kmalloc(sizeof(struct snd_adsp_tdm_playback), -+ GFP_KERNEL); -+ if (tdm_playback == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(tdm_playback, 0, sizeof(struct snd_adsp_tdm_playback)); -+ -+ /* save the TDM playback data */ -+ *tdm_playback_data = tdm_playback; -+ -+ /* set handle state as NULL state */ -+ tdm_playback->state = XF_HANDLE_NULL; -+ tdm_playback->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register TDM renderer component */ -+ if (xf_adsp_tdm_renderer_create(&tdm_playback->tdm_renderer, -+ &rdr_callbacks, -+ (void *)&tdm_playback->base) < 0) -+ return -EINVAL; -+ -+ /* mark TDM renderer component created */ -+ tdm_playback->state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as TDM renderer ID */ -+ tdm_playback->base.handle_id = tdm_playback->tdm_renderer->handle_id; -+ -+ /* init lock */ -+ spin_lock_init(&tdm_playback->base.lock); -+ -+ /* save the substream data */ -+ tdm_playback->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&tdm_playback->base.hrtimer, -+ CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ tdm_playback->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ tdm_playback->base.hrt_state = XF_HANDLE_CREATED; -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Initialize TDM record data -+ * -+ * \param[out] tdm_record_data Pointer to store TDM record data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize TDM record data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_record_init( -+ struct snd_adsp_tdm_record **tdm_record_data, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_tdm_record *tdm_record; -+ -+ /* allocate memory for TDM record data */ -+ tdm_record = kmalloc(sizeof(struct snd_adsp_tdm_record), GFP_KERNEL); -+ if (tdm_record == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(tdm_record, 0, sizeof(struct snd_adsp_tdm_record)); -+ -+ /* save the TDM record data */ -+ *tdm_record_data = tdm_record; -+ -+ /* set handle state as NULL state */ -+ tdm_record->state = XF_HANDLE_NULL; -+ tdm_record->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register TDM Capture component */ -+ if (xf_adsp_tdm_capture_create(&tdm_record->tdm_capture, -+ &cap_callbacks, -+ (void *)&tdm_record->base) != 0) -+ return -EINVAL; -+ -+ /* mark TDM capture component created */ -+ tdm_record->state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as TDM capture ID */ -+ tdm_record->base.handle_id = tdm_record->tdm_capture->handle_id; -+ -+ /* init lock */ -+ spin_lock_init(&tdm_record->base.lock); -+ -+ /* save the substream data */ -+ tdm_record->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&tdm_record->base.hrtimer, -+ CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ tdm_record->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ tdm_record->base.hrt_state = XF_HANDLE_CREATED; -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare TDM playback function -+ * -+ * \param[out] tdm_playback Pointer to TDM playback data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare TDM playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_playback_prepare( -+ struct snd_adsp_tdm_playback *tdm_playback, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ struct snd_adsp_control *ctr_if; -+ struct snd_pcm_runtime *runtime; -+ struct xf_adsp_tdm_renderer *tdm_renderer; -+ struct snd_adsp_base_info *base; -+ int i; -+ int pcm_width, ch_mode, fs, frame_size, hw_buffer_size; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ ctr_if = &adsp_card->ctr_if; -+ runtime = substream->runtime; -+ tdm_renderer = tdm_playback->tdm_renderer; -+ base = &tdm_playback->base; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ ch_mode = (runtime->channels == 8) ? -+ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; -+ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ -+ if (pcm_width == 16) -+ base->buf_bytes = base->period_bytes; -+ else -+ base->buf_bytes = ((base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) / -+ BYTES_PER_SAMPLE(S24_LE)); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = hw_buffer_size; -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ /* it should equal to a period size in bytes */ -+ base->pcm_indirect.hw_queue_size = base->period_bytes; -+ -+ /* prepare parameters to set to TDM playback as it is not ready */ -+ if (COMPONENT_IS_READY(tdm_playback->state) == FALSE) { -+ struct xf_adsp_tdm_renderer_params *params = -+ &tdm_renderer->params; -+ -+ /* apply renderer parameters */ -+ params->in_rate = fs; -+ params->ch_mode = ch_mode; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ /* setting Audio device indexes */ -+ params->dma1 = ADMAC_CH00; /* use DMAC for transfer data */ -+ params->dma2 = PDMA_CH03; -+ params->dev1 = SRC1; -+ params->dev2 = SSI30; /* set SSI index to SSI30 */ -+ -+ /* set volume rate if it is set by user or default value as */ -+ /* 100% */ -+ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] >= 0) -+ ? ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] : (1 << 20); -+ -+ /* set output sampling rate if it is set by user */ -+ if (ctr_if->tdm_sample_rate[DIRECT_PLAYBACK] >= 0) -+ params->out_rate = -+ ctr_if->tdm_sample_rate[DIRECT_PLAYBACK]; -+ -+ /* set parameters to ADSP TDM Renderer plugin */ -+ if (xf_adsp_tdm_renderer_set_params(tdm_renderer) != 0) -+ return -EINVAL; -+ -+ /* allocate buffer pool to prepare the execution */ -+ tdm_renderer->buf_pool = -+ xf_adsp_allocate_mem_pool(XF_BUF_POOL_SIZE, -+ base->buf_bytes); -+ if (IS_ERR(tdm_renderer->buf_pool)) /* PRQA S 306*/ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = -+ xf_adsp_get_data_from_pool( -+ tdm_renderer->buf_pool, i); -+ base->buf_queue++; -+ } -+ -+ /* mark TDM Renderer created */ -+ tdm_playback->state |= XF_HANDLE_READY; -+ -+ /* send zero buffer to plugin to kick init-processing */ -+ memset(base->buffer[0], 0, base->buf_bytes); -+ if (xf_adsp_empty_this_buffer(base->handle_id, base->buffer[0], -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* wait until all the buffer have been consummed */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ /* reset HW index */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare TDM record function -+ * -+ * \param[out] tdm_record Pointer to TDM record data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare TDM record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_record_prepare( -+ struct snd_adsp_tdm_record *tdm_record, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct xf_adsp_tdm_capture *tdm_capture = tdm_record->tdm_capture; -+ struct snd_adsp_base_info *base = &tdm_record->base; -+ int i; -+ int pcm_width, ch_mode, fs, frame_size; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ ch_mode = (runtime->channels == 8) ? -+ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ base->buf_bytes = (pcm_width == 16) ? base->period_bytes : -+ ((base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) -+ / BYTES_PER_SAMPLE(S24_LE)); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = -+ snd_pcm_lib_buffer_bytes(substream); -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ /* total size of allocated buffers */ -+ base->pcm_indirect.hw_queue_size = base->period_bytes * -+ XF_BUF_POOL_SIZE; -+ -+ /* prepare parameters to set to TDM Capture as it is not yet ready */ -+ if (COMPONENT_IS_READY(tdm_record->state) == FALSE) { -+ struct xf_adsp_tdm_capture_params *params = -+ &tdm_capture->params; -+ -+ /* apply capture parameters */ -+ params->out_rate = fs; -+ params->ch_mode = ch_mode; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ /* setting Audio device indexes */ -+ params->dma1 = PDMA_CH00; -+ params->dma2 = PDMA_CH01; -+ params->dev1 = SRC0; -+ params->dev2 = SSI40; /* set input device is SSI40 */ -+ -+ /* set volume rate if it is set by user or default value as */ -+ /* 100% */ -+ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_CAPTURE] >= 0) -+ ? ctr_if->tdm_vol_rate[DIRECT_CAPTURE] : (1 << 20); -+ -+ /* set input rate if it is set by user */ -+ if (ctr_if->tdm_sample_rate[DIRECT_CAPTURE] >= 0) { -+ params->in_rate = -+ ctr_if->tdm_sample_rate[DIRECT_CAPTURE]; -+ } -+ -+ /* allocate buffer pool to prepare the execution */ -+ tdm_capture->buf_pool = xf_adsp_allocate_mem_pool( -+ XF_BUF_POOL_SIZE, base->buf_bytes); -+ if (IS_ERR(tdm_capture->buf_pool)) /* PRQA S 306 */ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = xf_adsp_get_data_from_pool( -+ tdm_capture->buf_pool, i); -+ base->buf_queue++; -+ } -+ -+ /* set parameters to ADSP TDM Capture plugin */ -+ if (xf_adsp_tdm_capture_set_params(tdm_capture) != 0) -+ return -EINVAL; -+ -+ /* mark TDM Capture ready */ -+ tdm_record->state |= XF_HANDLE_READY; -+ -+ /* kick init process by sending a zero buffer length */ -+ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* wait until finishing initialization */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ /* reset hw data position */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize TDM playback function -+ * -+ * \param[out] tdm_playback Pointer to TDM playback data -+ * \retval -EINVAL Failed to deinitialize TDM playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_playback_deinit( -+ struct snd_adsp_tdm_playback *tdm_playback) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if TDM playback has been created */ -+ /* already */ -+ if (IS_VALID(tdm_playback)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(tdm_playback->state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process */ -+ /* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(tdm_playback->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool *//* PRQA S 3200 2 */ -+ xf_adsp_free_mem_pool( -+ tdm_playback->tdm_renderer->buf_pool); -+ -+ /* destroy TDM Renderer component */ -+ if (xf_adsp_tdm_renderer_destroy( -+ tdm_playback->tdm_renderer) != 0) -+ ret = -EINVAL; -+ -+ tdm_playback->tdm_renderer = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(tdm_playback->base.hrt_state) == TRUE) -+ hrtimer_cancel(&tdm_playback->base.hrtimer); -+ -+ /* free playback data */ -+ kfree(tdm_playback); -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize TDM record function -+ * -+ * \param[out] tdm_record Pointer to TDM record data -+ * \retval -EINVAL Failed to deinitialize TDM record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if TDM record has been created already */ -+ if (IS_VALID(tdm_record)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(tdm_record->state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process */ -+ /* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(tdm_record->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool *//* PRQA S 3200 2 */ -+ xf_adsp_free_mem_pool( -+ tdm_record->tdm_capture->buf_pool); -+ -+ /* destroy TDM Capture component */ -+ if (xf_adsp_tdm_capture_destroy( -+ tdm_record->tdm_capture) != 0) -+ ret = -EINVAL; -+ -+ tdm_record->tdm_capture = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(tdm_record->base.hrt_state) == TRUE) -+ hrtimer_cancel(&tdm_record->base.hrtimer); -+ -+ /* free record data */ -+ kfree(tdm_record); -+ } -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * callback functions of ADSP ALSA driver -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Open a playback/TDM playback or record/TDM record stream -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_open(struct snd_pcm_substream *substream) -+{ -+ /* get ADSP soundcard and CPU DAI index */ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ /* register data for playback/record functions */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* perform playback initialization */ -+ if (snd_adsp_playback_init( -+ &adsp_card->playback[dai_idx], -+ adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][dai_idx], -+ substream) < 0) { -+ /* perform playback de-initialization when */ -+ /* the initialization fails */ -+ snd_adsp_playback_deinit( -+ adsp_card->playback[dai_idx]); -+ adsp_card->playback[dai_idx] = NULL; -+ return -EINVAL; -+ } -+ } else { -+ /* perform record initialization */ -+ if (snd_adsp_record_init(&adsp_card->record[dai_idx], -+ adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][dai_idx], -+ substream) < 0) { -+ /* perform record de-initialization when the */ -+ /* initialization fails */ -+ snd_adsp_record_deinit( -+ adsp_card->record[dai_idx]); -+ adsp_card->record[dai_idx] = NULL; -+ return -EINVAL; -+ } -+ } -+ -+ /* save the hardware parameters */ -+ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_hw); -+ -+ /* each period has a frame size */ -+ snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ FRAME_SIZE); -+ } else { -+ /* register data for TDM playback/record functions */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* perform TDM playback initialization */ -+ if (snd_adsp_tdm_playback_init( -+ &adsp_card->tdm_playback, substream) < 0) { -+ /* perform TDM playback de-initialization */ -+ /* when the initialization fails */ -+ snd_adsp_tdm_playback_deinit( -+ adsp_card->tdm_playback); -+ adsp_card->tdm_playback = NULL; -+ return -EINVAL; -+ } -+ } else { -+ /* perform TDM record initialization */ -+ if (snd_adsp_tdm_record_init(&adsp_card->tdm_record, -+ substream) < 0) { -+ /* perform TDM record de-initialization */ -+ /* when the initialization fails */ -+ snd_adsp_tdm_record_deinit( -+ adsp_card->tdm_record); -+ adsp_card->tdm_record = NULL; -+ return -EINVAL; -+ } -+ } -+ -+ /* save the hardware parameters */ -+ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_tdm_hw); -+ -+ /* each period has a frame size */ -+ snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, TDM_FRAME_SIZE); -+ } -+ -+ snd_pcm_hw_constraint_integer(substream->runtime, -+ SNDRV_PCM_HW_PARAM_PERIODS); -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Close a playback/TDM playback or record/TDM record stream -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_close(struct snd_pcm_substream *substream) -+{ -+ /* get ADSP soundcard and CPU DAI index */ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ int err = 0; -+ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ /* destroy Renderer/Capture or Equalizer (if used) */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (snd_adsp_playback_deinit( -+ adsp_card->playback[dai_idx]) < 0) -+ err = -EINVAL; -+ -+ adsp_card->playback[dai_idx] = NULL; -+ } else { -+ if (snd_adsp_record_deinit( -+ adsp_card->record[dai_idx]) < 0) -+ err = -EINVAL; -+ -+ adsp_card->record[dai_idx] = NULL; -+ } -+ } else { -+ /* destroy TDM Renderer/TDM Capture */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (snd_adsp_tdm_playback_deinit( -+ adsp_card->tdm_playback) < 0) -+ err = -EINVAL; -+ -+ adsp_card->tdm_playback = NULL; -+ } else { -+ if (snd_adsp_tdm_record_deinit( -+ adsp_card->tdm_record) < 0) -+ err = -EINVAL; -+ -+ adsp_card->tdm_record = NULL; -+ } -+ } -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ * \brief Allocate ALSA buffer and calculate expire time of hr timer -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -ENOMEM Cannot allocate ALSA buffer -+ *****************************************************************************/ -+static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ struct snd_adsp_base_info *base; -+ int err = 0; -+ -+ base = snd_adsp_get_base_from_substream(substream); -+ -+ /* set expire time of hrtimer, this value should be time for */ -+ /* transfer a frame */ -+ base->ktime = ns_to_ktime((1000000000 / params_rate(hw_params)) * -+ params_period_size(hw_params)); -+ -+ err = snd_pcm_lib_malloc_pages(substream, -+ params_buffer_bytes(hw_params)); -+ -+ /* reset DMA buffer area */ -+ memset(substream->runtime->dma_area, 0, substream->runtime->dma_bytes); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ * \brief Free the allocated ALSA buffer -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Cannot deallocate buffer -+ *****************************************************************************/ -+static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+/** ************************************************************************** -+ * \brief Prepare playback/TDM playback or record/TDM record function -+ * before transferring data -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ /* get ADSP soundcard and CPU DAI index */ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ int err = 0; -+ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ /* get playback prepared to execute */ -+ err = snd_adsp_playback_prepare( -+ adsp_card->playback[dai_idx], substream); -+ else -+ /* get record prepared to execute */ -+ err = snd_adsp_record_prepare( -+ adsp_card->record[dai_idx], substream); -+ } else { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ /* get TDM playback prepared to execute */ -+ err = snd_adsp_tdm_playback_prepare( -+ adsp_card->tdm_playback, substream); -+ else -+ /* get TDM record prepared to execute */ -+ err = snd_adsp_tdm_record_prepare( -+ adsp_card->tdm_record, substream); -+ } -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ * \brief Trigger playback/TDM playback or record/TDM record stream -+ * to go to next phase -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ -+ switch (idx) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ /* start high-resolution timer */ -+ hrtimer_start(&base->hrtimer, base->ktime, -+ HRTIMER_MODE_REL); -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { -+ int buf_queue = 0; -+ -+ /* get current available buffer */ -+ spin_lock(&base->lock); -+ buf_queue = base->buf_queue; -+ spin_unlock(&base->lock); -+ -+ /* send all available buffer to plugin to */ -+ /* get data */ -+ for (; buf_queue > 0; buf_queue--) { -+ if (xf_adsp_fill_this_buffer( -+ base->handle_id, -+ base->buffer[base->buf_idx], -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ base->buf_idx++; -+ if (base->buf_idx >= XF_BUF_POOL_SIZE) -+ base->buf_idx = 0; -+ } -+ } -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Return HW data position -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval position HW data position -+ *****************************************************************************/ -+static snd_pcm_uframes_t snd_adsp_pcm_pointer( -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ unsigned int hw_idx, hw_buffer_size; -+ snd_pcm_uframes_t pointer; -+ -+ /* convert hw index to correct as submitted bytes */ -+ spin_lock(&base->lock); -+ hw_idx = (base->hw_idx / base->buf_bytes) * base->period_bytes; -+ spin_unlock(&base->lock); -+ -+ hw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ if (hw_idx >= hw_buffer_size) { -+ spin_lock(&base->lock); -+ base->hw_idx -= (hw_buffer_size / base->period_bytes) * -+ base->buf_bytes; -+ spin_unlock(&base->lock); -+ } -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ pointer = snd_pcm_indirect_playback_pointer(substream, -+ &base->pcm_indirect, -+ hw_idx); -+ else -+ pointer = snd_pcm_indirect_capture_pointer(substream, -+ &base->pcm_indirect, -+ hw_idx); -+ -+ return pointer; -+} -+ -+/** ************************************************************************** -+ * \brief Call read/write process to transfer data -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ snd_pcm_indirect_playback_transfer(substream, -+ &base->pcm_indirect, -+ snd_adsp_pcm_transfer); -+ else -+ snd_pcm_indirect_capture_transfer(substream, -+ &base->pcm_indirect, -+ snd_adsp_pcm_transfer); -+ -+ return 0; -+} -+ -+/** *************************************************************************** -+ * \brief Copy data from source buffer to destination buffer -+ * -+ * \params[in] dst Destination buffer pointer -+ * \params[out] src Source buffer pointer -+ * \params[in] dst_size Destination buffer size in byte -+ * \params[in] src_size Source buffer size in byte -+ * \retval None -+ *****************************************************************************/ -+static inline void snd_adsp_copy_data(void *dst, void *src, int dst_size, -+ int src_size) -+{ -+ unsigned char *data_dst = dst; -+ unsigned char *data_src = src; -+ int i; -+ -+ if (dst_size == src_size) -+ /* src and dst buffers are same size, does not need to */ -+ /* convert */ -+ memcpy(data_dst, data_src, dst_size); -+ else if (dst_size < src_size) { -+ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_3LE)); -+ i += BYTES_PER_SAMPLE(S24_3LE)) { -+ *(u32 *)data_dst = *(u32 *)data_src; -+ -+ data_dst += BYTES_PER_SAMPLE(S24_3LE); -+ data_src += BYTES_PER_SAMPLE(S24_LE); -+ } -+ -+ SAMPLE_COPY(data_dst, data_src, S24_3LE, S24_LE); -+ } else { -+ unsigned int tmp; -+ -+ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_LE)); -+ i += BYTES_PER_SAMPLE(S24_LE)) { -+ tmp = *(u32 *)data_src; -+ *(u32 *)data_dst = tmp & 0x0FFFFFF; -+ -+ data_dst += BYTES_PER_SAMPLE(S24_LE); -+ data_src += BYTES_PER_SAMPLE(S24_3LE); -+ } -+ -+ SAMPLE_COPY(data_dst, data_src, S24_LE, S24_3LE); -+ } -+} -+ -+/** ************************************************************************** -+ * \brief Transfer data process between ALSA buffer and ADSP buffer -+ * -+ * \param[in] substream Pointer to substream object -+ * \param[in] rec Pointer to indirect PCM data -+ * \param[in] bytes Number of byte need to be transferred -+ * \retval None -+ *****************************************************************************/ -+static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ int direct = substream->stream; -+ int trans_bytes = bytes; -+ int buf_bytes, period_bytes; -+ void *dma_buf, *data_buff; -+ -+ /* get the DMA buffer pointer */ -+ dma_buf = (void *)(substream->runtime->dma_area + rec->sw_data); -+ -+ /* get information from base */ -+ buf_bytes = base->buf_bytes; -+ period_bytes = base->period_bytes; -+ -+ /* make sure the available buffer and transfer size - TBD */ -+ while (trans_bytes > 0) { -+ spin_lock(&base->lock); -+ if ((base->buf_queue > 0) && (trans_bytes >= period_bytes)) { -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* get the buffer pointer from stream */ -+ data_buff = base->buffer[base->buf_idx]; -+ -+ if (direct == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* copy data from user *//* PRQA S 3200 2 */ -+ snd_adsp_copy_data(data_buff, dma_buf, -+ buf_bytes, period_bytes); -+ -+ /* send buffer to plugin */ -+ if (xf_adsp_empty_this_buffer(base->handle_id, -+ data_buff, -+ buf_bytes) < 0) -+ base->runtime_err = TRUE; -+ } else { -+ /* copy data to user *//* PRQA S 3200 2 */ -+ snd_adsp_copy_data(dma_buf, data_buff, -+ period_bytes, buf_bytes); -+ -+ /* send buffer to plugin */ -+ if (xf_adsp_fill_this_buffer(base->handle_id, -+ data_buff, -+ buf_bytes) < 0) -+ base->runtime_err = TRUE; -+ } -+ -+ base->buf_idx++; -+ if (base->buf_idx >= XF_BUF_POOL_SIZE) -+ base->buf_idx = 0; -+ } else { -+ spin_unlock(&base->lock); -+ break; -+ } -+ -+ trans_bytes -= period_bytes; -+ } -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Volume control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of volume control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = -1; -+ uinfo->value.integer.max = 799; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get volume value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to volume value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; -+ int handle_state, handle_id; -+ int volume, cmd_idx, direction; -+ unsigned int index; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* determine command index, direction, handle state, handle ID */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = -+ adsp_card->playback[index]->renderer->handle_id; -+ } -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->cap_state; -+ handle_id = -+ adsp_card->record[index]->capture->handle_id; -+ } -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) { -+ handle_state = adsp_card->tdm_playback->state; -+ handle_id = -+ adsp_card->tdm_playback->tdm_renderer->handle_id; -+ } -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) { -+ handle_state = adsp_card->tdm_record->state; -+ handle_id = -+ adsp_card->tdm_record->tdm_capture->handle_id; -+ } -+ } -+ } -+ -+ /* get the volume's value */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* get the volume's value from the plugin */ -+ if (xf_adsp_get_param(handle_id, cmd_idx, &volume) != 0) -+ return -EINVAL; -+ -+ /* check the value after getting it and adjust it */ -+ ucontrol->value.integer.value[0] = (volume == 0xFFFFFFFF) ? -+ (-1) : (volume * VOLUME_SCALE) >> 20; -+ } else { -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) -+ ucontrol->value.integer.value[0] = -+ (ctr_if->vol_rate[direction][index] -+ * VOLUME_SCALE) >> 20; -+ else -+ ucontrol->value.integer.value[0] = -+ (ctr_if->tdm_vol_rate[direction] -+ * VOLUME_SCALE) >> 20; -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set volume value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to volume value -+ * \retval 1 Volume change -+ * \retval 0 Volume does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) /* PRQA S 3673 */ -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; -+ int volume; -+ int ret; -+ int handle_state, handle_id, cmd_idx, volume_get; -+ int direction; -+ unsigned int index; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state and handle ID */ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* get the value to set */ -+ if (ucontrol->value.integer.value[0] == -1) -+ volume = 0xFFFFFFFF; -+ else { -+ /* round up the value if needed */ -+ volume = (ucontrol->value.integer.value[0] * (1 << 20)) / -+ VOLUME_SCALE; -+ if ((ucontrol->value.integer.value[0] * (1 << 20)) > -+ (VOLUME_SCALE * volume)) -+ volume += 1; -+ } -+ -+ /* determine command index, direction, handle state, handle ID */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = -+ adsp_card->playback[index]->renderer->handle_id; -+ } -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->cap_state; -+ handle_id = -+ adsp_card->record[index]->capture->handle_id; -+ } -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) { -+ handle_state = adsp_card->tdm_playback->state; -+ handle_id = -+ adsp_card->tdm_playback->tdm_renderer->handle_id; -+ } -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) { -+ handle_state = adsp_card->tdm_record->state; -+ handle_id = -+ adsp_card->tdm_record->tdm_capture->handle_id; -+ } -+ } -+ } -+ -+ /* set volume to plugin */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* TDM does not support set volume in runtime state */ -+ if (kcontrol->id.name[0] == PREFIX_OF_TDM_CTR_NAME) -+ return -EINVAL; -+ -+ /* apply set volume value to ADSP from user setting */ -+ if (xf_adsp_set_param(handle_id, cmd_idx, volume) != 0) -+ return -EINVAL; -+ -+ /* get volume from ADSP after setting to confirm */ -+ if (xf_adsp_get_param(handle_id, cmd_idx, &volume_get) != 0) -+ return -EINVAL; -+ -+ /* check if the value has changed */ -+ ret = (volume_get == volume) ? 1 : 0; -+ } else { -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) -+ ctr_if->vol_rate[direction][index] = volume; -+ else -+ ctr_if->tdm_vol_rate[direction] = volume; -+ -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Sample Rate Converter control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of sample rate -+ * converter control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = -1; -+ uinfo->value.integer.max = 48000; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get sample rate value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to sample rate value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int *rate; -+ int handle_id, handle_state, cmd_idx, direction; -+ unsigned int index; -+ -+ rate = (int *)&(ucontrol->value.integer.value[0]); /* PRQA S 310 */ -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state and handle ID */ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* determine command, direction, handle state, handle ID */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = -+ adsp_card->playback[index]->renderer->handle_id; -+ } -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->cap_state; -+ handle_id = -+ adsp_card->record[index]->capture->handle_id; -+ } -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) { -+ handle_state = adsp_card->tdm_playback->state; -+ handle_id = -+ adsp_card->tdm_playback->tdm_renderer->handle_id; -+ } -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) { -+ handle_state = adsp_card->tdm_record->state; -+ handle_id = -+ adsp_card->tdm_record->tdm_capture->handle_id; -+ } -+ } -+ } -+ -+ /* get parameter from plugin */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ if (xf_adsp_get_param(handle_id, cmd_idx, rate) != 0) -+ return -EINVAL; -+ } else { -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) { -+ *rate = -+ adsp_card->ctr_if.sample_rate[direction][index]; -+ } else { -+ *rate = adsp_card->ctr_if.tdm_sample_rate[direction]; -+ } -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set sample rate value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to sample rate value -+ * \retval 1 Sample rate change -+ * \retval 0 Sample rate does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) /* PRQA S 3673 */ -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ unsigned int index; -+ int rate; -+ int handle_state, cmd_idx, direction; -+ int ret = 1; -+ -+ rate = (int)ucontrol->value.integer.value[0]; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* determine command, direction and handle state */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->rdr_state; -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) -+ handle_state = adsp_card->record[index]->cap_state; -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) -+ handle_state = adsp_card->tdm_playback->state; -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) -+ handle_state = adsp_card->tdm_record->state; -+ } -+ } -+ -+ /* get the value to set */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ return -EINVAL; -+ -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) -+ adsp_card->ctr_if.sample_rate[direction][index] = rate; -+ else -+ adsp_card->ctr_if.tdm_sample_rate[direction] = rate; -+ -+ ret = 1; -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Equalizer control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of Equalizer control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = MAX_EQZ_PARAM_NUMBER; -+ uinfo->value.integer.min = -1; -+ uinfo->value.integer.max = 0x7fffffff; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get equalizer parameters value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer parameters value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int handle_state, direction; -+ int i, j, filter_index; -+ unsigned int index; -+ struct xf_adsp_equalizer *equalizer; -+ struct xf_adsp_equalizer_params *eqz_params; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determin direction of stream */ -+ direction = (kcontrol->id.name[0] == -+ PREFIX_OF_PLAYBACK_CTR_NAME) ? DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* set handle state as NULL state, handle ID, equalizer pointer */ -+ handle_state = XF_HANDLE_NULL; -+ equalizer = NULL; -+ -+ /* get component's state */ -+ if (direction == DIRECT_PLAYBACK) { -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->eqz_state; -+ equalizer = adsp_card->playback[index]->equalizer; -+ } -+ } else { -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->eqz_state; -+ equalizer = adsp_card->record[index]->equalizer; -+ } -+ } -+ -+ /* perform parameters' values getting */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* get equalizer's parameters */ -+ if (xf_adsp_equalizer_get_params(equalizer) != 0) -+ return -EINVAL; -+ -+ eqz_params = &equalizer->params; -+ } else -+ eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; -+ -+ /* get equalizer type: PARAMETRIC or GRAPHIC */ -+ ucontrol->value.integer.value[0] = eqz_params->eqz_type; -+ -+ /* get parameters' value from Equalizer plugin */ -+ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { -+ for (i = 0, filter_index = 1; -+ filter_index <= XA_REL_EQZ_FILTER_NUM; -+ i++, filter_index++) { -+ /* get filter index */ -+ ucontrol->value.integer.value[(i * 6) + 1] = -+ filter_index; -+ -+ /* get frequency centre */ -+ ucontrol->value.integer.value[(i * 6) + 2] = -+ eqz_params->p_coef.fc[i]; -+ -+ /* get bandwidth */ -+ ucontrol->value.integer.value[(i * 6) + 3] = -+ eqz_params->p_coef.band_width[i]; -+ -+ /* get filter type */ -+ ucontrol->value.integer.value[(i * 6) + 4] = -+ eqz_params->p_coef.type[i]; -+ -+ /* get gain base */ -+ ucontrol->value.integer.value[(i * 6) + 5] = -+ eqz_params->p_coef.gain_base[i]; -+ -+ /* get gain */ -+ ucontrol->value.integer.value[(i * 6) + 6] = -+ eqz_params->p_coef.gain[i]; -+ } -+ } else { -+ for (i = 0, filter_index = 1; -+ filter_index <= XA_REL_EQZ_GRAPHIC_BAND_NUM; -+ i++, filter_index++) { -+ /* get band index */ -+ ucontrol->value.integer.value[(i * 2) + 1] = -+ filter_index; -+ -+ /* get graphic gain */ -+ ucontrol->value.integer.value[(i * 2) + 2] = -+ eqz_params->g_coef.gain_g[i]; -+ } -+ -+ j = (i * 2) + 1; -+ -+ /* make the rest of values silent */ -+ while (j < MAX_EQZ_PARAM_NUMBER) { -+ ucontrol->value.integer.value[j] = -1; -+ j++; -+ } -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set equalizer parameters value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer parameters value -+ * \retval 1 Equalizer parameters change -+ * \retval 0 Equalizer parameters does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+/* PRQA S 3673 1*/ -+static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int handle_state, direction, filter_idx; -+ int i; -+ int index; -+ int ret = 0; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determine the direction */ -+ direction = (kcontrol->id.name[0] == -+ PREFIX_OF_PLAYBACK_CTR_NAME) ? DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* get the handle state */ -+ if (direction == DIRECT_PLAYBACK) { -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->eqz_state; -+ } else { -+ if (IS_VALID(adsp_card->record[index])) -+ handle_state = adsp_card->record[index]->eqz_state; -+ } -+ -+ /* perform equalizer's parameters setting */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ ret = -EINVAL; -+ else { -+ /* PRQA S 310 1*/ -+ struct xf_adsp_equalizer_params *eqz_params = -+ &adsp_card->ctr_if.eqz_params[direction][index]; -+ -+ i = 0; -+ /* PRQA S 3440 1*/ -+ eqz_params->eqz_type = ucontrol->value.integer.value[i]; -+ i++; -+ filter_idx = 0; -+ -+ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { -+ while (i < MAX_EQZ_PARAM_NUMBER) { -+ /* get index filter */ -+ /* PRQA S 3440*/ -+ filter_idx = ucontrol->value.integer.value[i]; -+ i++; -+ -+ /* valid index filter is range */ -+ /* (1 to XA_REL_EQZ_FILTER_NUM) */ -+ if ((filter_idx >= 1) && -+ (filter_idx <= XA_REL_EQZ_FILTER_NUM)) { -+ /* PRQA S 3440 5*/ -+ eqz_params->p_coef.fc[filter_idx - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.band_width[ -+ filter_idx - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.type[filter_idx - 1] -+ = ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.gain_base[ -+ filter_idx - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.gain[filter_idx - 1] -+ = ucontrol->value.integer.value[i]; -+ i++; -+ } -+ /* index filter = -1 means that user */ -+ /* does not set this filter */ -+ else if (filter_idx == -1 || filter_idx == 0) -+ i += 5; -+ else -+ return -EINVAL; -+ } -+ } else if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_GRAPHIC) { -+ while (i < ((XA_REL_EQZ_GRAPHIC_BAND_NUM * 2) + 1)) { -+ /*get index filter */ -+ /* PRQA S 3440 */ -+ filter_idx = ucontrol->value.integer.value[i++]; -+ -+ if ((filter_idx >= 1) && (filter_idx <= -+ XA_REL_EQZ_GRAPHIC_BAND_NUM)) { -+ eqz_params->g_coef.gain_g[filter_idx -+ - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ } else if (filter_idx == -1 || -+ filter_idx == 0) -+ i += 1; -+ else -+ return -EINVAL; -+ } -+ } else -+ return -EINVAL; -+ -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Equalizer Switch control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of Equalizer -+ * Switch control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 1; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get equalizer switch value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer switch value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int direction; -+ unsigned int index; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determine the direction */ -+ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? -+ DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* get the Equalizer switch status */ -+ ucontrol->value.integer.value[0] = -+ adsp_card->ctr_if.eqz_switch[direction][index]; -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set equalizer switch value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer switch value -+ * \retval 1 Equalizer switch change -+ * \retval 0 Equalizer switch does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) /* PRQA S 3673 */ -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int eqz_switch; -+ int handle_state, direction; -+ unsigned int index; -+ int ret = 0; -+ -+ eqz_switch = ucontrol->value.integer.value[0]; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determine the direction */ -+ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? -+ DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* determine handle state */ -+ if (direction == DIRECT_PLAYBACK) { -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->rdr_state; -+ } else { -+ if (IS_VALID(adsp_card->record[index])) -+ handle_state = adsp_card->record[index]->cap_state; -+ } -+ -+ /* set the status of Equalizer */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ /* runtime setting is not supported */ -+ ret = -EINVAL; -+ else { -+ adsp_card->ctr_if.eqz_switch[direction][index] = eqz_switch; -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Renderer output channel -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of Renderer output channel -+ * \retval 0 Success -+ *****************************************************************************/ -+static -+int snd_adsp_control_rdr_out_channel_info(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = MONAURAL; -+ uinfo->value.integer.max = STEREO; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get Renderer output channel's value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to Renderer output channel value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static -+int snd_adsp_control_rdr_out_channel_get(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int rdr_out_ch; -+ unsigned int index; -+ int handle_state, handle_id; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* determine handle state and handle ID */ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = adsp_card->playback[index]->renderer->handle_id; -+ } -+ -+ /* get Renderer output channel's value */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* get Renderer output channel's value from Renderer plugin */ -+ if (xf_adsp_get_param(handle_id -+ , XA_RDR_CONFIG_PARAM_OUT_CHANNELS -+ , &rdr_out_ch) != 0) { -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = rdr_out_ch; -+ } else { -+ ucontrol->value.integer.value[0] = -+ adsp_card->ctr_if.rdr_out_ch[index]; -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set Renderer output channel's value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to Renderer output channel value -+ * \retval 1 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static -+int snd_adsp_control_rdr_out_channel_put(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ unsigned int index; -+ int handle_state; -+ int ret = 1; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* determine handle state and handle ID */ -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->rdr_state; -+ -+ /* get Renderer output channel's value */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ /* not support runtime setting */ -+ ret = -EINVAL; -+ else -+ adsp_card->ctr_if.rdr_out_ch[index] = -+ ucontrol->value.integer.value[0]; -+ -+ return ret; -+} -+ -+/** control interface for playback's volume rate */ -+/* PRQA S 3218 */ -+static -+struct snd_kcontrol_new snd_adsp_playback_volume_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ } -+}; -+ -+/** control interface for Capture's volume rate */ -+/* PRQA S 3218 1*/ -+static -+struct snd_kcontrol_new snd_adsp_capture_volume_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ } -+}; -+ -+/** control interface for playback's output sample rate */ -+/* PRQA S 3218 1*/ -+static struct snd_kcontrol_new -+ snd_adsp_playback_sample_rate_out_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ } -+}; -+ -+/** control interface for Capture's input sample rate */ -+/* PRQA S 3218 */ -+static struct snd_kcontrol_new -+ snd_adsp_capture_sample_rate_in_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ } -+}; -+ -+/** control interface for Equalizer parameters in playback */ -+/* PRQA S 3218 1*/ -+static struct snd_kcontrol_new -+ snd_adsp_playback_equalizer_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ } -+}; -+ -+/** control interface for Equalizer parameters in record */ -+/* PRQA S 3218 */ -+static struct snd_kcontrol_new -+ snd_adsp_capture_equalizer_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ } -+}; -+ -+/** control interface for Equalizer usage in playback */ -+/* PRQA S 3218 */ -+static struct snd_kcontrol_new -+snd_adsp_playback_equalizer_switch_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ } -+}; -+ -+/** control interface for Equalizer usage in record */ -+/* PRQA S 3218 1*/ -+static struct snd_kcontrol_new -+ snd_adsp_capture_equalizer_switch_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ } -+}; -+ -+/** control interface for playback's output channel */ -+static struct snd_kcontrol_new -+snd_adsp_playback_out_channel_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ } -+}; -+ -+/** control interface for TDM playback's volume rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_playback_volume_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+}; -+ -+/** control interface for TDM capture's volume rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_capture_volume_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+}; -+ -+/** control interface for TDM playback's output sample rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_playback_sample_rate_out_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+}; -+ -+/** control interface for TDM capture's input sample rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_capture_sample_rate_in_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+}; -+ -+/** PCM callback function of the sound card */ -+static struct snd_pcm_ops snd_adsp_pcm_ops = { -+ .open = &snd_adsp_pcm_open, /* PRQA S 1053 10 */ -+ .close = &snd_adsp_pcm_close, -+ .ioctl = &snd_pcm_lib_ioctl, -+ .hw_params = &snd_adsp_pcm_hw_params, -+ .hw_free = &snd_adsp_pcm_hw_free, -+ .prepare = &snd_adsp_pcm_prepare, -+ .trigger = &snd_adsp_pcm_trigger, -+ .pointer = &snd_adsp_pcm_pointer, -+ .ack = &snd_adsp_pcm_ack -+}; -+ -+/******************************************************************* -+ * Internal functions -+ * ****************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Process information get from control structure -+ * -+ * \param[in] eqz_params Equalizer parameters object -+ * \param[in] eqz_ctr_params Equalizer parameters stored in control object -+ * \param[in] flag Indicate playback or capture stream -+ *****************************************************************************/ -+static void snd_adsp_get_eqz_params_from_control( -+ struct xf_adsp_equalizer_params *eqz_params, -+ struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag) -+{ -+ int filter_idx; -+ -+ if (flag == true) { -+ if (eqz_ctr_params->eqz_type >= 0) -+ eqz_params->eqz_type = eqz_ctr_params->eqz_type; -+ -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; -+ filter_idx++) { -+ if (eqz_ctr_params->p_coef.fc[filter_idx] >= 0) -+ eqz_params->p_coef.fc[filter_idx] = -+ eqz_ctr_params->p_coef.fc[filter_idx]; -+ if (eqz_ctr_params->p_coef.band_width[filter_idx] >= 0) -+ eqz_params->p_coef.band_width[filter_idx] = -+ eqz_ctr_params->p_coef.band_width[filter_idx]; -+ if (eqz_ctr_params->p_coef.type[filter_idx] >= 0) -+ eqz_params->p_coef.type[filter_idx] = -+ eqz_ctr_params->p_coef.type[filter_idx]; -+ if (eqz_ctr_params->p_coef.gain_base[filter_idx] >= 0) -+ eqz_params->p_coef.gain_base[filter_idx] = -+ eqz_ctr_params->p_coef.gain_base[filter_idx]; -+ if (eqz_ctr_params->p_coef.gain[filter_idx] >= 0) -+ eqz_params->p_coef.gain[filter_idx] = -+ eqz_ctr_params->p_coef.gain[filter_idx]; -+ } -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; -+ filter_idx++) { -+ if (eqz_ctr_params->g_coef.gain_g[filter_idx] >= 0) -+ eqz_params->g_coef.gain_g[filter_idx] = -+ eqz_ctr_params->g_coef.gain_g[filter_idx]; -+ } -+ } else { -+ eqz_ctr_params->eqz_type = eqz_params->eqz_type; -+ -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; -+ filter_idx++) { -+ eqz_ctr_params->p_coef.fc[filter_idx] = -+ eqz_params->p_coef.fc[filter_idx]; -+ eqz_ctr_params->p_coef.band_width[filter_idx] = -+ eqz_params->p_coef.band_width[filter_idx]; -+ eqz_ctr_params->p_coef.type[filter_idx] = -+ eqz_params->p_coef.type[filter_idx]; -+ eqz_ctr_params->p_coef.gain_base[filter_idx] = -+ eqz_params->p_coef.gain_base[filter_idx]; -+ eqz_ctr_params->p_coef.gain[filter_idx] = -+ eqz_params->p_coef.gain[filter_idx]; -+ } -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; -+ filter_idx++) -+ eqz_ctr_params->g_coef.gain_g[filter_idx] = -+ eqz_params->g_coef.gain_g[filter_idx]; -+ } -+} -+ -+/******************************************************************* -+ * ALSA ADSP Platform driver interface -+ * ****************************************************************/ -+ -+/** **************************************************************************** -+ * \brief Register control interface and preallocate ALSA buffer -+ * -+ * \param[in] runtime Pointer to runtime PCM data -+ * \retval 0 Success -+ * \retval -EINVAL Cannot register control interface -+ ******************************************************************************/ -+static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime) -+{ -+ int i = 0, err = 0; -+ int id; -+ struct snd_card *card; -+ struct snd_adsp_card *adsp_card; -+ int alsa_buf_sz = 0; -+ -+ /* get sound card data */ -+ card = runtime->card->snd_card; -+ -+ /* get driver data */ -+ adsp_card = snd_soc_dai_get_drvdata(runtime->cpu_dai); -+ -+ /* get the ID of CPU DAI */ -+ id = runtime->cpu_dai->id; -+ -+ /* register control interfaces */ -+ if (id == RDR_DAI_IDX0 || id == RDR_DAI_IDX1 -+ || id == RDR_DAI_IDX2 || id == RDR_DAI_IDX3) { -+ struct snd_kcontrol *kctl[RDR_CONTROL_NUM]; -+ void *rdr_ctr[RDR_CONTROL_NUM] = { -+ &snd_adsp_playback_volume_control[id], /* PRQA S 1031 */ -+ &snd_adsp_capture_volume_control[id], -+ &snd_adsp_playback_sample_rate_out_control[id], -+ &snd_adsp_capture_sample_rate_in_control[id], -+ &snd_adsp_playback_equalizer_control[id], -+ &snd_adsp_capture_equalizer_control[id], -+ &snd_adsp_playback_equalizer_switch_control[id], -+ &snd_adsp_capture_equalizer_switch_control[id], -+ &snd_adsp_playback_out_channel_control[id] -+ }; -+ -+ /* add basic control instance */ -+ for (i = 0; i < RDR_CONTROL_NUM; i++) { -+ kctl[i] = snd_ctl_new1(rdr_ctr[i], adsp_card); -+ err = snd_ctl_add(card, kctl[i]); -+ if (err < 0) -+ return -EINVAL; -+ } -+ -+ /* assign ALSA buffer size */ -+ alsa_buf_sz = MAX_BUFFER_BYTES; -+ -+ /* enable MIX feature from the 2nd playback/record stream */ -+ if (adsp_card->ctr_if.mix_usage == MIX_UNUSED) -+ adsp_card->ctr_if.mix_usage = FIRST_RUN; -+ else if (adsp_card->ctr_if.mix_usage == FIRST_RUN) -+ adsp_card->ctr_if.mix_usage = SECOND_RUN; -+ -+ } else { -+ struct snd_kcontrol *kctl[TDM_CONTROL_NUM]; -+ void *tdm_ctr[TDM_CONTROL_NUM] = { -+ &snd_adsp_tdm_playback_volume_control, -+ &snd_adsp_tdm_playback_sample_rate_out_control, -+ &snd_adsp_tdm_capture_volume_control, -+ &snd_adsp_tdm_capture_sample_rate_in_control -+ }; -+ -+ /* add basic control instances */ -+ for (i = 0; i < TDM_CONTROL_NUM; i++) { -+ kctl[i] = snd_ctl_new1(tdm_ctr[i], adsp_card); -+ err = snd_ctl_add(card, kctl[i]); -+ if (err < 0) -+ return -EINVAL; -+ } -+ -+ /* assign ALSA buffer size */ -+ alsa_buf_sz = TDM_MAX_BUFFER_BYTES; -+ } -+ -+ return snd_pcm_lib_preallocate_pages_for_all(runtime->pcm, -+ SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data(GFP_KERNEL), -+ alsa_buf_sz, alsa_buf_sz); -+} -+ -+/* **************************************************************************** -+ * ALSA ADSP DAI register -+ * ***************************************************************************/ -+ -+/** callback function of platform driver */ -+static struct snd_soc_platform_driver snd_adsp_platform = { -+ .pcm_new = &snd_adsp_pcm_new, /* PRQA S 1053 *//* PRQA S 0674 */ -+ .ops = &snd_adsp_pcm_ops, -+}; -+ -+/** component information of driver */ -+static const struct snd_soc_component_driver snd_adsp_component = { -+ .name = "snd_adsp", /* PRQA S 1053 */ -+}; -+ -+/** DAI information of ADSP ALSA driver */ -+static struct snd_soc_dai_driver snd_adsp_dai[MAX_DAI_IDX] = { -+ { -+ /* PRQA S 1053 */ -+ .id = RDR_DAI_IDX0, -+ .name = "adsp-dai.0", -+ .playback.stream_name = "Playback0", -+ .capture.stream_name = "Capture0", -+ }, -+ { -+ .id = RDR_DAI_IDX1, -+ .name = "adsp-dai.1", -+ .playback.stream_name = "Playback1", -+ .capture.stream_name = "Capture1", -+ }, -+ { -+ .id = RDR_DAI_IDX2, -+ .name = "adsp-dai.2", -+ .playback.stream_name = "Playback2", -+ .capture.stream_name = "Capture2", -+ }, -+ { -+ .id = RDR_DAI_IDX3, -+ .name = "adsp-dai.3", -+ .playback.stream_name = "Playback3", -+ .capture.stream_name = "Capture3", -+ }, -+ { -+ .id = TDM_DAI_IDX, -+ .name = "adsp-tdm-dai", -+ .playback.stream_name = "TDM Playback", -+ .capture.stream_name = "TDM Capture", -+ } -+}; -+ -+/** *************************************************************************** -+ * \brief Register platform driver and ADSP ALSA sound card -+ * -+ * \param[in] pdev Pointer to platform driver data -+ * \retval 0 Success -+ * \retval -ENOMEM Cannot allocate driver's data -+ * \retval -EINVAL Cannot register platform driver or sound card -+ ****************************************************************************/ -+static int snd_adsp_probe(struct platform_device *pdev) -+{ -+ struct snd_adsp_card *adsp_card; -+ int i; -+ -+ /* allocate a card data structure */ -+ adsp_card = kmalloc(sizeof(*adsp_card), GFP_KERNEL); -+ if (!adsp_card) -+ return -ENOMEM; -+ -+ /* init parameters */ -+ memset(adsp_card, 0, sizeof(*adsp_card)); /* PRQA S 3200 */ -+ /* PRQA S 3200 1*/ -+ memset(&adsp_card->ctr_if, -1, sizeof(struct snd_adsp_control)); -+ -+ /* disable Equalizer for all streams */ -+ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { -+ adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][i] = 0; -+ adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][i] = 0; -+ } -+ -+ /* disable MIX function for all */ -+ adsp_card->ctr_if.mix_usage = MIX_UNUSED; -+ -+ /* save driver data */ -+ dev_set_drvdata(&pdev->dev, adsp_card); -+ -+ /* register platform device */ -+ if (snd_soc_register_platform(&pdev->dev, &snd_adsp_platform) < 0) { -+ //snd_printk("[ADSP] Cannot register platform driver\n"); -+ snd_soc_unregister_platform(&pdev->dev); -+ return -EINVAL; -+ } -+ -+ /* fill format information of sound DAI driver for Rdr/Cap function */ -+ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { -+ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].playback.channels_min = MIN_CHANNEL; -+ snd_adsp_dai[i].playback.channels_max = MAX_CHANNEL; -+ -+ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].capture.channels_min = MIN_CHANNEL; -+ snd_adsp_dai[i].capture.channels_max = MAX_CHANNEL; -+ } -+ -+ /* fill format information of sound DAI driver for TDM function */ -+ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].playback.channels_min = TDM_MIN_CHANNEL; -+ snd_adsp_dai[i].playback.channels_max = TDM_MAX_CHANNEL; -+ -+ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].capture.channels_min = TDM_MIN_CHANNEL; -+ snd_adsp_dai[i].capture.channels_max = TDM_MAX_CHANNEL; -+ -+ /* register CPU dai */ -+ if (snd_soc_register_component(&pdev->dev, &snd_adsp_component -+ , snd_adsp_dai -+ , ARRAY_SIZE(snd_adsp_dai)) < 0) { -+ //snd_printk("[ADSP] Cannot register component\n"); -+ snd_soc_unregister_platform(&pdev->dev); -+ return -EINVAL; -+ } -+ -+ dev_info(&pdev->dev, "probed\n"); -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Unregister platform driver and ADSP ALSA sound card -+ * -+ * \param[in] pdev Pointer platform driver data -+ * \retval 0 Success -+ * \retval -EINVAL Invalid driver's data -+ *****************************************************************************/ -+static int snd_adsp_remove(struct platform_device *pdev) -+{ -+ /* get ADSP sound card data */ -+ struct snd_adsp_card *adsp_card = -+ (struct snd_adsp_card *)dev_get_drvdata(&pdev->dev); -+ -+ if (!adsp_card) { -+ //snd_printk("Invalid snd_adsp_card data\n"); -+ return -ENODEV; -+ } -+ -+ /* release the ADSP sound card */ -+ kfree(adsp_card); -+ -+ /* unregister platform driver */ -+ snd_soc_unregister_component(&pdev->dev); -+ snd_soc_unregister_platform(&pdev->dev); -+ -+ /* success */ -+ return 0; -+} -+ -+/** ADSP ALSA driver information */ -+static const struct of_device_id snd_adsp_id[] = { -+ { .compatible = "renesas,rcar_adsp_sound_gen3", }, /* PRQA S 1053 */ -+}; -+MODULE_DEVICE_TABLE(of, snd_adsp_id); -+ -+/** platform driver of ADSP ALSA sound card */ -+static struct platform_driver snd_adsp_driver = { -+ .driver = { /* PRQA S 1053 */ -+ .name = "rcar_adsp_sound", -+ .of_match_table = snd_adsp_id, -+ }, -+ .probe = snd_adsp_probe, -+ .remove = snd_adsp_remove, -+}; -+module_platform_driver(snd_adsp_driver); /* PRQA S 0651 */ -+ -+MODULE_AUTHOR("Renesas AudioDSP"); -+MODULE_DESCRIPTION("Platform driver for ADSP"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:ADSP-PCM-AUDIO"); -diff --git a/sound/soc/adsp/xf-adsp-base.c b/sound/soc/adsp/xf-adsp-base.c -new file mode 100644 -index 0000000..d797bf5 ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-base.c -@@ -0,0 +1,2239 @@ -+/** *************************************************************************** -+ *\file xf-adsp-base.c -+ *\brief Source file for ADSP Base Control layer -+ *\addtogroup ADSP Driver -+ ****************************************************************************** -+ *\date Oct. 21, 2017 -+ *\author Renesas Electronics Corporation -+ ****************************************************************************** -+ *\par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#include -+#include -+#include -+ -+#include "xf-adsp-base.h" -+ -+#define XF_AUX_POOL_SIZE (16) /**< size of auxiliary pool*/ -+#define XF_AUX_POOL_MSG_LENGTH (256) /**< size of auxiliary buffer */ -+ -+#define XF_PROXY_ALIGN (64) /**< proxy alignment */ -+ -+/** \def XF_ALIGNED(size) -+ * Get properly aligned buffer length -+ */ -+#define XF_ALIGNED(size)\ -+((((size) + XF_PROXY_ALIGN) - 1) & ~(XF_PROXY_ALIGN - 1)) /* PRQA S 3453 */ -+ -+#ifndef offset_of -+/** \def offset_of(type, member) -+ * Return the offset of member in type structuer in byte -+ */ -+#define offset_of(type, member) \ -+ ((int)(long int)&(((const type *)(0))->member)) /* PRQA S 3453 */ -+#endif -+ -+/************************************************* -+ * Variable and and function declaration -+ * **********************************************/ -+ -+/** ADSP base control data */ -+static struct xf_adsp_base *base; -+ -+/* function declaration */ -+static int xf_adsp_base_register_handle(void *private_data, -+ struct xf_callback_func *cb -+ , int comp_id); -+static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id); -+static int xf_adsp_base_free_handle(int handle_id); -+static void xf_adsp_base_init_handle(void); -+static int xf_adsp_base_get_valid_handle(void); -+static int xf_send_and_receive(struct xf_message *msg); -+static int xf_response_thread(void *data); -+static void xf_buffer_put(struct xf_buffer *buffer); -+static u32 xf_buffer_length(struct xf_buffer *b); -+static struct xf_buffer *xf_buffer_get(struct xf_pool *pool); -+static void *xf_buffer_data(struct xf_buffer *b); -+static int xf_adsp_unregister(int comp_id); -+static int xf_adsp_register(char *name, int *comp_id); -+ -+/************************************************* -+ * Helper function to process pool data -+ * **********************************************/ -+ -+/** *********************************************************** -+ * \brief get buffer from given pool -+ * -+ * \param[in] pool Data pool address -+ * \retval b Pointer to buffer address in pool -+ **************************************************************/ -+static struct xf_buffer *xf_buffer_get(struct xf_pool *pool) -+{ -+ struct xf_buffer *b; -+ -+ b = pool->free; -+ if (b) { -+ pool->free = b->link.next; -+ b->link.pool = pool; -+ } -+ return b; -+} -+ -+/*********************************************************** -+ *\brief return buffer back to pool -+ * -+ *\param[in] buffer Pointer to the buffer data -+ ************************************************************/ -+static void xf_buffer_put(struct xf_buffer *buffer) -+{ -+ struct xf_pool *pool = buffer->link.pool; -+ -+ buffer->link.next = pool->free; -+ pool->free = buffer; -+} -+ -+/*********************************************************** -+ *\brief get the address of the given buffer data -+ * -+ *\param[in] b Pointer to the buffer data -+ *\retval address Address of buffer data -+ ************************************************************/ -+static void *xf_buffer_data(struct xf_buffer *b) -+{ -+ return b->address; -+} -+ -+/************************************************************ -+ *\brief get the length of the given buffer data -+ * -+ *\param[in] b Pointer to the buffer data -+ *\retval length Size of buffer data -+ ************************************************************/ -+static u32 xf_buffer_length(struct xf_buffer *b) /* PRQA S 3673 */ -+{ -+ return b->link.pool->length; -+} -+ -+/************************************************************ -+ *\brief set data to the given command message -+ * -+ *\param[out] m Pointer to the command message -+ *\param[in] id Message ID -+ *\param[in] opcode Message opcode -+ *\param[in] length Message length -+ *\param[in] buf Pointer to the buffer data -+ *\param[in] next Pointer to the next message -+ *\retval m Pointer to the command message -+ ************************************************************/ -+static inline struct xf_message *xf_create_msg( -+ struct xf_message *m, u32 id, u32 opcode, -+ u32 length, void *buf, struct xf_message *next) -+{ -+ if (m) { -+ m->id = id; -+ m->opcode = opcode; -+ m->length = length; -+ m->buffer = buf; -+ m->next = next; -+ } -+ -+ return m; -+} -+ -+/***************************************************************** -+ *\brief synchronous send and wait for response message from proxy -+ * -+ *\param[in] msg Pointer to the command message -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ ****************************************************************/ -+static int xf_send_and_receive(struct xf_message *msg) -+{ -+ int err; -+ int opcode = msg->opcode; -+ -+ /* reset the base flag */ -+ spin_lock(&base->lock); -+ base->base_flag = FALSE; -+ spin_unlock(&base->lock); -+ -+ err = base->cmd.send(base->client, (void *)msg); -+ if (err != 0) -+ return err; -+ -+ /* sleep and wait for the response wake up event */ -+ if (wait_event_interruptible(base->base_wait, -+ base->base_flag || base->err_flag)) { -+ return -EINVAL; -+ } -+ -+ if (base->err_flag != 0) { -+ spin_lock(&base->lock); -+ base->err_flag = FALSE; -+ spin_unlock(&base->lock); -+ return -EINVAL; -+ } -+ -+ /* save the response message */ -+ /* PRQA S 3200 */ -+ memcpy(msg, &base->base_msg, sizeof(struct xf_message)); -+ -+ /* check if the reponsed message is right */ -+ if (msg->opcode != opcode) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+/************************************************************* -+ *\brief send a message to proxy -+ * -+ *\param[in] msg Pointer to the command message -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+static inline int xf_send(struct xf_message *msg) -+{ -+ return base->cmd.send(base->client, (void *)msg); -+} -+ -+/** *********************************************************** -+ *\brief receive message from proxy -+ * -+ *\param[in] msg Pointer to store the response message -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+static inline int xf_receive(struct xf_message *msg) -+{ -+ /* do not wait here */ -+ return base->cmd.recv(base->client, (void *)msg); -+} -+ -+/** *********************************************************** -+ *\brief thread for receive response data -+ **************************************************************/ -+static int xf_response_thread(void *data) -+{ -+ struct xf_message msg; -+ struct xf_handle *handle; -+ int id; -+ -+ /* set polling to wait the response message */ -+ spin_lock(&base->lock); -+ base->wait_flag = FALSE; -+ spin_unlock(&base->lock); -+ -+ while (!kthread_should_stop()) { -+ if (base->cmd.poll(base->client, &base->wait_flag) != 0) -+ continue; -+ -+ if (xf_receive(&msg) != 0) -+ continue; -+ /* get the handle id */ -+ id = XF_AP_CLIENT(msg.id); -+ -+ /* check the destination of the response message */ -+ if (id == 0) { -+ /* message is from base control */ -+ /* PRQA S 3200 1*/ -+ memcpy(&base->base_msg -+ , &msg, sizeof(struct xf_message)); -+ spin_lock(&base->lock); -+ base->base_flag = TRUE; -+ spin_unlock(&base->lock); -+ wake_up(&base->base_wait); -+ continue; -+ } -+ -+ /* get handle data */ -+ handle = xf_adsp_base_get_handle(id); -+ -+ if (handle == 0) -+ continue; -+ -+ switch (msg.opcode) { -+ case XF_EMPTY_THIS_BUFFER: /* PRQA S 0594 */ -+ handle->cb->empty_buf_done(handle->private_data, -+ msg.opcode, -+ msg.length, -+ msg.buffer); -+ break; -+ case XF_FILL_THIS_BUFFER: /* PRQA S 0594 */ -+ handle->cb->fill_buf_done(handle->private_data, -+ msg.opcode, -+ msg.length, -+ msg.buffer); -+ break; -+ case XF_SET_PARAM: /* PRQA S 0594 4 */ -+ case XF_GET_PARAM: -+ case XF_ROUTE: -+ case XF_UNROUTE: -+ /* message is from base control */ -+ memcpy(&base->base_msg, &msg, -+ sizeof(struct xf_message)); /* PRQA S 3200 */ -+ spin_lock(&base->lock); -+ base->base_flag = TRUE; -+ spin_unlock(&base->lock); -+ wake_up(&base->base_wait); -+ break; -+ default: -+ /* error has occurred */ -+ handle->cb->event_handler(handle->private_data); -+ xf_adsp_base_free_handle(id); /* PRQA S 3200 */ -+ spin_lock(&base->lock); -+ base->err_flag = TRUE; -+ spin_unlock(&base->lock); -+ wake_up(&base->base_wait); -+ break; -+ } -+ } -+ -+ pr_info("ADSP base thread was exited\n"); -+ -+ do_exit(0); -+ return 0; -+} -+ -+/************************************************************* -+ * \brief register component to ADSP -+ * -+ * \param[in] name Name string of component -+ * \param[out] comp_id Store the registered component ID -+ * \retval 0 Success -+ * \retval -EINVAL Failed -+ **************************************************************/ -+static int xf_adsp_register(char *name, int *comp_id) /* PRQA S 3673 */ -+{ -+ struct xf_message msg; -+ struct xf_buffer *b = xf_buffer_get(base->aux_pool); -+ int err = 0; -+ -+ msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); -+ msg.opcode = XF_REGISTER; -+ msg.length = strlen(name) + 1; -+ msg.buffer = xf_buffer_data(b); -+ -+ /* copy identify name of ADSP component */ -+ if (msg.length <= xf_buffer_length(b)) -+ strncpy(msg.buffer, name, msg.length); /* PRQA S 3200 */ -+ else -+ strncpy(msg.buffer, name, xf_buffer_length(b));/* PRQA S 3200 */ -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the registered component ID */ -+ *comp_id = XF_MSG_SRC(msg.id); -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ * \brief unregister component from ADSP -+ * \param[in] comp_id Registered component ID -+ * \retval 0 Success -+ * \retval -EINVAL Failed -+ **************************************************************/ -+static int xf_adsp_unregister(int comp_id) -+{ -+ struct xf_message msg; -+ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), comp_id), -+ XF_UNREGISTER, 0, NULL, NULL); /* PRQA S 3200 */ -+ -+ return xf_send_and_receive(&msg); -+} -+ -+/*************************************************************** -+ * APIs for ADSP component helper -+ * ************************************************************/ -+/** *********************************************************** -+ * \brief allocate memory pool from shared memory -+ * \param[in] pool_size Number of buffer need to allocate -+ * \param[in] buf_length Size of each buffer in bytes -+ * \retval pool Pointer to allocated pool -+ * \retval -EINVAL Invalid base data -+ * \retval -ENOMEM Out of memory resource -+ **************************************************************/ -+struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length) -+{ -+ void *data; -+ u32 number; -+ struct xf_buffer *b; -+ struct xf_message msg; -+ struct xf_pool *pool; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return ERR_PTR(-EINVAL); /* PRQA S 0306 */ -+ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), -+ XF_ALLOC, -+ buf_length * pool_size, NULL, NULL); /* PRQA S 3200 */ -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ -+ -+ pool = kmalloc(offset_of(struct xf_pool, buffer) + -+ (pool_size * sizeof(struct xf_buffer)), GFP_KERNEL);/* PRQA S 0306 */ -+ if (!pool) -+ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ -+ -+ pool->length = buf_length; -+ pool->number = pool_size; -+ pool->p = msg.buffer; -+ -+ number = pool_size; -+ for (pool->free = b = &pool->buffer[0], data = pool->p; -+ number > 0; number--, b++) { /* PRQA S 2462,3418,0489 */ -+ /* set address of the buffer */ -+ b->address = data; -+ -+ /* fill buffer into free list */ -+ if (number == 1) -+ b->link.next = NULL; -+ else -+ b->link.next = b + 1; /* PRQA S 0489 */ -+ -+ /* advance data pointer in contigous buffer */ -+ data += buf_length; /* PRQA S 0550 */ -+ } -+ -+ return pool; -+} -+ -+/** *********************************************************** -+ *\brief return memory to shared memory -+ *\param[in] pool Data pool address -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or pool data -+ **************************************************************/ -+int xf_adsp_free_mem_pool(struct xf_pool *pool) -+{ -+ struct xf_message msg; -+ -+ /* check the sane ADSP base pool data*/ -+ if (!base || !pool) -+ return -EINVAL; -+ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), -+ XF_FREE, pool->number * pool->length, -+ pool->p, NULL); /* PRQA S 3200 */ -+ -+ xf_send_and_receive(&msg); /* PRQA S 3200 */ -+ -+ kfree(pool); -+ -+ return 0; -+} -+ -+/** *********************************************************** -+ *\brief get buffer from given pool -+ * -+ *\param[in] pool Data pool address -+ *\param[in] index Buffer index -+ *\retval b Pointer to buffer address in pool -+ *\retval -EINVAL Invalid pool or index -+ **************************************************************/ -+char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index) -+{ -+ struct xf_buffer *buf[XF_BUF_POOL_SIZE] = {0}; -+ char *data; -+ int i; -+ -+ /* check the sane pool data*/ -+ if (!pool) -+ return ERR_PTR(-EINVAL); /* PRQA S 306 */ -+ -+ /* check the index is valid */ -+ if (index > (pool->number - 1)) -+ return ERR_PTR(-EINVAL); /* PRQA S 306 */ -+ -+ /* get buffer from pool */ -+ for (i = 0; i <= index; i++) -+ buf[i] = xf_buffer_get(pool); -+ -+ /* get data from buffer */ -+ data = xf_buffer_data(buf[index]); -+ -+ /* return buffer to pool */ -+ for (i = index; i >= 0; i--) -+ xf_buffer_put(buf[i]); -+ -+ return data; -+} -+ -+/** *********************************************************** -+ *\brief send empty this buffer command to ADSP framework -+ * -+ *\param[in] handle_id ID of the registered handle -+ *\param[in] buffer Pointer to data buffer -+ *\param[in] length Size of buffer in bytes -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length) -+{ -+ struct xf_message msg; -+ struct xf_handle *handle; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ /* submit message to port 0 of component */ -+ /* PRQA S 3200 2 */ -+ xf_create_msg( -+ &msg, __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), -+ __XF_PORT_SPEC2(handle->comp_id, 0)), -+ XF_EMPTY_THIS_BUFFER, length, buffer, NULL); -+ -+ xf_send(&msg); /* PRQA S 3200 */ -+ -+ return 0; -+} -+ -+/** *********************************************************** -+ *\brief send fill this buffer command to ADSP framework -+ * -+ *\param[in] handle_id ID of the registered handle -+ *\param[in] buffer Pointer to data buffer -+ *\param[in] length Size of buffer in bytes -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length) -+{ -+ struct xf_message msg; -+ struct xf_handle *handle; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ /* submit message to port 1 of component */ -+ /* PRQA S 3200 2 */ -+ xf_create_msg( -+ &msg, __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), -+ __XF_PORT_SPEC2(handle->comp_id, 1)), -+ XF_FILL_THIS_BUFFER, length, buffer, NULL); -+ -+ xf_send(&msg); /* PRQA S 3200 */ -+ -+ return 0; -+} -+ -+/** *********************************************************** -+ *\brief route data between two registered ADSP plugins -+ * -+ *\param[in] src_handle_id Handle ID of source plugin -+ *\param[in] dst_handle_id Handle ID of sink plugin -+ *\param[in] buf_cnt Number of buffer in tunnel -+ *\param[in] buf_size Size of each buffer in tunnel -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_route(int src_handle_id, -+ int dst_handle_id, -+ int buf_cnt, int buf_size) -+{ -+ struct xf_route_port_msg *route_msg; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ struct xf_handle *dst_handle, *src_handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ /* get handle data */ -+ dst_handle = xf_adsp_base_get_handle(dst_handle_id); -+ src_handle = xf_adsp_base_get_handle(src_handle_id); -+ -+ if (!dst_handle || !src_handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ route_msg = xf_buffer_data(b); -+ -+ /* route information */ -+ route_msg->dst = __XF_PORT_SPEC2(dst_handle->comp_id, 0); -+ route_msg->alloc_align = 4; -+ route_msg->alloc_number = buf_cnt; -+ route_msg->alloc_size = buf_size; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_CLIENT(0, src_handle_id) -+ , __XF_PORT_SPEC2(src_handle->comp_id, 1)), -+ XF_ROUTE, sizeof(*route_msg), route_msg, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief set a single parameter -+ * -+ *\param[in] handle_id ID of registered handle -+ *\param[in] index Sub-command index of parameter -+ *\param[in] value the setting value -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_set_param(int handle_id, int index, int value) -+{ -+ struct xf_message msg; -+ struct xf_buffer *b; -+ struct xf_set_param_msg *msg_params; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ msg_params->item[0].id = index; -+ msg_params->item[0].value = value; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(1) -+ , msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get a single parameter -+ * -+ *\param[in] handle_id ID of registered handle -+ *\param[in] index Sub-command index of parameter -+ *\param[out] value Store the getting value -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_get_param(int handle_id, int index, int *value) -+{ -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base and value data */ -+ if (!base || !value) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ msg_params->c.id[0] = index; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)), -+ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(1), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ *value = msg_params->r.value[0]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/*************************************************** -+ * APIs for ADSP base control -+ * ************************************************/ -+ -+/** *********************************************************** -+ *\brief initialize ADSP base's instance -+ * -+ *\retval 0 Success -+ *\retval -EINVAL ADSP base's instance has been initialized -+ *\retval -ENOMEM Cannot allocate memory for ADSP base -+ *\retval -EBUSY Cannot register client to proxy -+ **************************************************************/ -+int xf_adsp_base_create(xf_adsp_base_cmd_t *cmd) -+{ -+ int err = 0; -+ -+ if (base != 0) -+ return -EINVAL; -+ -+ if (!cmd || !cmd->recv || !cmd->send || !cmd->poll -+ || !cmd->client_register || !cmd->client_unregister) -+ return -EINVAL; -+ -+ base = kmalloc(sizeof(*base), GFP_KERNEL); -+ if (!base) -+ return -ENOMEM; -+ -+ memset(base, 0, sizeof(struct xf_adsp_base)); /* PRQA S 3200 */ -+ -+ /* store the proxy command */ -+ memcpy(&base->cmd, cmd, sizeof(xf_adsp_base_cmd_t)); -+ -+ /* create client to connect from proxy driver */ -+ err = base->cmd.client_register(&base->client); -+ if (err != 0) -+ goto err3; /* PRQA S 2001 */ -+ -+ /* initialize waiting queue */ -+ init_waitqueue_head(&base->base_wait); -+ -+ /* initialize handle */ -+ xf_adsp_base_init_handle(); -+ -+ /* create thread to get the responsed message from proxy */ -+ base->rsp_thread = kthread_run(&xf_response_thread -+ , (void *)base, "adsp base"); -+ if (base->rsp_thread != 0) { -+ pr_info("ADSP base thread has been started.\n"); -+ } else { -+ pr_info("Failed in create base thread\n"); -+ err = -ENOMEM; -+ goto err2; /* PRQA S 2001 */ -+ } -+ -+ /* allocate auxiliary pool for component usage */ -+ base->aux_pool = -+ xf_adsp_allocate_mem_pool(XF_AUX_POOL_SIZE -+ , XF_ALIGNED(XF_AUX_POOL_MSG_LENGTH)); -+ if (IS_ERR(base->aux_pool)) { /* PRQA S 306 */ -+ err = -ENOMEM; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ pr_info("ADSP base was created\n"); -+ return 0; -+ -+err1: -+ /* cancel the waitting queue */ -+ spin_lock(&base->lock); -+ base->wait_flag = TRUE; -+ spin_unlock(&base->lock); -+ -+ /* stop thread inadvance */ -+ kthread_stop(base->rsp_thread); -+ -+err2: -+ base->cmd.client_unregister(base->client); -+ -+err3: -+ kfree(base); -+ base = NULL; -+ -+ return err; -+} -+EXPORT_SYMBOL(xf_adsp_base_create); /* PRQA S 0651 */ -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP base's instance -+ * -+ *\retval 0 Success -+ *\retval -EINVAL Invalid ADSP base's instance -+ **************************************************************/ -+int xf_adsp_base_destroy(void) -+{ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ /* free auxiliary pool to shared memory */ -+ xf_adsp_free_mem_pool(base->aux_pool); /* PRQA S 3200 */ -+ -+ /* cancel wait the response message, go to stop process */ -+ spin_lock(&base->lock); -+ base->wait_flag = TRUE; -+ spin_unlock(&base->lock); -+ -+ /* stop response thread */ -+ kthread_stop(base->rsp_thread); -+ -+ /* unregister client */ -+ base->cmd.client_unregister(base->client); -+ -+ kfree(base); -+ base = NULL; -+ -+ pr_info("ADSP base was destroyed\n"); -+ return 0; -+} -+EXPORT_SYMBOL(xf_adsp_base_destroy); /* PRQA S 0651 */ -+ -+/** *********************************************************** -+ * \brief initialize handle instance -+ **************************************************************/ -+static inline void xf_adsp_base_init_handle(void) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_HANDLE; i++) -+ base->handle[i] = NULL; -+} -+ -+/** *********************************************************** -+ *\brief get the next available handle ID for register -+ * -+ *\retval -1 Unavailable handle ID -+ *\retval 0 to 255 Available handle ID -+ **************************************************************/ -+static inline int xf_adsp_base_get_valid_handle(void) -+{ -+ int id = -1; -+ int i; -+ -+ for (i = 0; i < MAX_HANDLE; i++) { -+ /* get the id of the first available handler */ -+ if (base->handle[i] == NULL) { -+ id = i; -+ break; -+ } -+ } -+ -+ return id; -+} -+ -+/** *********************************************************** -+ *\brief register a handle instance for component usage -+ * -+ *\param[in] private_data Private data of this component -+ *\param[in] cb Callback function -+ *\param[in] comp_id ID of register component -+ *\retval id ID of registered handle -+ *\retval -EINVAL Cannot get the handle instance -+ *\retval -ENOMEM Cannot allocate handle memory -+ **************************************************************/ -+static int xf_adsp_base_register_handle(void *private_data -+ , struct xf_callback_func *cb -+ , int comp_id) -+{ -+ struct xf_handle *handle; -+ int id; -+ -+ /* get the next handle id */ -+ id = xf_adsp_base_get_valid_handle(); -+ -+ /* check available handle in base */ -+ if (id < 0) -+ return -EINVAL; -+ -+ /* allocate handle data */ -+ handle = kmalloc(sizeof(*handle), GFP_KERNEL); -+ if (!handle) -+ return -ENOMEM; -+ -+ /* save handle data */ -+ handle->private_data = private_data; -+ handle->cb = cb; -+ handle->comp_id = comp_id; -+ -+ /* save the hanle data */ -+ base->handle[id] = handle; -+ -+ /* return the id numbering in base handle */ -+ return (id + 1); -+} -+ -+/** *********************************************************** -+ *\brief get handle instance from handle ID -+ * -+ *\param[in] handle_id ID of registered handle -+ *\retval handle Pointer to handle instance -+ **************************************************************/ -+static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id) -+{ -+ return base->handle[handle_id - 1]; -+} -+ -+/** *********************************************************** -+ *\brief free the registered handle instance -+ * -+ *\param[in] handle_id ID of registered handle -+ *\retval 0 Success -+ *\retval -EINVAL Invalid handle ID -+ **************************************************************/ -+static int xf_adsp_base_free_handle(int handle_id) -+{ -+ if (handle_id < 1 || handle_id > MAX_HANDLE) -+ return -EINVAL; -+ -+ kfree(base->handle[handle_id - 1]); -+ base->handle[handle_id - 1] = NULL; -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for Renderer component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP Renderer parameters -+ * -+ *\param[in] renderer Pointer to Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_renderer_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !renderer) -+ return -EINVAL; -+ -+ params = &renderer->params; -+ -+ /* get Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_CHANNELS; -+ msg_params->item[i++].value = params->channel; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; -+ msg_params->item[i++].value = params->out_channel; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_MIX_CONTROL; -+ msg_params->item[i++].value = params->mix_ctrl; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_STATE; -+ msg_params->item[i++].value = params->state; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP Renderer parameters -+ * -+ *\param[in] renderer Pointer to Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 */ -+int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer) -+{ -+ struct xf_adsp_renderer_params *rdr_params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !renderer) -+ return -EINVAL; -+ -+ rdr_params = &renderer->params; -+ -+ /* get Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 13 1*/ -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_CHANNELS; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_MIX_CONTROL; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_STATE; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ rdr_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ -+ rdr_params->channel = msg_params->r.value[i++]; -+ rdr_params->pcm_width = msg_params->r.value[i++]; -+ rdr_params->frame_size = msg_params->r.value[i++]; -+ rdr_params->dev1 = msg_params->r.value[i++]; -+ rdr_params->dev2 = msg_params->r.value[i++]; -+ rdr_params->dma1 = msg_params->r.value[i++]; -+ rdr_params->dma2 = msg_params->r.value[i++]; -+ rdr_params->out_rate = msg_params->r.value[i++]; -+ rdr_params->vol_rate = msg_params->r.value[i++]; -+ rdr_params->out_channel = msg_params->r.value[i++]; -+ rdr_params->mix_ctrl = msg_params->r.value[i++]; -+ rdr_params->state = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create Renderer component -+ * -+ *\param[in,out] renderer Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Renderer instance -+ *****************************************************************************/ -+int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_renderer *rdr; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ rdr = kmalloc(sizeof(*rdr), GFP_KERNEL); -+ if (!rdr) -+ return -ENOMEM; -+ -+ memset(rdr, 0, sizeof(struct xf_adsp_renderer)); /* PRQA S 3200 */ -+ -+ /* register renderer component */ -+ err = xf_adsp_register("renderer", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register Renderer to ADSP base control */ -+ rdr->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (rdr->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from Renderer plugin */ -+ err = xf_adsp_renderer_get_params(rdr); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save renderer compoent data */ -+ *renderer = rdr; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(rdr); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP Renderer component -+ * -+ *\param[in] renderer Pointer to Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Renderer data -+ **************************************************************/ -+/* PRQA S 3673 */ -+int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !renderer) -+ return -EINVAL; -+ -+ handle_id = renderer->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(renderer); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for Capture component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP Capture parameters -+ * -+ *\param[in] capture Pointer to Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_capture_set_params(struct xf_adsp_capture *capture) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_capture_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !capture) -+ return -EINVAL; -+ -+ params = &capture->params; -+ -+ /* get Capture's handle data */ -+ handle = xf_adsp_base_get_handle(capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_CHANNELS; -+ msg_params->item[i++].value = params->channel; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_STATE; -+ msg_params->item[i++].value = params->state; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP Capture parameters -+ * -+ *\param[in] capture Pointer to Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 */ -+int xf_adsp_capture_get_params(struct xf_adsp_capture *capture) -+{ -+ struct xf_adsp_capture_params *cap_params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !capture) -+ return -EINVAL; -+ -+ cap_params = &capture->params; -+ -+ /* get Capture's handle data */ -+ handle = xf_adsp_base_get_handle(capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 11 1*/ -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_CHANNELS; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_STATE; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ cap_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 11 */ -+ cap_params->channel = msg_params->r.value[i++]; -+ cap_params->pcm_width = msg_params->r.value[i++]; -+ cap_params->frame_size = msg_params->r.value[i++]; -+ cap_params->dev1 = msg_params->r.value[i++]; -+ cap_params->dev2 = msg_params->r.value[i++]; -+ cap_params->dma1 = msg_params->r.value[i++]; -+ cap_params->dma2 = msg_params->r.value[i++]; -+ cap_params->out_rate = msg_params->r.value[i++]; -+ cap_params->vol_rate = msg_params->r.value[i++]; -+ cap_params->state = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create Capture component -+ * -+ *\param[in,out] capture Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Capture instance -+ *****************************************************************************/ -+int xf_adsp_capture_create(struct xf_adsp_capture **capture -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_capture *cap; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ cap = kmalloc(sizeof(*cap), GFP_KERNEL); -+ if (!cap) -+ return -ENOMEM; -+ -+ memset(cap, 0, sizeof(struct xf_adsp_capture)); /* PRQA S 3200 */ -+ -+ /* register capture component */ -+ err = xf_adsp_register("capture", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register capture to ADSP base control */ -+ cap->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (cap->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from capture plugin */ -+ err = xf_adsp_capture_get_params(cap); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save capture compoent data */ -+ *capture = cap; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(cap); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP Capture component -+ * -+ *\param[in] capture Pointer to Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Capture data -+ **************************************************************/ -+int xf_adsp_capture_destroy(struct xf_adsp_capture *capture) /* PRQA S 3673 */ -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !capture) -+ return -EINVAL; -+ -+ handle_id = capture->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(capture); -+ //pr_info("ADSP Capture[%d] was destroyed\n", handle_id); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for Equalizer component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP Equalizer parameters -+ * -+ *\param[in] equalizer Pointer to Equalizer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_equalizer_params *params; -+ struct xf_buffer *b; -+ int i, n; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !equalizer) -+ return -EINVAL; -+ -+ params = &equalizer->params; -+ -+ /* get Equalizer's handle data */ -+ handle = xf_adsp_base_get_handle(equalizer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_COEF_FS; -+ msg_params->item[i++].value = params->rate; -+ -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_CH; -+ msg_params->item[i++].value = params->channel; -+ -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; -+ msg_params->item[i++].value = params->eqz_type; -+ -+ if (params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { -+ struct xf_equalizer_parametric_coef *coef = ¶ms->p_coef; -+ -+ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; -+ msg_params->item[i++].value = coef->type[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; -+ msg_params->item[i++].value = coef->fc[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; -+ msg_params->item[i++].value = -+ coef->band_width[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; -+ msg_params->item[i++].value = coef->gain[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; -+ msg_params->item[i++].value = coef->gain_base[n]; -+ } -+ } else { -+ struct xf_equalizer_graphic_coef *coef = ¶ms->g_coef; -+ -+ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; -+ msg_params->item[i++].value = coef->gain_g[n]; -+ } -+ } -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP Equalizer parameters -+ * -+ *\param[in] equalizer Pointer to Equalizer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 1*/ -+int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer) -+{ -+ struct xf_adsp_equalizer_params *eqz_params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i, n; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !equalizer) -+ return -EINVAL; -+ -+ eqz_params = &equalizer->params; -+ -+ /* get Equalizer's handle data */ -+ handle = xf_adsp_base_get_handle(equalizer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_COEF_FS; /* PRQA S 3440 4 */ -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_CH; -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; -+ -+ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; /* PRQA S 3440 5 */ -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; -+ } -+ -+ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n;/* PRQA S 3440 */ -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ eqz_params->rate = msg_params->r.value[i++]; /* PRQA S 3440 4 */ -+ eqz_params->channel = msg_params->r.value[i++]; -+ eqz_params->pcm_width = msg_params->r.value[i++]; -+ eqz_params->eqz_type = msg_params->r.value[i++]; -+ -+ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { -+ eqz_params->p_coef.type[n] = -+ msg_params->r.value[i++]; /* PRQA S 3440 5 */ -+ eqz_params->p_coef.fc[n] = msg_params->r.value[i++]; -+ eqz_params->p_coef.band_width[n] = msg_params->r.value[i++]; -+ eqz_params->p_coef.gain[n] = msg_params->r.value[i++]; -+ eqz_params->p_coef.gain_base[n] = msg_params->r.value[i++]; -+ } -+ -+ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { -+ eqz_params->g_coef.gain_g[n] = -+ msg_params->r.value[i++]; /* PRQA S 3440 */ -+ } -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create Equalizer component -+ * -+ *\param[in,out] equalizer Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Equalier instance -+ *****************************************************************************/ -+int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_equalizer *eqz; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ eqz = kmalloc(sizeof(*eqz), GFP_KERNEL); -+ if (!eqz) -+ return -ENOMEM; -+ -+ memset(eqz, 0, sizeof(struct xf_adsp_equalizer)); /* PRQA S 3200 */ -+ -+ /* register equalizer component */ -+ err = xf_adsp_register("equalizer", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register equalizer to ADSP base control */ -+ eqz->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (eqz->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from equalizer plugin */ -+ err = xf_adsp_equalizer_get_params(eqz); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save equalizer compoent data */ -+ *equalizer = eqz; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(eqz); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP Equalizer component -+ * -+ *\param[in] equalizer Pointer to Equalizer component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Equalizer data -+ **************************************************************/ -+/* PRQA S 3673 */ -+int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base and Equalizer data */ -+ if (!base || !equalizer) -+ return -EINVAL; -+ -+ handle_id = equalizer->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(equalizer); -+ //pr_info("ADSP Equalizer[%d] was destroyed\n", handle_id); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for TDM Renderer component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP TDM Renderer parameters -+ * -+ *\param[in] tdm_renderer Pointer to TDM Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_tdm_renderer_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_renderer) -+ return -EINVAL; -+ -+ params = &tdm_renderer->params; -+ -+ /* get TDM Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->item[i++].value = params->ch_mode; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP TDM Renderer parameters -+ * -+ *\param[in] tdm_renderer Pointer to TDM Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 1*/ -+int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer) -+{ -+ struct xf_adsp_tdm_renderer_params *params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_renderer) -+ return -EINVAL; -+ -+ params = &tdm_renderer->params; -+ -+ /* get TDM Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 13 1*/ -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ -+ params->ch_mode = msg_params->r.value[i++]; -+ params->pcm_width = msg_params->r.value[i++]; -+ params->frame_size = msg_params->r.value[i++]; -+ params->dev1 = msg_params->r.value[i++]; -+ params->dev2 = msg_params->r.value[i++]; -+ params->dma1 = msg_params->r.value[i++]; -+ params->dma2 = msg_params->r.value[i++]; -+ params->out_rate = msg_params->r.value[i++]; -+ params->vol_rate = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create TDM Renderer component -+ * -+ *\param[in,out] tdm_renderer Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Renderer instance -+ *****************************************************************************/ -+int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer -+ , struct xf_callback_func *cb -+ , void *private_data) -+{ -+ struct xf_adsp_tdm_renderer *tdm_rdr; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ tdm_rdr = kmalloc(sizeof(*tdm_rdr), GFP_KERNEL); -+ if (!tdm_rdr) -+ return -ENOMEM; -+ /* PRQA S 3200 */ -+ memset(tdm_rdr, 0, sizeof(struct xf_adsp_tdm_renderer)); -+ -+ /* register TDM Renderer component */ -+ err = xf_adsp_register("tdm-renderer", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register TDM Renderer to ADSP base control */ -+ tdm_rdr->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (tdm_rdr->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from plugin */ -+ err = xf_adsp_tdm_renderer_get_params(tdm_rdr); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save compoent data */ -+ *tdm_renderer = tdm_rdr; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(tdm_rdr); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP TDM Renderer component -+ * -+ *\param[in] tdm_renderer Pointer to TDM Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Renderer data -+ **************************************************************/ -+/* PRQA S 3673 1*/ -+int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_renderer) -+ return -EINVAL; -+ -+ handle_id = tdm_renderer->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(tdm_renderer); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for TDM Capture component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP TDM Capture parameters -+ * -+ *\param[in] tdm_capture Pointer to TDM Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_tdm_capture_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_capture) -+ return -EINVAL; -+ -+ params = &tdm_capture->params; -+ -+ /* get TDM Capture's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->item[i++].value = params->ch_mode; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP TDM Capture parameters -+ * -+ *\param[in] tdm_capture Pointer to TDM Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 1*/ -+int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture) -+{ -+ struct xf_adsp_tdm_capture_params *params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_capture) -+ return -EINVAL; -+ -+ params = &tdm_capture->params; -+ -+ /* get TDM Capture's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 13 1*/ -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ -+ params->ch_mode = msg_params->r.value[i++]; -+ params->pcm_width = msg_params->r.value[i++]; -+ params->frame_size = msg_params->r.value[i++]; -+ params->dev1 = msg_params->r.value[i++]; -+ params->dev2 = msg_params->r.value[i++]; -+ params->dma1 = msg_params->r.value[i++]; -+ params->dma2 = msg_params->r.value[i++]; -+ params->out_rate = msg_params->r.value[i++]; -+ params->vol_rate = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create TDM Capture component -+ * -+ *\param[in,out] tdm_capture Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Renderer instance -+ *****************************************************************************/ -+int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_tdm_capture *tdm_cap; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ tdm_cap = kmalloc(sizeof(*tdm_cap), GFP_KERNEL); -+ if (!tdm_cap) -+ return -ENOMEM; -+ -+ /* PRQA S 3200 */ -+ memset(tdm_cap, 0, sizeof(struct xf_adsp_tdm_capture)); -+ -+ /* register TDM Capture component */ -+ err = xf_adsp_register("tdm-capture", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register TDM Capture to ADSP base control */ -+ tdm_cap->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (tdm_cap->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from plugin */ -+ err = xf_adsp_tdm_capture_get_params(tdm_cap); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save compoent data */ -+ *tdm_capture = tdm_cap; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(tdm_cap); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP TDM Capture component -+ * -+ *\param[in] tdm_capture Pointer to TDM Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Renderer data -+ **************************************************************/ -+/* PRQA S 3673 */ -+int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_capture) -+ return -EINVAL; -+ -+ handle_id = tdm_capture->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(tdm_capture); -+ -+ return 0; -+} -diff --git a/sound/soc/adsp/xf-adsp-base.h b/sound/soc/adsp/xf-adsp-base.h -new file mode 100644 -index 0000000..818ebdd ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-base.h -@@ -0,0 +1,276 @@ -+/** ************************************************************************* -+ *\file xf-adsp-base.h -+ *\brief Header file for ADSP Base Control layer -+ *\addtogroup ADSP Driver -+ **************************************************************************** -+ *\date Oct. 21, 2017 -+ *\author Renesas Electronics Corporation -+ **************************************************************************** -+ *\par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#ifndef __XF_ADSP_BASE_H -+#define __XF_ADSP_BASE_H -+ -+#include "xf-adsp-config.h" -+#include -+ -+#define XF_BUF_POOL_SIZE (4) /**< number of buffer in a data pool */ -+ -+/**< maximum number of DSP component can be registered */ -+#define MAX_HANDLE (256) -+ -+/* define boolean */ -+#define TRUE (1) -+#define FALSE (0) -+ -+/** \struct xf_callback_func -+ * \brief callback function for ADSP's response message -+ */ -+struct xf_callback_func { -+ /** callback for empty buffer done message */ -+ int (*empty_buf_done)(void *data, int opcode, int length, char *buffer); -+ -+ /** callback for fill buffer done message */ -+ int (*fill_buf_done)(void *data, int opcode, int length, char *buffer); -+ -+ /** callback for event handler */ -+ int (*event_handler)(void *data); -+}; -+ -+/** \struct xf_adsp_renderer_params -+ * \brief parameter structure for Renderer component -+ */ -+struct xf_adsp_renderer_params { -+ int channel; /**< channel number */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+ int out_channel; /**< output channels */ -+ int mix_ctrl; /**< mix control flag */ -+ int state; /**< operation state */ -+}; -+ -+/** \struct xf_adsp_renderer -+ * \brief Renderer component structure -+ */ -+struct xf_adsp_renderer { -+ struct xf_adsp_renderer_params params; /**< parameter structure*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle*/ -+}; -+ -+/** \struct xf_adsp_capture_params -+ *\brief parameter structure of Capture component -+ */ -+struct xf_adsp_capture_params { -+ int channel; /**< channel number */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+ int state; /**< operation state */ -+}; -+ -+/** \struct xf_adsp_capture -+ * \brief Capture component structure -+ */ -+struct xf_adsp_capture { -+ struct xf_adsp_capture_params params; /**< parameter structuer*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle*/ -+}; -+ -+/** \struct xf_equalizer_parametric_coef -+ *\brief Parametric Equalizer type's parameters -+ */ -+struct xf_equalizer_parametric_coef { -+ int type[XA_REL_EQZ_FILTER_NUM]; /**< Filter type*/ -+ int fc[XA_REL_EQZ_FILTER_NUM]; /**< Filter center frequency*/ -+ int gain[XA_REL_EQZ_FILTER_NUM]; /**< Filter gain*/ -+ int band_width[XA_REL_EQZ_FILTER_NUM]; /**< Filter band width */ -+ int gain_base[XA_REL_EQZ_FILTER_NUM]; /**< Filter base gain */ -+}; -+ -+/** \struct xf_equalizer_graphic_coef -+ * \brief Graphic Equalizer type's parameters -+ */ -+struct xf_equalizer_graphic_coef { -+ int gain_g[XA_REL_EQZ_GRAPHIC_BAND_NUM];/**< Graphic equalizer gain */ -+}; -+ -+/** \struct xf_adsp_equalizer_params -+ *\brief Equalizer parameters -+ */ -+struct xf_adsp_equalizer_params { -+ int channel; /**< channel number */ -+ int pcm_width; /**< PCM width */ -+ int rate; /**< sampling rate */ -+ int eqz_type; /**< Equalizer type */ -+ /**< Parametric parameters */ -+ struct xf_equalizer_parametric_coef p_coef; -+ struct xf_equalizer_graphic_coef g_coef; /**< Graphic parameters */ -+}; -+ -+/** \struct xf_adsp_equalizer -+ * \brief Equalizer component's structure -+ */ -+struct xf_adsp_equalizer { -+ struct xf_adsp_equalizer_params params;/**< Equalizer parameters */ -+ struct xf_pool *buf_pool; /**< buffer pool for transfer data */ -+ int handle_id; /**< ID of registered handle */ -+}; -+ -+/** \struct xf_adsp_tdm_renderer_params -+ * \brief parameter structure for TDM Renderer component -+ */ -+struct xf_adsp_tdm_renderer_params { -+ int ch_mode; /**< channel mode */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+}; -+ -+/** \struct xf_adsp_tdm_renderer -+ * \brief TDM Renderer component structure -+ */ -+struct xf_adsp_tdm_renderer { -+ struct xf_adsp_tdm_renderer_params params; /**< parameter structure*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle */ -+}; -+ -+/** \struct xf_adsp_tdm_capture_params -+ * \brief parameter structure for TDM Capture component -+ */ -+struct xf_adsp_tdm_capture_params { -+ int ch_mode; /**< channel mode */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+}; -+ -+/** \struct xf_adsp_tdm_capture -+ * \brief TDM Capture component structure -+ */ -+struct xf_adsp_tdm_capture { -+ struct xf_adsp_tdm_capture_params params; /**< parameter structure*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle*/ -+}; -+ -+/** \struct xf_handle -+ * \brief Handle struct for each ADSP component -+ */ -+struct xf_handle { -+ int comp_id;/**< ADSP component ID */ -+ struct xf_callback_func *cb;/**< callback functions */ -+ void *private_data; /**< private data for callback functions*/ -+}; -+ -+/** \struct xf_adsp_base -+ * \brief Base component structure -+ */ -+struct xf_adsp_base { -+ xf_adsp_base_cmd_t cmd; /**< proxy commands */ -+ void *client;/**< client data which registered to proxy */ -+ struct xf_pool *aux_pool; /**< auxiliary buffer pool data */ -+ struct xf_handle *handle[MAX_HANDLE]; /**< handler data */ -+ struct task_struct *rsp_thread;/**< thread for response message*/ -+ wait_queue_head_t base_wait; /**< ADSP base's waiting queue */ -+ struct xf_message base_msg; /**< ADSP base's response message */ -+ int base_flag; /**< flag to control its waiting queue */ -+ int err_flag; /**< flag to indicate a error from plugins */ -+ int wait_flag; /**< flag to control the polling waiting*/ -+ spinlock_t lock; /**< spinlock data */ -+}; -+ -+struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length); -+int xf_adsp_free_mem_pool(struct xf_pool *pool); -+char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index); -+ -+int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length); -+int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length); -+ -+int xf_adsp_route(int src_handle_id, int dst_handle_id -+ , int buf_cnt, int buf_size); -+ -+int xf_adsp_set_param(int handle_id, int index, int value); -+int xf_adsp_get_param(int handle_id, int index, int *value); -+ -+int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer -+ , struct xf_callback_func *cb, void *private_data); -+int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer); -+int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer); -+int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer); -+ -+int xf_adsp_capture_create(struct xf_adsp_capture **capture -+ , struct xf_callback_func *cb, void *private_data); -+int xf_adsp_capture_destroy(struct xf_adsp_capture *capture); -+int xf_adsp_capture_set_params(struct xf_adsp_capture *capture); -+int xf_adsp_capture_get_params(struct xf_adsp_capture *capture); -+ -+int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer -+ , struct xf_callback_func *cb, void *private_data); -+int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer); -+int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer); -+int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer); -+ -+int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer -+ , struct xf_callback_func *cb -+ , void *private_data); -+int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer); -+int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer); -+int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer); -+ -+int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture -+ , struct xf_callback_func *cb -+ , void *private_data); -+int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture); -+int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture); -+int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture); -+ -+#endif -diff --git a/sound/soc/adsp/xf-adsp-config.h b/sound/soc/adsp/xf-adsp-config.h -new file mode 100644 -index 0000000..7fc93ab ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-config.h -@@ -0,0 +1,604 @@ -+/** **************************************************************************** -+ *\file xf-adsp-config.h -+ *\brief Header file for ADSP configuration -+ *\addtogroup ADSP Driver -+ ******************************************************************************* -+ *\date Oct. 21, 2017 -+ *\author Renesas Electronics Corporation -+ ******************************************************************************* -+ *\par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#ifndef __XF_ADSP_CONFIG_H -+#define __XF_ADSP_CONFIG_H -+ -+/* Equalizer definition */ -+#define XA_REL_EQZ_FILTER_NUM (9) /**< number of filter */ -+#define XA_REL_EQZ_GRAPHIC_BAND_NUM (5) /**< number of graphic band */ -+ -+struct xf_buffer { -+ void *address; -+ union { /* PRQA S 750 3 */ -+ struct xf_buffer *next; -+ struct xf_pool *pool; -+ } link; -+}; -+ -+struct xf_pool { -+ /* length of individual buffer in a pool */ -+ u32 length; -+ -+ /* number of buffer in a pool */ -+ u32 number; -+ -+ /* pointer to pool memory */ -+ void *p; -+ -+ /* pointer to first free buffer in a pool */ -+ struct xf_buffer *free; -+ -+ /* individual buffer */ -+ struct xf_buffer buffer[0]; /* PRQA S 1037 */ -+}; -+ -+struct xf_message { -+ /* pointer to the next item in the list */ -+ struct xf_message *next; -+ -+ /* shmem session_id */ -+ u32 id; -+ -+ /* operation code */ -+ u32 opcode; -+ -+ /* length of attached message buffer */ -+ u32 length; -+ -+ /* message buffer */ -+ void *buffer; -+}; -+ -+/******************************************************************************* -+ * XF_GET_PARAM message -+ ******************************************************************************/ -+ -+/* ...message body (command/response) */ -+union xf_get_param_msg { /* PRQA S 750 18 */ -+ /* ...command structure */ -+ struct { -+ /* ...array of parameters requested */ -+ u32 id[0]; /* PRQA S 1037 */ -+ -+ } __attribute__((__packed__)) c; -+ -+ /* ...response structure */ -+ struct { -+ /* ...array of parameters values */ -+ u32 value[0];/* PRQA S 1037 */ -+ -+ } __attribute__((__packed__)) r; -+ -+}; -+ -+/* ...length of the XF_GET_PARAM command/response */ -+/* PRQA S 3453 2 */ -+#define XF_GET_PARAM_CMD_LEN(params) (sizeof(u32) * (params)) -+#define XF_GET_PARAM_RSP_LEN(params) (sizeof(u32) * (params)) -+ -+/******************************************************************************* -+ * XF_SET_PARAM message -+ ******************************************************************************/ -+ -+/* ...component initialization parameter */ -+struct xf_set_param_item { -+ /* ...index of parameter passed to SET_CONFIG_PARAM call */ -+ u32 id; -+ -+ /* ...value of parameter */ -+ u32 value; -+ -+} __attribute__ ((__packed__)); -+ -+/* ...message body (no response message? - tbd) */ -+struct xf_set_param_msg { -+ /* ...command message */ -+ struct xf_set_param_item item[0]; /* PRQA S 1037 */ -+ -+} __attribute__ ((__packed__)); -+ -+/* ...length of the command message */ -+/* PRQA S 3453 */ -+#define XF_SET_PARAM_CMD_LEN(params) \ -+ (sizeof(struct xf_set_param_item) * (params)) -+ -+/******************************************************************************* -+ * XF_ROUTE definition -+ ******************************************************************************/ -+ -+/* ...port routing command */ -+struct xf_route_port_msg { -+ /* ...source port specification */ -+ u32 src; -+ -+ /* ...destination port specification */ -+ u32 dst; -+ -+ /* ...number of buffers to allocate */ -+ u32 alloc_number; -+ -+ /* ...length of buffer to allocate */ -+ u32 alloc_size; -+ -+ /* ...alignment restriction for a buffer */ -+ u32 alloc_align; -+ -+} __attribute__((__packed__)); -+ -+/******************************************************************************* -+ * XF_UNROUTE definition -+ ******************************************************************************/ -+ -+/* ...port unrouting command */ -+struct xf_unroute_port_msg { -+ /* ...source port specification */ -+ u32 src; -+ -+ /* ...destination port specification */ -+ u32 dst; -+ -+} __attribute__((__packed__)); -+ -+/* ...Capture states */ -+enum xa_capture_state { -+ XA_CAP_STATE_RUN = 0, -+ XA_CAP_STATE_IDLE = 1, -+ XA_CAP_STATE_PAUSE = 2 -+}; -+ -+/* ...Renderer states */ -+enum xa_renderer_state { -+ XA_RDR_STATE_RUN = 0, -+ XA_RDR_STATE_IDLE = 1, -+ XA_RDR_STATE_PAUSE = 2 -+}; -+ -+/******************************************************************************* -+ * Message routing composition - move somewhere else - tbd -+ ******************************************************************************/ -+ -+/* ...adjust IPC client of message going from user-space */ -+#define XF_MSG_AP_FROM_USER(id, client) \ -+ (((id) & ~(0xF << 2)) | ((client) << 2)) -+ -+/* ...wipe out IPC client from message going to user-space */ -+#define XF_MSG_AP_TO_USER(id) \ -+ ((id) & ~(0xF << 18)) -+ -+/* ...port specification (12 bits) */ -+#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8)) -+#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8)) -+#define XF_PORT_CORE(spec) ((spec) & 0x3) -+#define XF_PORT_CLIENT(spec) (((spec) >> 2) & 0x3F) -+#define XF_PORT_ID(spec) (((spec) >> 8) & 0xF) -+ -+/* ...message id contains source and destination ports specification */ -+#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) -+#define XF_MSG_SRC(id) (((id) >> 0) & 0xFFFF) -+#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3) -+#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F) -+#define XF_MSG_SRC_PORT(id) (((id) >> 8) & 0xF) -+#define XF_MSG_SRC_PROXY(id) (((id) >> 15) & 0x1) -+#define XF_MSG_DST(id) (((id) >> 16) & 0xFFFF) -+#define XF_MSG_DST_CORE(id) (((id) >> 16) & 0x3) -+#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F) -+#define XF_MSG_DST_PORT(id) (((id) >> 24) & 0xF) -+#define XF_MSG_DST_PROXY(id) (((id) >> 31) & 0x1) -+ -+/* ...special treatment of AP-proxy destination field */ -+#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) -+#define XF_AP_CLIENT(id) (((id) >> 22) & 0x1FF) -+#define __XF_AP_PROXY(core) ((core) | 0x8000) -+#define __XF_DSP_PROXY(core) ((core) | 0x8000) -+#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 0x8000) -+ -+/******************************************************************************* -+ * Opcode composition -+ ******************************************************************************/ -+ -+/* ...opcode composition with command/response data tags */ -+#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) -+ -+/* ...accessors */ -+#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31)) -+#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30)) -+#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F)) -+ -+/******************************************************************************* -+ * Opcode types -+ ******************************************************************************/ -+ -+/* ...unregister client */ -+#define XF_UNREGISTER __XF_OPCODE(0, 0, 0) -+ -+/* ...register client at proxy */ -+#define XF_REGISTER __XF_OPCODE(1, 0, 1) -+ -+/* ...port routing command */ -+#define XF_ROUTE __XF_OPCODE(1, 0, 2) -+ -+/* ...port unrouting command */ -+#define XF_UNROUTE __XF_OPCODE(1, 0, 3) -+ -+/* ...shared buffer allocation */ -+#define XF_ALLOC __XF_OPCODE(0, 0, 4) -+ -+/* ...shared buffer freeing */ -+#define XF_FREE __XF_OPCODE(0, 0, 5) -+ -+/* ...set component parameters */ -+#define XF_SET_PARAM __XF_OPCODE(1, 0, 6) -+ -+/* ...get component parameters */ -+#define XF_GET_PARAM __XF_OPCODE(1, 1, 7) -+ -+/* ...input buffer reception */ -+#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8) -+ -+/* ...output buffer reception */ -+#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9) -+ -+/* ...flush specific port */ -+#define XF_FLUSH __XF_OPCODE(0, 0, 10) -+ -+/* ...start component operation */ -+#define XF_START __XF_OPCODE(0, 0, 11) -+ -+/* ...stop component operation */ -+#define XF_STOP __XF_OPCODE(0, 0, 12) -+ -+/* ...pause component operation */ -+#define XF_PAUSE __XF_OPCODE(0, 0, 13) -+ -+/* ...resume component operation */ -+#define XF_RESUME __XF_OPCODE(0, 0, 14) -+ -+/* ...total amount of supported decoder commands */ -+#define __XF_OP_NUM (15) -+ -+/************************************************* -+ * Renderer - specific configuration parameters -+ * **********************************************/ -+ -+enum xa_config_param_renderer { -+ XA_RDR_CONFIG_PARAM_STATE = 0, -+ XA_RDR_CONFIG_PARAM_PCM_WIDTH = 1, -+ XA_RDR_CONFIG_PARAM_CHANNELS = 2, -+ XA_RDR_CONFIG_PARAM_SAMPLE_RATE = 3, -+ XA_RDR_CONFIG_PARAM_FRAME_SIZE = 4, -+ XA_RDR_CONFIG_PARAM_OUTPUT1 = 5, -+ XA_RDR_CONFIG_PARAM_DMACHANNEL1 = 6, -+ XA_RDR_CONFIG_PARAM_OUTPUT2 = 7, -+ XA_RDR_CONFIG_PARAM_DMACHANNEL2 = 8, -+ XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 9, -+ XA_RDR_CONFIG_PARAM_VOLUME_RATE = 10, -+ XA_RDR_CONFIG_PARAM_OUT_CHANNELS = 11, -+ XA_RDR_CONFIG_PARAM_MIX_CONTROL = 12, -+ XA_RDR_CONFIG_PARAM_NUM = 13 -+}; -+ -+/************************************************* -+ * Capture - specific configuration parameters -+ * **********************************************/ -+ -+enum xa_config_param_capture { -+ XA_CAP_CONFIG_PARAM_CB = 0, -+ XA_CAP_CONFIG_PARAM_STATE = 1, -+ XA_CAP_CONFIG_PARAM_PCM_WIDTH = 2, -+ XA_CAP_CONFIG_PARAM_CHANNELS = 3, -+ XA_CAP_CONFIG_PARAM_SAMPLE_RATE = 4, -+ XA_CAP_CONFIG_PARAM_FRAME_SIZE = 5, -+ XA_CAP_CONFIG_PARAM_INPUT1 = 6, -+ XA_CAP_CONFIG_PARAM_DMACHANNEL1 = 7, -+ XA_CAP_CONFIG_PARAM_INPUT2 = 8, -+ XA_CAP_CONFIG_PARAM_DMACHANNEL2 = 9, -+ XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 10, -+ XA_CAP_CONFIG_PARAM_VOLUME_RATE = 11, -+ XA_CAP_CONFIG_PARAM_NUM = 12 -+}; -+ -+/************************************************* -+ * Equalizer - specific configuration parameters -+ * **********************************************/ -+ -+enum xa_rel_eqz_filter_type { -+ XA_REL_EQZ_TYPE_THROUGH = 0, -+ XA_REL_EQZ_TYPE_PEAK = 1, -+ XA_REL_EQZ_TYPE_BASS = 2, -+ XA_REL_EQZ_TYPE_TREBLE = 3 -+}; -+ -+enum xa_rel_eqz_type { -+ XA_REL_EQZ_TYPE_PARAMETRIC = 0, -+ XA_REL_EQZ_TYPE_GRAPHIC = 1 -+}; -+ -+/*****************************************************************************/ -+/* Additional subcommand indices */ -+/*****************************************************************************/ -+ -+enum xa_add_cmd_type_generic { -+ /* XA_API_CMD_SET_CONFIG_PARAM indices */ -+ XA_EQZ_CONFIG_PARAM_COEF_FS = 0x0000, -+ XA_EQZ_CONFIG_PARAM_PCM_WIDTH = 0x0001, -+ XA_EQZ_CONFIG_PARAM_CH = 0x0002, -+ XA_EQZ_CONFIG_PARAM_EQZ_TYPE = 0x0003, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC = 0x0010, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_FC = 0x0011, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_FC = 0x0012, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_FC = 0x0013, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_FC = 0x0014, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_FC = 0x0015, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_FC = 0x0016, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_FC = 0x0017, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_FC = 0x0018, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE = 0x0020, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_TYPE = 0x0021, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_TYPE = 0x0022, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_TYPE = 0x0023, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_TYPE = 0x0024, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_TYPE = 0x0025, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_TYPE = 0x0026, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_TYPE = 0x0027, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_TYPE = 0x0028, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW = 0x0030, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BW = 0x0031, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BW = 0x0032, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BW = 0x0033, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BW = 0x0034, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BW = 0x0035, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BW = 0x0036, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BW = 0x0037, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BW = 0x0038, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA = 0x0040, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_GA = 0x0041, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_GA = 0x0042, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_GA = 0x0043, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_GA = 0x0044, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_GA = 0x0045, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_GA = 0x0046, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_GA = 0x0047, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_GA = 0x0048, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA = 0x0050, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BA = 0x0051, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BA = 0x0052, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BA = 0x0053, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BA = 0x0054, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BA = 0x0055, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BA = 0x0056, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BA = 0x0057, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BA = 0x0058, -+ -+ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA = 0x0060, -+ XA_EQZ_CONFIG_PARAM_BAND_1_GCOEF_GA = 0x0061, -+ XA_EQZ_CONFIG_PARAM_BAND_2_GCOEF_GA = 0x0062, -+ XA_EQZ_CONFIG_PARAM_BAND_3_GCOEF_GA = 0x0063, -+ XA_EQZ_CONFIG_PARAM_BAND_4_GCOEF_GA = 0x0064 -+}; -+ -+/* ...tdm-renderer-specific configuration parameters */ -+enum xa_config_param_tdm_renderer { -+ XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH = 0, -+ XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE = 1, -+ XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE = 2, -+ XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE = 3, -+ XA_TDM_RDR_CONFIG_PARAM_OUTPUT1 = 4, -+ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1 = 5, -+ XA_TDM_RDR_CONFIG_PARAM_OUTPUT2 = 6, -+ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2 = 7, -+ XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, -+ XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE = 9 -+}; -+ -+enum xa_rel_tdm_renderer_channel_mode { -+ XA_TDM_RDR_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ -+ XA_TDM_RDR_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ -+ /**< 1 six-channels plus 1 two-channels TDM data */ -+ XA_TDM_RDR_CHANNEL_MODE_6_2 = 2, -+ XA_TDM_RDR_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ -+ XA_TDM_RDR_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ -+}; -+ -+/* ...TDM Capture-specific configuration parameters */ -+enum xa_config_param_tdm_capture { -+ XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH = 0, -+ XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE = 1, -+ XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE = 2, -+ XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE = 3, -+ XA_TDM_CAP_CONFIG_PARAM_INPUT1 = 4, -+ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1 = 5, -+ XA_TDM_CAP_CONFIG_PARAM_INPUT2 = 6, -+ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2 = 7, -+ XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, -+ XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE = 9 -+}; -+ -+enum xa_rel_tdm_capture_channel_mode { -+ XA_TDM_CAP_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ -+ XA_TDM_CAP_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ -+ /**< 1 six-channels plus 1 two-channels TDM data */ -+ XA_TDM_CAP_CHANNEL_MODE_6_2 = 2, -+ XA_TDM_CAP_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ -+ XA_TDM_CAP_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ -+}; -+ -+/*****************************************************************************/ -+/* HW supported */ -+/*****************************************************************************/ -+/* ...SSI modules supported by HW */ -+enum ssi_module { -+ SSI00 = 0, -+ SSI01 = 1, -+ SSI02 = 2, -+ SSI03 = 3, -+ SSI04 = 4, -+ SSI05 = 5, -+ SSI06 = 6, -+ SSI07 = 7, -+ SSI10 = 10, -+ SSI11 = 11, -+ SSI12 = 12, -+ SSI13 = 13, -+ SSI14 = 14, -+ SSI15 = 15, -+ SSI16 = 16, -+ SSI17 = 17, -+ SSI20 = 20, -+ SSI21 = 21, -+ SSI22 = 22, -+ SSI23 = 23, -+ SSI24 = 24, -+ SSI25 = 25, -+ SSI26 = 26, -+ SSI27 = 27, -+ SSI30 = 30, -+ SSI31 = 31, -+ SSI32 = 32, -+ SSI33 = 33, -+ SSI34 = 34, -+ SSI35 = 35, -+ SSI36 = 36, -+ SSI37 = 37, -+ SSI40 = 40, -+ SSI41 = 41, -+ SSI42 = 42, -+ SSI43 = 43, -+ SSI44 = 44, -+ SSI45 = 45, -+ SSI46 = 46, -+ SSI47 = 47, -+ SSI5 = 50, -+ SSI6 = 60, -+ SSI7 = 70, -+ SSI8 = 80, -+ SSI90 = 90, -+ SSI91 = 91, -+ SSI92 = 92, -+ SSI93 = 93, -+ SSI94 = 94, -+ SSI95 = 95, -+ SSI96 = 96, -+ SSI97 = 97 -+}; -+ -+/* ...SRC modules supported by HW */ -+enum src_module { -+ SRC0 = 110, /* SRC0 */ -+ SRC1 = 111, /* SRC1 */ -+ SRC2 = 112, /* SRC2 */ -+ SRC3 = 113, /* SRC3 */ -+ SRC4 = 114, /* SRC4 */ -+ SRC5 = 115, /* SRC5 */ -+ SRC6 = 116, /* SRC6 */ -+ SRC7 = 117, /* SRC7 */ -+ SRC8 = 118, /* SRC8 */ -+ SRC9 = 119, /* SRC9 */ -+ SRCMAX = 120 /* Maximum number of SRC modules */ -+}; -+ -+/* ...PDMA supported by HW */ -+enum { -+ PDMA_CH00 = 0, -+ PDMA_CH01 = 1, -+ PDMA_CH02 = 2, -+ PDMA_CH03 = 3, -+ PDMA_CH04 = 4, -+ PDMA_CH05 = 5, -+ PDMA_CH06 = 6, -+ PDMA_CH07 = 7, -+ PDMA_CH08 = 8, -+ PDMA_CH09 = 9, -+ PDMA_CH10 = 10, -+ PDMA_CH11 = 11, -+ PDMA_CH12 = 12, -+ PDMA_CH13 = 13, -+ PDMA_CH14 = 14, -+ PDMA_CH15 = 15, -+ PDMA_CH16 = 16, -+ PDMA_CH17 = 17, -+ PDMA_CH18 = 18, -+ PDMA_CH19 = 19, -+ PDMA_CH20 = 20, -+ PDMA_CH21 = 21, -+ PDMA_CH22 = 22, -+ PDMA_CH23 = 23, -+ PDMA_CH24 = 24, -+ PDMA_CH25 = 25, -+ PDMA_CH26 = 26, -+ PDMA_CH27 = 27, -+ PDMA_CH28 = 28, -+ PDMA_CHMAX = 29 -+}; -+ -+/* ...DMAC supported by HW */ -+enum { -+ ADMAC_CH00 = PDMA_CHMAX + 0, -+ ADMAC_CH01 = PDMA_CHMAX + 1, -+ ADMAC_CH02 = PDMA_CHMAX + 2, -+ ADMAC_CH03 = PDMA_CHMAX + 3, -+ ADMAC_CH04 = PDMA_CHMAX + 4, -+ ADMAC_CH05 = PDMA_CHMAX + 5, -+ ADMAC_CH06 = PDMA_CHMAX + 6, -+ ADMAC_CH07 = PDMA_CHMAX + 7, -+ ADMAC_CH08 = PDMA_CHMAX + 8, -+ ADMAC_CH09 = PDMA_CHMAX + 9, -+ ADMAC_CH10 = PDMA_CHMAX + 10, -+ ADMAC_CH11 = PDMA_CHMAX + 11, -+ ADMAC_CH12 = PDMA_CHMAX + 12, -+ ADMAC_CH13 = PDMA_CHMAX + 13, -+ ADMAC_CH14 = PDMA_CHMAX + 14, -+ ADMAC_CH15 = PDMA_CHMAX + 15, -+ ADMAC_CH16 = PDMA_CHMAX + 16, -+ ADMAC_CH17 = PDMA_CHMAX + 17, -+ ADMAC_CH18 = PDMA_CHMAX + 18, -+ ADMAC_CH19 = PDMA_CHMAX + 19, -+ ADMAC_CH20 = PDMA_CHMAX + 20, -+ ADMAC_CH21 = PDMA_CHMAX + 21, -+ ADMAC_CH22 = PDMA_CHMAX + 22, -+ ADMAC_CH23 = PDMA_CHMAX + 23, -+ ADMAC_CH24 = PDMA_CHMAX + 24, -+ ADMAC_CH25 = PDMA_CHMAX + 25, -+ ADMAC_CH26 = PDMA_CHMAX + 26, -+ ADMAC_CH27 = PDMA_CHMAX + 27, -+ ADMAC_CH28 = PDMA_CHMAX + 28, -+ ADMAC_CH29 = PDMA_CHMAX + 29, -+ ADMAC_CH30 = PDMA_CHMAX + 30, -+ ADMAC_CH31 = PDMA_CHMAX + 31, -+ ADMAC_CHMAX = PDMA_CHMAX + 32 -+}; -+ -+#endif --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch deleted file mode 100644 index d068e6d..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch +++ /dev/null @@ -1,32 +0,0 @@ -From bcf876462ac57204cf9054ba6cc5d0703b9beb5e Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:48 +0900 -Subject: [PATCH 3/6] arm64: dts: r8a7795-salvator-x: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts -index 6156bcc521b2..1f1920270aa4 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts -@@ -117,12 +117,6 @@ - status = "okay"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1 /* HDMI0 */ -- &rsnd_port2>; /* HDMI1 */ --}; -- - &hdmi0 { - status = "okay"; - --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch new file mode 100644 index 0000000..6d95d65 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch @@ -0,0 +1,185 @@ +From 825517f3f8ebe551d297db16e4582c0eae646f05 Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Wed, 31 Oct 2018 16:12:36 +0700 +Subject: [PATCH 4/6] ADSP: integrate ADSP sound for H3, M3, M3N board + +Signed-off-by: tienphitran +[takeshi.kihara.df: fix W=1 dtc warning] +Signed-off-by: Takeshi Kihara +--- + arch/arm64/boot/dts/renesas/r8a7795.dtsi | 5 ++ + arch/arm64/boot/dts/renesas/r8a7796.dtsi | 5 ++ + arch/arm64/boot/dts/renesas/r8a77965.dtsi | 5 ++ + .../boot/dts/renesas/salvator-common.dtsi | 84 +++++++++++++++++-- + 4 files changed, 94 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi +index 1896e5250dff..8dfda0fda91c 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi +@@ -793,6 +793,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi +index c00d1da64198..726c0d07fe59 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi +@@ -798,6 +798,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi +index 454a67b132f4..799b005ade92 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi +@@ -227,6 +227,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +index 922b9cc4797c..2c1d49c4bcaa 100644 +--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +@@ -153,11 +153,27 @@ + }; + + sound_card: sound { +- compatible = "audio-graph-card"; ++ compatible = "audio-graph-scu-card"; + + label = "rcar-sound"; + +- dais = <&rsnd_port0>; ++ prefix = "ak4613"; ++ routing = "ak4613 Playback", "Playback0", ++ "ak4613 Playback", "Playback1", ++ "ak4613 Playback", "Playback2", ++ "ak4613 Playback", "Playback3", ++ "Capture0", "ak4613 Capture", ++ "Capture1", "ak4613 Capture", ++ "Capture2", "ak4613 Capture", ++ "Capture3", "ak4613 Capture", ++ "ak4613 Playback", "DAI0 Playback", ++ "DAI0 Capture", "ak4613 Capture"; ++ ++ dais = <&adsp_port0 ++ &adsp_port1 ++ &adsp_port2 ++ &adsp_port3 ++ &rsnd_port0>; + }; + + vbus0_usb2: regulator-vbus0-usb2 { +@@ -419,8 +435,27 @@ + asahi-kasei,out5-single-end; + asahi-kasei,out6-single-end; + +- port { +- ak4613_endpoint: endpoint { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ak4613_endpoint0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&adsp_endpoint0>; ++ }; ++ ak4613_endpoint1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&adsp_endpoint1>; ++ }; ++ ak4613_endpoint2: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&adsp_endpoint2>; ++ }; ++ ak4613_endpoint3: endpoint@3 { ++ reg = <3>; ++ remote-endpoint = <&adsp_endpoint3>; ++ }; ++ ak4613_endpoint4: endpoint@4 { ++ reg = <4>; + remote-endpoint = <&rsnd_endpoint0>; + }; + }; +@@ -731,6 +766,45 @@ + status = "okay"; + }; + ++&rcar_adsp_sound { ++ status = "okay"; ++ /* Multiple DAI */ ++ #sound-dai-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adsp_port0: port@0 { ++ reg = <0>; ++ adsp_endpoint0: endpoint { ++ remote-endpoint = <&ak4613_endpoint0>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port1: port@1 { ++ reg = <1>; ++ adsp_endpoint1: endpoint { ++ remote-endpoint = <&ak4613_endpoint1>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port2: port@2 { ++ reg = <2>; ++ adsp_endpoint2: endpoint { ++ remote-endpoint = <&ak4613_endpoint2>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port3: port@3 { ++ reg = <3>; ++ adsp_endpoint3: endpoint { ++ remote-endpoint = <&ak4613_endpoint3>; ++ dai-format = "left_j"; ++ }; ++ }; ++ }; ++}; ++ + &rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; +@@ -769,7 +843,7 @@ + rsnd_port0: port@0 { + reg = <0>; + rsnd_endpoint0: endpoint { +- remote-endpoint = <&ak4613_endpoint>; ++ remote-endpoint = <&ak4613_endpoint4>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-Update-device-tree-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-Update-device-tree-for-ADSP-sound-driver.patch deleted file mode 100644 index 2586dac..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-Update-device-tree-for-ADSP-sound-driver.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 81528aacc64df60f2471873deca3f1092d47b6ae Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 17:56:29 +0700 -Subject: [PATCH 4/4] Update device tree for ADSP sound driver - -Signed-off-by: tienphitran - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi -index 1c8e713..1331a09 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi -@@ -2161,6 +2161,11 @@ - status = "disabled"; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi -index f25b476..ed332e7 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi -@@ -2067,6 +2067,11 @@ - status = "disabled"; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi -index d86bf9e..05861b4 100644 ---- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi -@@ -1478,6 +1478,11 @@ - }; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts -index 10a3403..b96ae07 100644 ---- a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts -+++ b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts -@@ -356,11 +356,26 @@ - }; - - sound_card: sound { -- compatible = "audio-graph-card"; -+ compatible = "audio-graph-scu-card"; - - label = "rcar-sound"; -- -- dais = <&rsnd_port0>; -+ prefix = "ak4613"; -+ routing = "ak4613 Playback", "DAI0 Playback", -+ "DAI0 Capture", "ak4613 Capture", -+ "ak4613 Playback", "Playback0", -+ "ak4613 Playback", "Playback1", -+ "ak4613 Playback", "Playback2", -+ "ak4613 Playback", "Playback3", -+ "Capture0", "ak4613 Capture", -+ "Capture1", "ak4613 Capture", -+ "Capture2", "ak4613 Capture", -+ "Capture3", "ak4613 Capture"; -+ -+ dais = <&adsp_port0 -+ &adsp_port1 -+ &adsp_port2 -+ &adsp_port3 -+ &rsnd_port0>; - }; - }; - -@@ -567,7 +582,19 @@ - asahi-kasei,out6-single-end; - - port { -- ak4613_endpoint: endpoint { -+ ak4613_endpoint0: endpoint@0 { -+ remote-endpoint = <&adsp_endpoint0>; -+ }; -+ ak4613_endpoint1: endpoint@1 { -+ remote-endpoint = <&adsp_endpoint1>; -+ }; -+ ak4613_endpoint2: endpoint@2 { -+ remote-endpoint = <&adsp_endpoint2>; -+ }; -+ ak4613_endpoint3: endpoint@3 { -+ remote-endpoint = <&adsp_endpoint3>; -+ }; -+ ak4613_endpoint4: endpoint@4 { - remote-endpoint = <&rsnd_endpoint0>; - }; - }; -@@ -766,6 +793,39 @@ - shared-pin; - }; - -+&rcar_adsp_sound { -+ status = "okay"; -+ /* Multiple DAI */ -+ #sound-dai-cells = <1>; -+ -+ ports { -+ adsp_port0: port@0 { -+ adsp_endpoint0: endpoint@0 { -+ remote-endpoint = <&ak4613_endpoint0>; -+ dai-format = "left_j"; -+ }; -+ }; -+ adsp_port1: port@1 { -+ adsp_endpoint1: endpoint@1 { -+ remote-endpoint = <&ak4613_endpoint1>; -+ dai-format = "left_j"; -+ }; -+ }; -+ adsp_port2: port@2 { -+ adsp_endpoint2: endpoint@2 { -+ remote-endpoint = <&ak4613_endpoint2>; -+ dai-format = "left_j"; -+ }; -+ }; -+ adsp_port3: port@3 { -+ adsp_endpoint3: endpoint@3 { -+ remote-endpoint = <&ak4613_endpoint3>; -+ dai-format = "left_j"; -+ }; -+ }; -+ }; -+}; -+ - &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; - pinctrl-names = "default"; -@@ -801,7 +861,7 @@ - ports { - rsnd_port0: port@0 { - rsnd_endpoint0: endpoint { -- remote-endpoint = <&ak4613_endpoint>; -+ remote-endpoint = <&ak4613_endpoint4>; - - dai-format = "left_j"; - bitclock-master = <&rsnd_endpoint0>; -diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi -index 242de2c..870bd4e 100644 ---- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi -@@ -1276,6 +1276,11 @@ - }; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -index 6cda028..89fbcf6 100644 ---- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi -+++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -@@ -125,12 +125,43 @@ - regulator-boot-on; - regulator-always-on; - }; -+ - rsnd_ak4613: sound { -- compatible = "simple-audio-card"; -+ compatible = "simple-scu-audio-card"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&sndcpu>; - simple-audio-card,frame-master = <&sndcpu>; -- sndcpu: simple-audio-card,cpu { -+ -+ simple-audio-card,name = "audio-card"; -+ simple-audio-card,prefix = "ak4613"; -+ simple-audio-card,routing = "ak4613 Playback", "Playback0", -+ "ak4613 Playback", "Playback1", -+ "ak4613 Playback", "Playback2", -+ "ak4613 Playback", "Playback3", -+ "Capture0", "ak4613 Capture", -+ "Capture1", "ak4613 Capture", -+ "Capture2", "ak4613 Capture", -+ "Capture3", "ak4613 Capture", -+ "ak4613 Playback", "DAI0 Playback", -+ "DAI0 Capture", "ak4613 Capture"; -+ -+ sndcpu: simple-audio-card,cpu@0 { -+ sound-dai = <&rcar_adsp_sound 0>; -+ }; -+ -+ simple-audio-card,cpu@1 { -+ sound-dai = <&rcar_adsp_sound 1>; -+ }; -+ -+ simple-audio-card,cpu@2 { -+ sound-dai = <&rcar_adsp_sound 2>; -+ }; -+ -+ simple-audio-card,cpu@3 { -+ sound-dai = <&rcar_adsp_sound 3>; -+ }; -+ -+ simple-audio-card,cpu@4 { - sound-dai = <&rcar_sound>; - }; - -@@ -139,7 +170,6 @@ - }; - }; - -- - vbus0_usb2: regulator-vbus0-usb2 { - compatible = "regulator-fixed"; - -@@ -763,6 +793,12 @@ - status = "okay"; - }; - -+&rcar_adsp_sound { -+ status = "okay"; -+ /* Multiple DAI */ -+ #sound-dai-cells = <1>; -+}; -+ - &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; - pinctrl-names = "default"; --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch deleted file mode 100644 index b740cfe..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 47fe276f805a83ef155bd9c16aea9fb16a3a931d Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:54 +0900 -Subject: [PATCH 4/6] arm64: dts: r8a7795-salvator-xs: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts -index b37b1de9d51a..286a8ffbdce5 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts -@@ -127,12 +127,6 @@ - status = "okay"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1 /* HDMI0 */ -- &rsnd_port2>; /* HDMI1 */ --}; -- - &hdmi0 { - status = "okay"; - --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch new file mode 100644 index 0000000..34b32d8 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch @@ -0,0 +1,272 @@ +From 455f26d0de1cf6eaeb0aa5b58725e3e34d8d34bd Mon Sep 17 00:00:00 2001 +From: Nguyen Dang +Date: Tue, 6 Nov 2018 11:36:15 +0700 +Subject: [PATCH 5/6] ADSP: integrate ADSP sound for E3 board + +Signed-off-by: Nguyen Dang +[takeshi.kihara.df: fix W=1 dtc warning] +[takeshi.kihara.df: support for dt file separation by E3 ES1.0 SoC] +Signed-off-by: Takeshi Kihara +--- + .../arm64/boot/dts/renesas/r8a77990-ebisu.dts | 84 +++++++++++++++++-- + .../boot/dts/renesas/r8a77990-es10-ebisu.dts | 84 +++++++++++++++++-- + arch/arm64/boot/dts/renesas/r8a77990.dtsi | 5 ++ + 3 files changed, 163 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts +index 26081a6e1866..20fdb4085d87 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts +@@ -221,11 +221,27 @@ + }; + + sound_card: sound { +- compatible = "audio-graph-card"; ++ compatible = "audio-graph-scu-card"; + + label = "rcar-sound"; + +- dais = <&rsnd_port0>; ++ prefix = "ak4613"; ++ routing = "ak4613 Playback", "DAI0 Playback", ++ "DAI0 Capture", "ak4613 Capture", ++ "ak4613 Playback", "Playback0", ++ "ak4613 Playback", "Playback1", ++ "ak4613 Playback", "Playback2", ++ "ak4613 Playback", "Playback3", ++ "Capture0", "ak4613 Capture", ++ "Capture1", "ak4613 Capture", ++ "Capture2", "ak4613 Capture", ++ "Capture3", "ak4613 Capture"; ++ ++ dais = <&adsp_port0 ++ &adsp_port1 ++ &adsp_port2 ++ &adsp_port3 ++ &rsnd_port0>; + }; + + vbus0_usb2: regulator-vbus0-usb2 { +@@ -501,8 +517,27 @@ + asahi-kasei,out5-single-end; + asahi-kasei,out6-single-end; + +- port { +- ak4613_endpoint: endpoint { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ak4613_endpoint0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&adsp_endpoint0>; ++ }; ++ ak4613_endpoint1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&adsp_endpoint1>; ++ }; ++ ak4613_endpoint2: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&adsp_endpoint2>; ++ }; ++ ak4613_endpoint3: endpoint@3 { ++ reg = <3>; ++ remote-endpoint = <&adsp_endpoint3>; ++ }; ++ ak4613_endpoint4: endpoint@4 { ++ reg = <4>; + remote-endpoint = <&rsnd_endpoint0>; + }; + }; +@@ -702,6 +737,45 @@ + status = "okay"; + }; + ++&rcar_adsp_sound { ++ status = "okay"; ++ /* Multiple DAI */ ++ #sound-dai-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adsp_port0: port@0 { ++ reg = <0>; ++ adsp_endpoint0: endpoint { ++ remote-endpoint = <&ak4613_endpoint0>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port1: port@1 { ++ reg = <1>; ++ adsp_endpoint1: endpoint { ++ remote-endpoint = <&ak4613_endpoint1>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port2: port@2 { ++ reg = <2>; ++ adsp_endpoint2: endpoint { ++ remote-endpoint = <&ak4613_endpoint2>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port3: port@3 { ++ reg = <3>; ++ adsp_endpoint3: endpoint { ++ remote-endpoint = <&ak4613_endpoint3>; ++ dai-format = "left_j"; ++ }; ++ }; ++ }; ++}; ++ + &rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; +@@ -737,7 +811,7 @@ + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { +- remote-endpoint = <&ak4613_endpoint>; ++ remote-endpoint = <&ak4613_endpoint4>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; +diff --git a/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts +index 087d5533f3db..61e18309c4a4 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts +@@ -221,11 +221,27 @@ + }; + + sound_card: sound { +- compatible = "audio-graph-card"; ++ compatible = "audio-graph-scu-card"; + + label = "rcar-sound"; + +- dais = <&rsnd_port0>; ++ prefix = "ak4613"; ++ routing = "ak4613 Playback", "DAI0 Playback", ++ "DAI0 Capture", "ak4613 Capture", ++ "ak4613 Playback", "Playback0", ++ "ak4613 Playback", "Playback1", ++ "ak4613 Playback", "Playback2", ++ "ak4613 Playback", "Playback3", ++ "Capture0", "ak4613 Capture", ++ "Capture1", "ak4613 Capture", ++ "Capture2", "ak4613 Capture", ++ "Capture3", "ak4613 Capture"; ++ ++ dais = <&adsp_port0 ++ &adsp_port1 ++ &adsp_port2 ++ &adsp_port3 ++ &rsnd_port0>; + }; + + vbus0_usb2: regulator-vbus0-usb2 { +@@ -501,8 +517,27 @@ + asahi-kasei,out5-single-end; + asahi-kasei,out6-single-end; + +- port { +- ak4613_endpoint: endpoint { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ak4613_endpoint0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&adsp_endpoint0>; ++ }; ++ ak4613_endpoint1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&adsp_endpoint1>; ++ }; ++ ak4613_endpoint2: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&adsp_endpoint2>; ++ }; ++ ak4613_endpoint3: endpoint@3 { ++ reg = <3>; ++ remote-endpoint = <&adsp_endpoint3>; ++ }; ++ ak4613_endpoint4: endpoint@4 { ++ reg = <4>; + remote-endpoint = <&rsnd_endpoint0>; + }; + }; +@@ -702,6 +737,45 @@ + status = "okay"; + }; + ++&rcar_adsp_sound { ++ status = "okay"; ++ /* Multiple DAI */ ++ #sound-dai-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adsp_port0: port@0 { ++ reg = <0>; ++ adsp_endpoint0: endpoint { ++ remote-endpoint = <&ak4613_endpoint0>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port1: port@1 { ++ reg = <1>; ++ adsp_endpoint1: endpoint { ++ remote-endpoint = <&ak4613_endpoint1>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port2: port@2 { ++ reg = <2>; ++ adsp_endpoint2: endpoint { ++ remote-endpoint = <&ak4613_endpoint2>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port3: port@3 { ++ reg = <3>; ++ adsp_endpoint3: endpoint { ++ remote-endpoint = <&ak4613_endpoint3>; ++ dai-format = "left_j"; ++ }; ++ }; ++ }; ++}; ++ + &rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; +@@ -737,7 +811,7 @@ + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { +- remote-endpoint = <&ak4613_endpoint>; ++ remote-endpoint = <&ak4613_endpoint4>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; +diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi +index bd4d71e2b93e..845399adcbdb 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi +@@ -181,6 +181,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch deleted file mode 100644 index 825e48f..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 7f000c3d136f9c2fb2087a1a1715a29e51140fc9 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:49:00 +0900 -Subject: [PATCH 5/6] arm64: dts: r8a7795-es1-salvator-x: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts -index 212e1f6ac5af..8e56c7b9d4bf 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts -@@ -117,11 +117,6 @@ - status = "okay"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1 /* HDMI0 */ -- &rsnd_port2>; /* HDMI1 */ --}; - - &hdmi0 { - status = "okay"; --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch new file mode 100644 index 0000000..f1a9f30 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch @@ -0,0 +1,82 @@ +From 9ad46b0976a91a5de41ab62c3d0fe923857a8dda Mon Sep 17 00:00:00 2001 +From: Nguyen Dang +Date: Tue, 6 Nov 2018 11:46:25 +0700 +Subject: [PATCH 6/6] ADSP: remove HDMI support from rcar-sound + +Signed-off-by: Nguyen Dang +--- + arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts | 6 ------ + arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts | 6 ------ + arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts | 5 ----- + arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts | 5 ----- + 4 files changed, 22 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts +index 6928afbd8e06..b268afd7df85 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts +@@ -104,12 +104,6 @@ + status = "okay"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1 /* HDMI0 */ +- &rsnd_port2>; /* HDMI1 */ +-}; +- + &hdmi0 { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts +index 498f78875dbd..b6ec3036e9fd 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts +@@ -114,12 +114,6 @@ + status = "okay"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1 /* HDMI0 */ +- &rsnd_port2>; /* HDMI1 */ +-}; +- + &hdmi0 { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts +index 02a938b416d0..2dba6e8e627a 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts +@@ -88,11 +88,6 @@ + "dclkin.0", "dclkin.1", "dclkin.2"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1>; /* HDMI0 */ +-}; +- + &hdmi0 { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts +index bd66be180d6d..708bd634b5af 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts +@@ -88,11 +88,6 @@ + "dclkin.0", "dclkin.1", "dclkin.2"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1>; /* HDMI0 */ +-}; +- + &hdmi0 { + status = "okay"; + +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch deleted file mode 100644 index c312fea..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 867b08a686424cb771dbf83814b44e64e72cebe2 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:49:09 +0900 -Subject: [PATCH 6/6] arm64: dts: r8a7796-salvator-x: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts -index 8e4f264ff8a3..9343244e8032 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts -@@ -91,11 +91,6 @@ - "dclkin.0", "dclkin.1", "dclkin.2"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1>; /* HDMI0 */ --}; -- - &lvds0 { - ports { - port@1 { --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers_4.14.bb b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers_4.14.bb index 68b24e7..34d3c3c 100644 --- a/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers_4.14.bb +++ b/meta-rcar-gen3/recipes-kernel/linux-libc-headers/linux-libc-headers_4.14.bb @@ -4,8 +4,8 @@ require include/adsp-control.inc RENESAS_BSP_URL = " \ git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas-bsp.git" -BRANCH = "v4.14.70-ltsi-rc1/rcar-3.8.0" -SRCREV = "52f8a317698424fe3a4ba7f88d2b87fc6bf6591d" +BRANCH = "v4.14.75-ltsi/rcar-3.9.2" +SRCREV = "a5266d298124874c2c06b8b13d073f6ecc2ee355" SRC_URI = "${RENESAS_BSP_URL};branch=${BRANCH}" @@ -14,22 +14,14 @@ SRC_URI_append = " \ ${@base_conditional("USE_ICCOM", "1", " file://0001-rpmsg-Add-message-to-be-able-to-configure-RPMSG_VIRT.patch", "", d)} \ " -# Device tree patches -SRC_URI_append = " \ - file://0001-arm64-dts-salvator-common-Rcar-Sound.patch \ - file://0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch \ - file://0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch \ - file://0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch \ - file://0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch \ - file://0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch \ -" - # Add ADSP ALSA driver SUPPORT_ADSP_ASOC = " \ - file://0001-Add-build-for-ADSP-sound-driver.patch \ - file://0002-Add-document-file-for-ADSP-sound-driver.patch \ - file://0003-Add-ADSP-sound-driver-source.patch \ - file://0004-Update-device-tree-for-ADSP-sound-driver.patch \ + file://0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch \ + file://0002-ADSP-add-ADSP-sound-driver-source.patch \ + file://0003-ADSP-add-build-for-ADSP-sound-driver.patch \ + file://0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch \ + file://0005-ADSP-integrate-ADSP-sound-for-E3-board.patch \ + file://0006-ADSP-remove-HDMI-support-from-rcar-sound.patch \ " SRC_URI_append = " \ diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch new file mode 100644 index 0000000..765053f --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch @@ -0,0 +1,32 @@ +From 5f378e5db591a4a119b6cface6037cbded240506 Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Thu, 25 Oct 2018 13:25:10 +0700 +Subject: [PATCH 1/6] ADSP: add document for compatible string + "renesas,rcar_adsp_sound_gen3" + +Signed-off-by: tienphitran +--- + .../devicetree/bindings/sound/renesas,adsp.txt | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 Documentation/devicetree/bindings/sound/renesas,adsp.txt + +diff --git a/Documentation/devicetree/bindings/sound/renesas,adsp.txt b/Documentation/devicetree/bindings/sound/renesas,adsp.txt +new file mode 100644 +index 000000000000..b529bcadea82 +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/renesas,adsp.txt +@@ -0,0 +1,11 @@ ++Renesas ADSP sound driver ++ ++Required properties: ++- compatible : "renesas,rcar_adsp_sound_gen3" ++ ++Example: ++ ++rcar_adsp_sound: adsp_sound@0 { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++}; +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-Add-build-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-Add-build-for-ADSP-sound-driver.patch deleted file mode 100644 index 508600d..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-Add-build-for-ADSP-sound-driver.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 4e7d2e7b5737d9a7ffbd59ad260e6b86b2e48691 Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 17:57:56 +0700 -Subject: [PATCH 1/4] Add build for ADSP sound driver - -Signed-off-by: tienphitran - -diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig -index c0abad2..f5f6abb 100644 ---- a/sound/soc/Kconfig -+++ b/sound/soc/Kconfig -@@ -71,6 +71,7 @@ source "sound/soc/txx9/Kconfig" - source "sound/soc/ux500/Kconfig" - source "sound/soc/xtensa/Kconfig" - source "sound/soc/zte/Kconfig" -+source "sound/soc/adsp/Kconfig" - - # Supported codecs - source "sound/soc/codecs/Kconfig" -diff --git a/sound/soc/Makefile b/sound/soc/Makefile -index bf8c1e2..6e77abb 100644 ---- a/sound/soc/Makefile -+++ b/sound/soc/Makefile -@@ -52,3 +52,4 @@ obj-$(CONFIG_SND_SOC) += txx9/ - obj-$(CONFIG_SND_SOC) += ux500/ - obj-$(CONFIG_SND_SOC) += xtensa/ - obj-$(CONFIG_SND_SOC) += zte/ -+obj-$(CONFIG_SND_SOC) += adsp/ --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-arm64-dts-salvator-common-Rcar-Sound.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-arm64-dts-salvator-common-Rcar-Sound.patch deleted file mode 100644 index a7e0587..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-arm64-dts-salvator-common-Rcar-Sound.patch +++ /dev/null @@ -1,83 +0,0 @@ -From cda5747801eadd0f29a591bee4b36c6f1ae30a54 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:30 +0900 -Subject: [PATCH 1/6] arm64: dts: salvator-common: Rcar-Sound - -This Patch Adds Rcar_Sound - -Signed-off-by: Takeshi Kihara ---- - .../boot/dts/renesas/salvator-common.dtsi | 40 ++++++++----------- - 1 file changed, 16 insertions(+), 24 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -index 3257143e43c1..6cda02800731 100644 ---- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi -+++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -@@ -125,15 +125,21 @@ - regulator-boot-on; - regulator-always-on; - }; -+ rsnd_ak4613: sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,format = "left_j"; -+ simple-audio-card,bitclock-master = <&sndcpu>; -+ simple-audio-card,frame-master = <&sndcpu>; -+ sndcpu: simple-audio-card,cpu { -+ sound-dai = <&rcar_sound>; -+ }; - -- sound_card: sound { -- compatible = "audio-graph-card"; -- -- label = "rcar-sound"; -- -- dais = <&rsnd_port0>; -+ sndcodec: simple-audio-card,codec { -+ sound-dai = <&ak4613>; -+ }; - }; - -+ - vbus0_usb2: regulator-vbus0-usb2 { - compatible = "regulator-fixed"; - -@@ -454,12 +460,6 @@ - asahi-kasei,out4-single-end; - asahi-kasei,out5-single-end; - asahi-kasei,out6-single-end; -- -- port { -- ak4613_endpoint: endpoint { -- remote-endpoint = <&rsnd_endpoint0>; -- }; -- }; - }; - - cs2000: clk_multiplier@4f { -@@ -795,18 +795,10 @@ - <&audio_clk_c>, - <&cpg CPG_CORE CPG_AUDIO_CLK_I>; - -- ports { -- rsnd_port0: port@0 { -- rsnd_endpoint0: endpoint { -- remote-endpoint = <&ak4613_endpoint>; -- -- dai-format = "left_j"; -- bitclock-master = <&rsnd_endpoint0>; -- frame-master = <&rsnd_endpoint0>; -- -- playback = <&ssi0 &src0 &dvc0>; -- capture = <&ssi1 &src1 &dvc1>; -- }; -+ rcar_sound,dai { -+ dai0 { -+ playback = <&ssi0 &src0 &dvc0>; -+ capture = <&ssi1 &src1 &dvc1>; - }; - }; - }; --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-ADSP-add-ADSP-sound-driver-source.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-ADSP-add-ADSP-sound-driver-source.patch new file mode 100644 index 0000000..8da35f4 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-ADSP-add-ADSP-sound-driver-source.patch @@ -0,0 +1,7217 @@ +From 8fb0a86601a73224c5c0b76e3b0037a40da880fc Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Mon, 15 Oct 2018 18:00:42 +0700 +Subject: [PATCH 2/6] ADSP: add ADSP sound driver source + +Signed-off-by: tienphitran +--- + include/adsp_drv/xf-adsp-drv-ext.h | 58 + + sound/soc/adsp/Kconfig | 14 + + sound/soc/adsp/Makefile | 3 + + sound/soc/adsp/xf-adsp-alsa.c | 3936 ++++++++++++++++++++++++++++ + sound/soc/adsp/xf-adsp-base.c | 2259 ++++++++++++++++ + sound/soc/adsp/xf-adsp-base.h | 275 ++ + sound/soc/adsp/xf-adsp-config.h | 604 +++++ + 7 files changed, 7149 insertions(+) + create mode 100644 include/adsp_drv/xf-adsp-drv-ext.h + create mode 100644 sound/soc/adsp/Kconfig + create mode 100644 sound/soc/adsp/Makefile + create mode 100644 sound/soc/adsp/xf-adsp-alsa.c + create mode 100644 sound/soc/adsp/xf-adsp-base.c + create mode 100644 sound/soc/adsp/xf-adsp-base.h + create mode 100644 sound/soc/adsp/xf-adsp-config.h + +diff --git a/include/adsp_drv/xf-adsp-drv-ext.h b/include/adsp_drv/xf-adsp-drv-ext.h +new file mode 100644 +index 000000000000..6c3dbc0be1ef +--- /dev/null ++++ b/include/adsp_drv/xf-adsp-drv-ext.h +@@ -0,0 +1,58 @@ ++/***************************************************************************** ++ * \file xf-adsp-driver-ext.h ++ * \brief Header file for ADSP driver extension part ++ * \addtogroup ADSP Driver ++ ****************************************************************************** ++ * \date Oct. 21, 2017 ++ * \author Renesas Electronics Corporation ++ ****************************************************************************** ++ * \par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#ifndef __XF_ADSP_DRV_EXT_H ++#define __XF_ADSP_DRV_EXT_H ++ ++/*********************************************************** ++ * Extension client APIs ++ * ********************************************************/ ++ ++struct xf_adsp_base_cmd { ++ /* register new client for ADSP base control */ ++ int (*client_register)(void **private_data); ++ /* unregister client */ ++ int (*client_unregister)(void *private_data); ++ /* get data from proxy */ ++ int (*recv)(void *private_data, void *buf); ++ /* send data to proxy */ ++ int (*send)(void *private_data, void *buf); ++ /* wait the valid message in the response queue */ ++ int (*poll)(void *private_data, int *condition); ++}; ++ ++/* create ADSP base control data */ ++int xf_adsp_base_create(struct xf_adsp_base_cmd *cmd); ++ ++/* destroy ADSP base control data */ ++int xf_adsp_base_destroy(void); ++ ++#endif +diff --git a/sound/soc/adsp/Kconfig b/sound/soc/adsp/Kconfig +new file mode 100644 +index 000000000000..605261f0855f +--- /dev/null ++++ b/sound/soc/adsp/Kconfig +@@ -0,0 +1,14 @@ ++## SoC for ADSP driver configuration ++menu "ASoC ADSP driver" ++ ++config SND_SOC_ADSP ++ tristate "SoC Audio for R-Car ADSP" ++ select SND_SIMPLE_CARD ++ select SND_SIMPLE_SCU_CARD ++ select SND_AUDIO_GRAPH_CARD ++ select SND_AUDIO_GRAPH_SCU_CARD ++ default y ++ help ++ This option enables ALSA ADSP sound supports ADSP module ++ ++endmenu +diff --git a/sound/soc/adsp/Makefile b/sound/soc/adsp/Makefile +new file mode 100644 +index 000000000000..8277fdbc5bbe +--- /dev/null ++++ b/sound/soc/adsp/Makefile +@@ -0,0 +1,3 @@ ++## Makefile for SoC ADSP driver ++snd-soc-adsp-objs := xf-adsp-alsa.o xf-adsp-base.o ++obj-$(CONFIG_SND_SOC_ADSP) += snd-soc-adsp.o +diff --git a/sound/soc/adsp/xf-adsp-alsa.c b/sound/soc/adsp/xf-adsp-alsa.c +new file mode 100644 +index 000000000000..e602c6efcc6a +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-alsa.c +@@ -0,0 +1,3936 @@ ++/** *************************************************************************** ++ * \file xf-adsp-alsa.c ++ * \brief Source file for ADSP ALSA Driver ++ * \addtogroup ADSP Driver ++ ****************************************************************************** ++ * \date Oct. 21, 2017 ++ * \author Renesas Electronics Corporation ++ ****************************************************************************** ++ * \par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ *****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xf-adsp-base.h" ++ ++/* Name of Volume control for playback */ ++#define PLAYBACK_VOLUME_CTR_NAME "PlaybackVolume" ++ ++/* Name of Volume control for capture */ ++#define CAPTURE_VOLUME_CTR_NAME "CaptureVolume" ++ ++/* Name of Sample Rate control for playback */ ++#define PLAYBACK_OUT_RATE_CTR_NAME "PlaybackOutRate" ++ ++/* Name of Output Channel control for playback */ ++#define PLAYBACK_OUT_CHANNEL_CTR_NAME "PlaybackOutChannel" ++ ++/* Name of Sample Rate control for capture */ ++#define CAPTURE_IN_RATE_CTR_NAME "CaptureInRate" ++ ++/* Name of Equalizer parameters control for playback */ ++#define PLAYBACK_EQZ_CTR_NAME "PlaybackEQZControl" ++ ++/* Name of Equalizer parameters control for capture */ ++#define CAPTURE_EQZ_CTR_NAME "CaptureEQZControl" ++ ++/* Name of Equalizer Switch control for playback */ ++#define PLAYBACK_EQZ_SWITCH_CTR_NAME "PlaybackEQZSwitch" ++ ++/* Name of Equalizer Switch control for capture */ ++#define CAPTURE_EQZ_SWITCH_CTR_NAME "CaptureEQZSwitch" ++ ++/* Name of Volume control for TDM playback */ ++#define TDM_PLAYBACK_VOLUME_CTR_NAME "TDMPlaybackVolume" ++ ++/* Name of Volume control for TDM capture */ ++#define TDM_CAPTURE_VOLUME_CTR_NAME "TDMCaptureVolume" ++ ++/* Name of Sample Rate control for TDM playback */ ++#define TDM_PLAYBACK_OUT_RATE_CTR_NAME "TDMPlaybackOutRate" ++ ++/* Name of Sample Rate control for TDM capture */ ++#define TDM_CAPTURE_IN_RATE_CTR_NAME "TDMCaptureInRate" ++ ++/* Prefix of Playback control name */ ++#define PREFIX_OF_PLAYBACK_CTR_NAME PLAYBACK_VOLUME_CTR_NAME[0] ++ ++/* Prefix of Capture control name */ ++#define PREFIX_OF_CAPTURE_CTR_NAME CAPTURE_VOLUME_CTR_NAME[0] ++ ++/* Prefix of TDM control name */ ++#define PREFIX_OF_TDM_CTR_NAME TDM_PLAYBACK_VOLUME_CTR_NAME[0] ++ ++/* Prefix of TDM playback */ ++#define TDM_PLAYBACK TDM_PLAYBACK_VOLUME_CTR_NAME[3] ++ ++/* Prefix of TDM record */ ++#define TDM_CAPTURE TDM_CAPTURE_VOLUME_CTR_NAME[3] ++ ++/* Number of control for playback & capture */ ++#define RDR_CONTROL_NUM (9) ++ ++/* Number of controls for TDM */ ++#define TDM_CONTROL_NUM (4) ++ ++/* Indicate playback stream */ ++#define DIRECT_PLAYBACK (0) ++ ++/* Indicate capture stream */ ++#define DIRECT_CAPTURE (1) ++ ++/* Indicate stream number */ ++#define DIRECT_NUM (2) ++ ++/* Supported frame size for playback/record function in driver */ ++#define FRAME_SIZE (1024) ++ ++/* Supported frame size for TDM playback/record function in driver */ ++#define TDM_FRAME_SIZE (1024) ++ ++/* Supported sample rate in driver */ ++#define SND_ADSP_SAMPLE_RATES (SNDRV_PCM_RATE_32000 | \ ++ SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_48000) ++ ++/* Supported PCM width in driver */ ++#define SND_ADSP_PCM_WIDTHS (SNDRV_PCM_FMTBIT_S16_LE | \ ++ SNDRV_PCM_FMTBIT_S24_LE) ++ ++/* Macro to control DAI index */ ++/* DAI 0 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX0 (0) ++ ++/* DAI 1 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX1 (1) ++ ++/* DAI 2 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX2 (2) ++ ++/* DAI 3 index for playback/record functions of stereo/mono formats */ ++#define RDR_DAI_IDX3 (3) ++ ++/* DAI 4 index for playback/record functions of TDM formats */ ++#define TDM_DAI_IDX (4) ++ ++/* Maximum number of DAI supported by driver */ ++#define MAX_DAI_IDX (5) ++ ++/* Renderer/Capture software information */ ++/* Minimum channel number supported */ ++#define MIN_CHANNEL (1) ++ ++/* Maximum channel number supported */ ++#define MAX_CHANNEL (2) ++ ++/* Minimum buffer size in byte */ ++#define MIN_BUF_SIZE (FRAME_SIZE * MIN_CHANNEL * 2) ++ ++/* Maximum buffer size in byte */ ++#define MAX_BUF_SIZE (FRAME_SIZE * MAX_CHANNEL * 4) ++ ++/* Minimum numbers of period in the buffer */ ++#define MIN_PERIOD (1) ++ ++/* Maximum numbers of period in the buffer */ ++#define MAX_PERIOD (4) ++ ++/* Maximun numbers of bytes in ALSA buffer */ ++#define MAX_BUFFER_BYTES (MAX_PERIOD * MAX_BUF_SIZE) ++ ++/* TDM software information */ ++/*< Minimum channel number supported in TDM plugin */ ++#define TDM_MIN_CHANNEL (6) ++ ++/* Maximum channel number supported in TDM plugin */ ++#define TDM_MAX_CHANNEL (8) ++ ++/* Minimum buffer size in byte for TDM format */ ++#define TDM_MIN_BUF_SIZE (TDM_FRAME_SIZE * TDM_MIN_CHANNEL * 2) ++ ++/* Maximum buffer size in byte for TDM format */ ++#define TDM_MAX_BUF_SIZE (TDM_FRAME_SIZE * TDM_MAX_CHANNEL * 4) ++ ++/* Minimum numbers of period in the buffer for TDM format */ ++#define TDM_MIN_PERIOD (1) ++ ++/* Maximum numbers of period in the buffer for TDM format */ ++#define TDM_MAX_PERIOD (4) ++ ++/* Maximum numbers of bytes in ALSA buffer for TDM format */ ++#define TDM_MAX_BUFFER_BYTES (TDM_MAX_PERIOD * TDM_MAX_BUF_SIZE) ++ ++/* Volume scale used when user set */ ++#define VOLUME_SCALE (100) ++ ++/* Maximum element in Equalizer parameter control */ ++#define MAX_EQZ_PARAM_NUMBER (55) ++ ++/* Equalizer control is disabled */ ++#define EQZ_OFF (0) ++ ++/* Equalizer control is enabled */ ++#define EQZ_ON (1) ++ ++/* Component status */ ++/* Handle state is NULL */ ++#define XF_HANDLE_NULL (0) ++ ++/* Handle state is CREATED after creating handle successfully */ ++#define XF_HANDLE_CREATED BIT(0) ++ ++/* Handle state is READY after finishing handle init */ ++#define XF_HANDLE_READY BIT(1) ++ ++/* channels */ ++/* Mono stream */ ++#define MONAURAL (1) ++ ++/* Stereo stream */ ++#define STEREO (2) ++ ++/* define number of bytes in a sample of 24 bits format types */ ++/* store 24 bits data in 4 bytes LE */ ++#define FMTBIT_S24_LE_BYTES_PER_SAMPLE (4) ++ ++/* store 24 bits data in 3 bytes LE */ ++#define FMTBIT_S24_3LE_BYTES_PER_SAMPLE (3) ++ ++/* helper macro to get bytes per sample number */ ++#define BYTES_PER_SAMPLE(fmt) (FMTBIT_##fmt##_BYTES_PER_SAMPLE) ++ ++/* check component is created */ ++#define COMPONENT_IS_CREATED(n) (((n & XF_HANDLE_CREATED) != 0) ? TRUE : FALSE) ++ ++/* check component is ready */ ++#define COMPONENT_IS_READY(n) (((n & XF_HANDLE_READY) != 0) ? TRUE : FALSE) ++ ++/* indicator of stream order */ ++#define MIX_UNUSED (0) ++#define FIRST_RUN (2) ++#define SECOND_RUN (1) ++ ++/* check MIX usage */ ++#define MIX_ENABLED(mix_ctl) ((mix_ctl == SECOND_RUN) ? TRUE : FALSE) ++ ++/******************************************************************* ++ * base structures for ADSP ALSA driver ++ * ****************************************************************/ ++ ++/** \struct snd_adsp_control ++ * \brief Structure stores parameters from user ++ */ ++struct snd_adsp_control { ++ /* Volume rate for playback/record */ ++ int vol_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Volume rate for TDM playback/TDM record */ ++ int tdm_vol_rate[DIRECT_NUM]; ++ ++ /* Out sample rate with Renderer, in sample rate with Capture */ ++ int sample_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Out sample rate for TDM Renderer, in sample rate for TDM Capture */ ++ int tdm_sample_rate[DIRECT_NUM]; ++ ++ /* Output channel of playback */ ++ int rdr_out_ch[MAX_DAI_IDX - 1]; ++ ++ /* Equalizer parameters */ ++ struct xf_adsp_equalizer_params eqz_params[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Equalizer switch */ ++ int eqz_switch[DIRECT_NUM][MAX_DAI_IDX - 1]; ++ ++ /* Indicator of MIX usage */ ++ int mix_usage; ++}; ++ ++/** \struct snd_adsp_base_info ++ * \brief Structure stores some base information of a stream ++ */ ++struct snd_adsp_base_info { ++ /* high resolution timer data */ ++ struct hrtimer hrtimer; ++ ++ /* kernel time value in nanosecond */ ++ ktime_t ktime; ++ ++ /* high resolution timer state */ ++ int hrt_state; ++ ++ /* target handle id of ALSA driver */ ++ int handle_id; ++ ++ /* data buffer */ ++ char *buffer[XF_BUF_POOL_SIZE]; ++ ++ /* size of each allocated data buffer */ ++ int buf_bytes; ++ ++ /* data index of buffer */ ++ int buf_idx; ++ ++ /* queue index of buffer */ ++ int buf_queue; ++ ++ /* HW index in bytes */ ++ int hw_idx; ++ ++ /* number of bytes in a period */ ++ int period_bytes; ++ ++ /* substream runtime object */ ++ struct snd_pcm_substream *substream; ++ ++ /* indirect PCM data transfer */ ++ struct snd_pcm_indirect pcm_indirect; ++ ++ /* spinlock data */ ++ spinlock_t lock; ++ ++ /* runtime error indicator */ ++ int runtime_err; ++}; ++ ++/** \struct snd_adsp_playback ++ * \brief Structure stores data for playback function ++ */ ++struct snd_adsp_playback { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* Renderer component data */ ++ struct xf_adsp_renderer *renderer; ++ ++ /* Equalizer component data */ ++ struct xf_adsp_equalizer *equalizer; ++ ++ /* Renderer component state */ ++ int rdr_state; ++ ++ /* Equalizer component state */ ++ int eqz_state; ++}; ++ ++/** \struct snd_adsp_record ++ * \brief Structure stores data for record function ++ */ ++struct snd_adsp_record { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* Capture component data */ ++ struct xf_adsp_capture *capture; ++ ++ /* Equalizer component data */ ++ struct xf_adsp_equalizer *equalizer; ++ ++ /* Capture component state */ ++ int cap_state; ++ ++ /* Equalizer component state */ ++ int eqz_state; ++}; ++ ++/** \struct snd_adsp_tdm_playback ++ * \brief Structure stores data for TDM playback function ++ */ ++struct snd_adsp_tdm_playback { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* TDM Renderer component data */ ++ struct xf_adsp_tdm_renderer *tdm_renderer; ++ ++ /* TDM Renderer component state */ ++ int state; ++}; ++ ++/** \struct snd_adsp_tdm_record ++ * \brief Structure stores data for TDM record function ++ */ ++struct snd_adsp_tdm_record { ++ /* base information of stream */ ++ struct snd_adsp_base_info base; ++ ++ /* TDM Capture component data */ ++ struct xf_adsp_tdm_capture *tdm_capture; ++ ++ /* TDM Capture component state */ ++ int state; ++}; ++ ++/** \struct snd_adsp_card ++ * \brief Structure stores data for ALSA sound card ++ */ ++struct snd_adsp_card { ++ /* playback data */ ++ struct snd_adsp_playback *playback[MAX_DAI_IDX - 1]; ++ ++ /* record data */ ++ struct snd_adsp_record *record[MAX_DAI_IDX - 1]; ++ ++ /* TDM playback data */ ++ struct snd_adsp_tdm_playback *tdm_playback; ++ ++ /* TDM record data */ ++ struct snd_adsp_tdm_record *tdm_record; ++ ++ /* Structure contains params information for control */ ++ struct snd_adsp_control ctr_if; ++}; ++ ++/** HW configuration of ALSA ADSP card for Renderer/Capture */ ++static struct snd_pcm_hardware snd_pcm_adsp_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ ++ | SNDRV_PCM_INFO_RESUME ++ | SNDRV_PCM_INFO_BLOCK_TRANSFER ++ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SND_ADSP_PCM_WIDTHS, ++ .rates = SND_ADSP_SAMPLE_RATES, ++ .rate_min = 32000, ++ .rate_max = 48000, ++ .channels_min = MIN_CHANNEL, ++ .channels_max = MAX_CHANNEL, ++ ++ /* maximum buffer size in bytes */ ++ .buffer_bytes_max = MAX_BUFFER_BYTES, ++ ++ /* minimum size of the periods (frame) in bytes */ ++ .period_bytes_min = MIN_BUF_SIZE, ++ ++ /* maximum size of the periods (frame) in bytes */ ++ .period_bytes_max = MAX_BUF_SIZE, ++ ++ /* minimum periods (frames) in a buffer */ ++ .periods_min = MIN_PERIOD, ++ ++ /* maximum periods (frames) in a buffer */ ++ .periods_max = MAX_PERIOD, ++}; ++ ++/* HW configuration of ALSA ADSP card for TDM */ ++static struct snd_pcm_hardware snd_pcm_adsp_tdm_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ ++ | SNDRV_PCM_INFO_RESUME ++ | SNDRV_PCM_INFO_BLOCK_TRANSFER ++ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SND_ADSP_PCM_WIDTHS, ++ .rates = SND_ADSP_SAMPLE_RATES, ++ .rate_min = 32000, ++ .rate_max = 48000, ++ .channels_min = TDM_MIN_CHANNEL, ++ .channels_max = TDM_MAX_CHANNEL, ++ ++ /* maximum buffer size in bytes */ ++ .buffer_bytes_max = TDM_MAX_BUFFER_BYTES, ++ ++ /* minimum size of the periods (frame) in bytes */ ++ .period_bytes_min = TDM_MIN_BUF_SIZE, ++ ++ /* maximum size of the periods (frame) in bytes */ ++ .period_bytes_max = TDM_MAX_BUF_SIZE, ++ ++ /* minimum periods (frames) in a buffer */ ++ .periods_min = TDM_MIN_PERIOD, ++ ++ /* maximum periods (frames) in a buffer */ ++ .periods_max = TDM_MAX_PERIOD, ++}; ++ ++/******************************************************************* ++ * function declaration ++ * ****************************************************************/ ++ ++static int ++snd_adsp_rdr_empty_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_rdr_fill_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_cap_empty_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_cap_fill_buf_done(void *data, int opcode, int length, char *buffer); ++static int ++snd_adsp_get_dai_id_from_substream(struct snd_pcm_substream *substream); ++static void * ++snd_adsp_get_drvdata_from_substream(struct snd_pcm_substream *substream); ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_substream(struct snd_pcm_substream *substream); ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_hrt(struct hrtimer *hrt); ++static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt); ++static int snd_adsp_playback_init(struct snd_adsp_playback **data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_record_init(struct snd_adsp_record **data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_record_prepare(struct snd_adsp_record *record, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback); ++static int snd_adsp_record_deinit(struct snd_adsp_record *record); ++static int snd_adsp_tdm_playback_init(struct snd_adsp_tdm_playback **data, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_tdm_record_init(struct snd_adsp_tdm_record **data, ++ struct snd_pcm_substream *substream); ++static int ++snd_adsp_tdm_playback_prepare(struct snd_adsp_tdm_playback *tdm_playback, ++ struct snd_pcm_substream *substream); ++static int snd_adsp_tdm_record_prepare(struct snd_adsp_tdm_record *tdm_record, ++ struct snd_pcm_substream *substream); ++static int ++snd_adsp_tdm_playback_deinit(struct snd_adsp_tdm_playback *tdm_playback); ++static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record); ++static int snd_adsp_pcm_open(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_close(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params); ++static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx); ++static snd_pcm_uframes_t ++snd_adsp_pcm_pointer(struct snd_pcm_substream *substream); ++static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream); ++static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, size_t bytes); ++static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int ++snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo); ++static int ++snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int ++snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static void snd_adsp_get_eqz_params_from_control( ++ struct xf_adsp_equalizer_params *eqz_params, ++ struct xf_adsp_equalizer_params *eqz_ctr_params, ++ bool flag); ++static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime); ++static int snd_adsp_probe(struct platform_device *pdev); ++static int snd_adsp_remove(struct platform_device *pdev); ++ ++/******************************************************************* ++ * callback function of ADSP control interface ++ * ****************************************************************/ ++/** ************************************************************************** ++ * \brief event handler callback to notify error from ADSP ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_event_handler(void *data) ++{ ++ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; ++ ++ if (base) ++ base->runtime_err = TRUE; ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief empty buf done callback for playback/TDM playback functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_rdr_empty_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; ++ ++ if (base) { ++ spin_lock(&base->lock); ++ ++ base->buf_queue++; ++ base->hw_idx += length; /* increase the DMA buffer index */ ++ ++ spin_unlock(&base->lock); ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief fill buf done callback for playback/TDM playback functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_rdr_fill_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief empty buf done callback for record/TDM record functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_cap_empty_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief fill buf done callback for record/TDM record functions ++ * ++ * \param[in] data Pointer to ADSP ALSA sound card ++ * \param[in] opcode Opcode of message ++ * \param[in] length Length of data buffer ++ * \param[in] buffer Pointer to data buffer ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_cap_fill_buf_done(void *data, int opcode, int length, char *buffer) ++{ ++ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; ++ ++ if (base) { ++ spin_lock(&base->lock); ++ ++ base->buf_queue++; ++ base->hw_idx += length; /* increase the DMA buffer index */ ++ ++ spin_unlock(&base->lock); ++ } ++ ++ return 0; ++} ++ ++/** callback functions for playback/TDM playback */ ++static struct xf_callback_func rdr_callbacks = /* PRQA S 3218 */ ++{ ++ .empty_buf_done = &snd_adsp_rdr_empty_buf_done, /* PRQA S 1053 2 */ ++ .fill_buf_done = &snd_adsp_rdr_fill_buf_done, ++ .event_handler = &snd_adsp_event_handler ++}; ++ ++/** callback functions for record/TDM record */ ++static struct xf_callback_func cap_callbacks = /* PRQA S 3218 */ ++{ ++ .empty_buf_done = &snd_adsp_cap_empty_buf_done, /* PRQA S 1053 2 */ ++ .fill_buf_done = &snd_adsp_cap_fill_buf_done, ++ .event_handler = &snd_adsp_event_handler ++}; ++ ++/******************************************************************* ++ * helper functions to get some internal data ++ * ****************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Get current index of CPU DAI from runtime data of substream ++ * ++ * \param[in] substream Pointer to PCM stream data ++ * \retval id Index of current CPU DAI ++ *****************************************************************************/ ++static int ++snd_adsp_get_dai_id_from_substream(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd; ++ ++ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; ++ return rtd->cpu_dai->id; ++} ++ ++/** ************************************************************************** ++ * \brief Get ADSP ALSA driver's data from runtime data of substream ++ * ++ * \param[in] substream Pointer to PCM stream data ++ * \retval pointer Pointer to driver's data ++ *****************************************************************************/ ++static void * ++snd_adsp_get_drvdata_from_substream(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd; ++ ++ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; ++ return snd_soc_dai_get_drvdata(rtd->cpu_dai); ++} ++ ++/** ************************************************************************** ++ * \brief Get base's data of playback/record from runtime data of substream ++ * ++ * \param[in] substream Pointer to PCM stream data ++ * \retval pointer Pointer to playback/record's base data ++ *****************************************************************************/ ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_substream(struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ struct snd_adsp_base_info *base; ++ int dai_idx; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ ++ /* get DAI index of substream */ ++ dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ ++ /* get base data of the substream */ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ base = !adsp_card->playback[dai_idx] ? ++ NULL : &adsp_card->playback[dai_idx]->base; ++ } else { ++ base = !adsp_card->record[dai_idx] ? ++ NULL : &adsp_card->record[dai_idx]->base; ++ } ++ } else { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ base = !adsp_card->tdm_playback ? ++ NULL : &adsp_card->tdm_playback->base; ++ } else { ++ base = !adsp_card->tdm_record ? ++ NULL : &adsp_card->tdm_record->base; ++ } ++ } ++ ++ return base; ++} ++ ++/** *************************************************************************** ++ * \brief Get playback/record/TDM playback/TDM record's base data ++ * from hr timer data ++ * ++ * \param[in] hrt Pointer to hr timer data ++ * \retval pointer Pointer to playback/record's base data ++ *****************************************************************************/ ++static struct snd_adsp_base_info * ++snd_adsp_get_base_from_hrt(struct hrtimer *hrt) ++{ ++ return (struct snd_adsp_base_info *)hrt; ++} ++ ++/***************************************************************************** ++ * hrtimer interrupt function ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Interrupt function of high resolution timer ++ * ++ * \param[in] hrt Pointer to hr timer data ++ * \retval HRTIMER_RESTART Restart the timer after expire time ++ *****************************************************************************/ ++static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt) ++{ ++ struct snd_adsp_base_info *base = snd_adsp_get_base_from_hrt(hrt); ++ ++ spin_lock(&base->lock); ++ if (base->hw_idx != 0) { ++ spin_unlock(&base->lock); ++ /* update PCM status for the next period */ ++ snd_pcm_period_elapsed(base->substream); ++ } else { ++ spin_unlock(&base->lock); ++ } ++ ++ hrtimer_forward_now(hrt, base->ktime); ++ ++ return HRTIMER_RESTART; ++} ++ ++/***************************************************************************** ++ * internal functions to manage playback and record functions ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Initialize playback data ++ * ++ * \param[out] playback_data Pointer to store playback data ++ * \param[in] eqz_flag Flag to indicate equalizer usage ++ * \param[in] substream Pointer to substream data ++ * \retval EINVAL Failed to initialize playback data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_playback_init(struct snd_adsp_playback **playback_data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_playback *playback; ++ ++ /* allocate memory for playback data */ ++ playback = kmalloc(sizeof(*playback), GFP_KERNEL); ++ if (!playback) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(playback, 0, sizeof(struct snd_adsp_playback)); ++ ++ /* save the playback data */ ++ *playback_data = playback; ++ ++ /* set handle state as NULL state */ ++ playback->rdr_state = XF_HANDLE_NULL; ++ playback->eqz_state = XF_HANDLE_NULL; ++ playback->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register renderer component */ ++ if (xf_adsp_renderer_create(&playback->renderer, ++ &rdr_callbacks, ++ (void *)&playback->base) < 0) ++ return -EINVAL; ++ ++ /* mark renderer component created */ ++ playback->rdr_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as renderer ID */ ++ playback->base.handle_id = playback->renderer->handle_id; ++ ++ if (eqz_flag == EQZ_ON) { ++ /* create equalizer component when equalizer is used */ ++ if (xf_adsp_equalizer_create(&playback->equalizer, ++ &rdr_callbacks, ++ (void *)&playback->base) < 0) ++ return -EINVAL; ++ ++ /* mark equalizer component created */ ++ playback->eqz_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as equalizer ID */ ++ playback->base.handle_id = playback->equalizer->handle_id; ++ } ++ ++ /* init lock */ ++ spin_lock_init(&playback->base.lock); ++ ++ /* save the substream data */ ++ playback->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&playback->base.hrtimer, ++ CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ playback->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ playback->base.hrt_state = XF_HANDLE_CREATED; ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Initialize record data ++ * ++ * \param[out] record_data Pointer to store record data ++ * \param[in] eqz_flag Flag to indicate equalizer usage ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to initialize record data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_record_init(struct snd_adsp_record **record_data, ++ int eqz_flag, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_record *record; ++ ++ /* allocate memory for record data */ ++ record = kmalloc(sizeof(*record), GFP_KERNEL); ++ if (!record) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(record, 0, sizeof(struct snd_adsp_record)); ++ ++ /* save the record data */ ++ *record_data = record; ++ ++ /* set handle state as NULL state */ ++ record->cap_state = XF_HANDLE_NULL; ++ record->eqz_state = XF_HANDLE_NULL; ++ record->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register capture component */ ++ if (xf_adsp_capture_create(&record->capture, ++ &cap_callbacks, ++ (void *)&record->base) < 0) ++ return -EINVAL; ++ ++ /* mark capture component created */ ++ record->cap_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as capture ID */ ++ record->base.handle_id = record->capture->handle_id; ++ ++ /* create equalizer component in case of it being used */ ++ if (eqz_flag == EQZ_ON) { ++ if (xf_adsp_equalizer_create(&record->equalizer, ++ &cap_callbacks, ++ (void *)&record->base) < 0) ++ return -EINVAL; ++ ++ /* mark equalizer component created */ ++ record->eqz_state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as equalizer ID */ ++ record->base.handle_id = record->equalizer->handle_id; ++ } ++ ++ /* init lock */ ++ spin_lock_init(&record->base.lock); ++ ++ /* save the substream data */ ++ record->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&record->base.hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ record->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ record->base.hrt_state = XF_HANDLE_CREATED; ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare playback function ++ * ++ * \param[out] playback Pointer to playback data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, hw_buffer_size; ++ int out_rate; ++ struct snd_adsp_control *ctr_if; ++ struct snd_pcm_runtime *runtime; ++ struct xf_adsp_renderer *renderer; ++ struct xf_adsp_equalizer *equalizer; ++ struct snd_adsp_base_info *base; ++ int i; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ runtime = substream->runtime; ++ renderer = playback->renderer; ++ equalizer = playback->equalizer; ++ base = &playback->base; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ ch = runtime->channels; ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ vol_rate = ctr_if->vol_rate[DIRECT_PLAYBACK][dai_idx]; ++ out_rate = ctr_if->sample_rate[DIRECT_PLAYBACK][dai_idx]; ++ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ ++ if (pcm_width == 16) ++ base->buf_bytes = base->period_bytes; ++ else ++ base->buf_bytes = (base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = hw_buffer_size; ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ /* it should equal to a period size in bytes */ ++ base->pcm_indirect.hw_queue_size = base->period_bytes; ++ ++ /* set parameters when Renderer is not ready */ ++ if (COMPONENT_IS_READY(playback->rdr_state) == FALSE) { ++ struct xf_adsp_renderer_params *params = &renderer->params; ++ ++ /* apply renderer parameters */ ++ params->in_rate = fs; ++ params->channel = ch; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ if (ctr_if->mix_usage == SECOND_RUN) ++ params->mix_ctrl = ctr_if->mix_usage; ++ else ++ params->mix_ctrl = MIX_UNUSED; ++ ++ /* set flow as ADSP->PDMA0->SRC0->PDMA1->SSI0 */ ++ params->dev1 = SRC0; ++ params->dev2 = SSI00; ++ params->dma1 = PDMA_CH00; ++ params->dma2 = PDMA_CH01; ++ ++ /* when MIX is enabled, change to DMAC transfer type to save */ ++ /* hw FIFO */ ++ if (MIX_ENABLED(params->mix_ctrl) == TRUE) ++ params->dma1 = ADMAC_CH01; ++ ++ /* set volume rate if it is set by user or default value */ ++ /* is 100% */ ++ if (vol_rate >= 0) ++ params->vol_rate = vol_rate; ++ else ++ params->vol_rate = (1 << 20); ++ ++ /* set output channel if it is set by user */ ++ if (ctr_if->rdr_out_ch[dai_idx] >= MONAURAL) ++ params->out_channel = ctr_if->rdr_out_ch[dai_idx]; ++ else ++ params->out_channel = params->channel; ++ ++ /* set sample rate output if it is set by user */ ++ if (out_rate >= 0) ++ params->out_rate = out_rate; ++ ++ /* set parameters to ADSP Renderer plugin */ ++ if (xf_adsp_renderer_set_params(renderer) != 0) ++ return -EINVAL; ++ ++ /* allocate buffer pool to prepare the execution */ ++ renderer->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(renderer->buf_pool)) /* PRQA S 306*/ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ renderer->buf_pool, i); ++ ++ base->buf_queue++; ++ memset(base->buffer[i], 0, base->buf_bytes); ++ } ++ ++ /* mark Renderer ready */ ++ playback->rdr_state |= XF_HANDLE_READY; ++ ++ /* set parameters for Equalizer if it is used */ ++ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { ++ /* apply Equalizer parameter setting */ ++ equalizer->params.channel = ch; ++ equalizer->params.pcm_width = pcm_width; ++ equalizer->params.rate = fs; ++ ++ /* get equalizer parameters from control interface */ ++ /* data */ ++ snd_adsp_get_eqz_params_from_control( ++ &equalizer->params, ++ &ctr_if->eqz_params[DIRECT_PLAYBACK][dai_idx], ++ true); ++ ++ /* set parameters to Equalizer plugin */ ++ if (xf_adsp_equalizer_set_params(equalizer) != 0) ++ return -EINVAL; ++ ++ /* route Equalizer to Renderer */ ++ if (xf_adsp_route(equalizer->handle_id, ++ renderer->handle_id, ++ XF_BUF_POOL_SIZE, ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ /* mark Equalizer ready */ ++ playback->eqz_state |= XF_HANDLE_READY; ++ ++ /* prepare data before start PCM */ ++ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ /* send buffer to plugin to kick */ ++ /* init-processing */ ++ if (xf_adsp_empty_this_buffer( ++ base->handle_id, ++ base->buffer[i], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ } ++ } else { ++ /* send zero buffer to plugin to kick */ ++ /* init-processing */ ++ if (xf_adsp_empty_this_buffer(base->handle_id, ++ base->buffer[0], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ } ++ ++ /* wait until all the buffer have been consummed */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ /* reset HW index */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare record function ++ * ++ * \param[out] record Pointer to record data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_record_prepare(struct snd_adsp_record *record, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, in_rate; ++ int hw_buffer_size, hw_queue_size; ++ struct snd_adsp_control *ctr_if; ++ struct snd_pcm_runtime *runtime; ++ struct xf_adsp_capture *capture; ++ struct xf_adsp_equalizer *equalizer; ++ struct snd_adsp_base_info *base; ++ int i; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ runtime = substream->runtime; ++ capture = record->capture; ++ equalizer = record->equalizer; ++ base = &record->base; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ ch = runtime->channels; ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ vol_rate = ctr_if->vol_rate[DIRECT_CAPTURE][dai_idx]; ++ in_rate = ctr_if->sample_rate[DIRECT_CAPTURE][dai_idx]; ++ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ /* total size of allocated buffers */ ++ hw_queue_size = base->period_bytes * XF_BUF_POOL_SIZE; ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ ++ if (pcm_width == 16) ++ base->buf_bytes = base->period_bytes; ++ else ++ base->buf_bytes = ((base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = hw_buffer_size; ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ base->pcm_indirect.hw_queue_size = hw_queue_size; ++ ++ /* prepare parameters to set to Capture plugin when it is not yet */ ++ /* ready */ ++ if (COMPONENT_IS_READY(record->cap_state) == FALSE) { ++ struct xf_adsp_capture_params *params = &capture->params; ++ ++ /* apply capture parameters */ ++ params->out_rate = fs; ++ params->channel = ch; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ params->dev1 = SRC0; ++ params->dev2 = SSI10; ++ params->dma1 = PDMA_CH00; ++ params->dma2 = PDMA_CH01; ++ ++ /* set volume rate if it is set by user or default volume as */ ++ /* 100% */ ++ if (vol_rate >= 0) ++ params->vol_rate = vol_rate; ++ else ++ params->vol_rate = (1 << 20); ++ ++ /* set sample rate input if it is set by user */ ++ if (in_rate >= 0) ++ params->in_rate = in_rate; ++ ++ /* allocate buffer pool to prepare the execution */ ++ capture->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(capture->buf_pool)) /* PRQA S 306 */ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ capture->buf_pool, i); ++ ++ base->buf_queue++; ++ } ++ ++ /* set parameters to ADSP Capture plugin */ ++ if (xf_adsp_capture_set_params(capture) != 0) ++ return -EINVAL; ++ ++ /* mark Capture ready */ ++ record->cap_state |= XF_HANDLE_READY; ++ ++ /* set parameters for Equalizer if it's used */ ++ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { ++ /* apply Equalizer parameter setting */ ++ equalizer->params.channel = ch; ++ equalizer->params.pcm_width = pcm_width; ++ equalizer->params.rate = fs; ++ ++ /* get equalizer parameter from control interface */ ++ /* data */ ++ snd_adsp_get_eqz_params_from_control( ++ &equalizer->params, ++ &ctr_if->eqz_params[DIRECT_CAPTURE][dai_idx], ++ true); ++ ++ /* set parameters to Equalizer plugin */ ++ if (xf_adsp_equalizer_set_params(equalizer) != 0) ++ return -EINVAL; ++ ++ /* route Capture to Equalizer */ ++ if (xf_adsp_route(capture->handle_id, ++ equalizer->handle_id, ++ XF_BUF_POOL_SIZE, ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ /* mark Equalizer ready */ ++ record->eqz_state |= XF_HANDLE_READY; ++ } ++ ++ /* kick init process by sending a zero buffer length */ ++ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* wait until finishing initialization */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { ++ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ /* send buffer to plugin */ ++ if (xf_adsp_fill_this_buffer( ++ base->handle_id, ++ base->buffer[i], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ } ++ ++ /* wait until all the buffer have been responsed */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ } ++ ++ /* reset hw data position */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize playback function ++ * ++ * \param[out] playback Pointer to playback data ++ * \retval -EINVAL Failed to deinitialize playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if playback has been created already */ ++ if (playback) { ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(playback->rdr_state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process *//* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(playback->base.handle_id, ++ NULL, 0); ++ ++ /* free buffer pool */ /* PRQA S 3200 1 */ ++ xf_adsp_free_mem_pool(playback->renderer->buf_pool); ++ ++ /* destroy Renderer */ ++ if (xf_adsp_renderer_destroy(playback->renderer) != 0) ++ ret = -EINVAL; ++ ++ playback->renderer = NULL; ++ } ++ ++ /* destroy Equalizer if it is used */ ++ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { ++ if (xf_adsp_equalizer_destroy(playback->equalizer)) ++ ret = -EINVAL; ++ ++ playback->equalizer = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(playback->base.hrt_state) == TRUE) ++ hrtimer_cancel(&playback->base.hrtimer); ++ ++ /* free playback data */ ++ kfree(playback); ++ } ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize record function ++ * ++ * \param[out] record Pointer to record data ++ * \retval -EINVAL Failed to deinitialize record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_record_deinit(struct snd_adsp_record *record) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if record has been created already */ ++ if (!record) ++ return ret; ++ ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(record->cap_state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process *//* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(record->base.handle_id, NULL, 0); ++ ++ /* free buffer pool */ /* PRQA S 3200 1 */ ++ xf_adsp_free_mem_pool(record->capture->buf_pool); ++ ++ if (xf_adsp_capture_destroy(record->capture)) ++ ret = -EINVAL; ++ ++ record->capture = NULL; ++ } ++ ++ /* destroy Equalizer if it is used */ ++ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { ++ if (xf_adsp_equalizer_destroy(record->equalizer) != 0) ++ ret = -EINVAL; ++ ++ record->equalizer = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(record->base.hrt_state) == TRUE) ++ hrtimer_cancel(&record->base.hrtimer); ++ ++ /* free record data */ ++ kfree(record); ++ ++ return ret; ++} ++ ++/***************************************************************************** ++ * internal functions to manage TDM playback and TDM record functions ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Initialize TDM playback data ++ * ++ * \param[out] tdm_playback_data Pointer to store TDM playback data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to initialize TDM playback data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_playback_init(struct snd_adsp_tdm_playback **tdm_playback_data, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_tdm_playback *tdm_playback; ++ ++ /* allocate memory for TDM playback data */ ++ tdm_playback = kmalloc(sizeof(*tdm_playback), GFP_KERNEL); ++ ++ if (!tdm_playback) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(tdm_playback, 0, sizeof(struct snd_adsp_tdm_playback)); ++ ++ /* save the TDM playback data */ ++ *tdm_playback_data = tdm_playback; ++ ++ /* set handle state as NULL state */ ++ tdm_playback->state = XF_HANDLE_NULL; ++ tdm_playback->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register TDM renderer component */ ++ if (xf_adsp_tdm_renderer_create(&tdm_playback->tdm_renderer, ++ &rdr_callbacks, ++ (void *)&tdm_playback->base) < 0) ++ return -EINVAL; ++ ++ /* mark TDM renderer component created */ ++ tdm_playback->state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as TDM renderer ID */ ++ tdm_playback->base.handle_id = tdm_playback->tdm_renderer->handle_id; ++ ++ /* init lock */ ++ spin_lock_init(&tdm_playback->base.lock); ++ ++ /* save the substream data */ ++ tdm_playback->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&tdm_playback->base.hrtimer, ++ CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ tdm_playback->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ tdm_playback->base.hrt_state = XF_HANDLE_CREATED; ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Initialize TDM record data ++ * ++ * \param[out] tdm_record_data Pointer to store TDM record data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to initialize TDM record data ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_record_init(struct snd_adsp_tdm_record **tdm_record_data, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_tdm_record *tdm_record; ++ ++ /* allocate memory for TDM record data */ ++ tdm_record = kmalloc(sizeof(*tdm_record), GFP_KERNEL); ++ if (!tdm_record) ++ return -EINVAL; ++ ++ /* init params */ ++ memset(tdm_record, 0, sizeof(struct snd_adsp_tdm_record)); ++ ++ /* save the TDM record data */ ++ *tdm_record_data = tdm_record; ++ ++ /* set handle state as NULL state */ ++ tdm_record->state = XF_HANDLE_NULL; ++ tdm_record->base.hrt_state = XF_HANDLE_NULL; ++ ++ /* register TDM Capture component */ ++ if (xf_adsp_tdm_capture_create(&tdm_record->tdm_capture, ++ &cap_callbacks, ++ (void *)&tdm_record->base) != 0) ++ return -EINVAL; ++ ++ /* mark TDM capture component created */ ++ tdm_record->state = XF_HANDLE_CREATED; ++ ++ /* set target handle ID as TDM capture ID */ ++ tdm_record->base.handle_id = tdm_record->tdm_capture->handle_id; ++ ++ /* init lock */ ++ spin_lock_init(&tdm_record->base.lock); ++ ++ /* save the substream data */ ++ tdm_record->base.substream = substream; ++ ++ /* init high resolution timer for updating hw status */ ++ hrtimer_init(&tdm_record->base.hrtimer, ++ CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ ++ /* PRQA S 0563 1 */ ++ tdm_record->base.hrtimer.function = &snd_adsp_hrtimer_func; ++ tdm_record->base.hrt_state = XF_HANDLE_CREATED; ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare TDM playback function ++ * ++ * \param[out] tdm_playback Pointer to TDM playback data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare TDM playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_playback_prepare(struct snd_adsp_tdm_playback *tdm_playback, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card; ++ struct snd_adsp_control *ctr_if; ++ struct snd_pcm_runtime *runtime; ++ struct xf_adsp_tdm_renderer *tdm_renderer; ++ struct snd_adsp_base_info *base; ++ int i; ++ int pcm_width, ch_mode, fs, frame_size, hw_buffer_size; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ runtime = substream->runtime; ++ tdm_renderer = tdm_playback->tdm_renderer; ++ base = &tdm_playback->base; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ ++ ch_mode = (runtime->channels == 8) ? ++ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; ++ ++ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ ++ if (pcm_width == 16) ++ base->buf_bytes = base->period_bytes; ++ else ++ base->buf_bytes = ((base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = hw_buffer_size; ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ /* it should equal to a period size in bytes */ ++ base->pcm_indirect.hw_queue_size = base->period_bytes; ++ ++ /* prepare parameters to set to TDM playback as it is not ready */ ++ if (COMPONENT_IS_READY(tdm_playback->state) == FALSE) { ++ struct xf_adsp_tdm_renderer_params *params; ++ ++ params = &tdm_renderer->params; ++ ++ /* apply renderer parameters */ ++ params->in_rate = fs; ++ params->ch_mode = ch_mode; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ /* setting Audio device indexes */ ++ params->dma1 = ADMAC_CH00; /* use DMAC for transfer data */ ++ params->dma2 = PDMA_CH03; ++ params->dev1 = SRC1; ++ params->dev2 = SSI30; /* set SSI index to SSI30 */ ++ ++ /* set volume rate if it is set by user or default value as */ ++ /* 100% */ ++ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] >= 0) ++ ? ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] : (1 << 20); ++ ++ /* set output sampling rate if it is set by user */ ++ if (ctr_if->tdm_sample_rate[DIRECT_PLAYBACK] >= 0) ++ params->out_rate = ++ ctr_if->tdm_sample_rate[DIRECT_PLAYBACK]; ++ ++ /* set parameters to ADSP TDM Renderer plugin */ ++ if (xf_adsp_tdm_renderer_set_params(tdm_renderer) != 0) ++ return -EINVAL; ++ ++ /* allocate buffer pool to prepare the execution */ ++ tdm_renderer->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(tdm_renderer->buf_pool)) /* PRQA S 306*/ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ tdm_renderer->buf_pool, i); ++ ++ base->buf_queue++; ++ } ++ ++ /* mark TDM Renderer created */ ++ tdm_playback->state |= XF_HANDLE_READY; ++ ++ /* send zero buffer to plugin to kick init-processing */ ++ memset(base->buffer[0], 0, base->buf_bytes); ++ ++ if (xf_adsp_empty_this_buffer(base->handle_id, base->buffer[0], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* wait until all the buffer have been consummed */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ /* reset HW index */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Prepare TDM record function ++ * ++ * \param[out] tdm_record Pointer to TDM record data ++ * \param[in] substream Pointer to substream data ++ * \retval -EINVAL Failed to prepare TDM record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_tdm_record_prepare(struct snd_adsp_tdm_record *tdm_record, ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_card *adsp_card = ++ snd_adsp_get_drvdata_from_substream(substream); ++ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct xf_adsp_tdm_capture *tdm_capture = tdm_record->tdm_capture; ++ struct snd_adsp_base_info *base = &tdm_record->base; ++ int i; ++ int pcm_width, ch_mode, fs, frame_size; ++ ++ /* runtime parameter */ ++ fs = runtime->rate; ++ ++ ch_mode = (runtime->channels == 8) ? ++ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; ++ ++ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; ++ frame_size = runtime->period_size; ++ ++ /* get number of bytes in a period */ ++ base->period_bytes = snd_pcm_lib_period_bytes(substream); ++ base->buf_bytes = (pcm_width == 16) ? ++ base->period_bytes : ((base->period_bytes * ++ BYTES_PER_SAMPLE(S24_3LE)) / ++ BYTES_PER_SAMPLE(S24_LE)); ++ ++ /* pcm indirect configuration */ ++ base->pcm_indirect.hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ /* total size of allocated buffers */ ++ base->pcm_indirect.hw_queue_size = base->period_bytes * ++ XF_BUF_POOL_SIZE; ++ ++ /* prepare parameters to set to TDM Capture as it is not yet ready */ ++ if (COMPONENT_IS_READY(tdm_record->state) == FALSE) { ++ struct xf_adsp_tdm_capture_params *params; ++ ++ params = &tdm_capture->params; ++ ++ /* apply capture parameters */ ++ params->out_rate = fs; ++ params->ch_mode = ch_mode; ++ params->pcm_width = pcm_width; ++ params->frame_size = frame_size; ++ ++ /* setting Audio device indexes */ ++ params->dma1 = PDMA_CH00; ++ params->dma2 = PDMA_CH01; ++ params->dev1 = SRC0; ++ params->dev2 = SSI40; /* set input device is SSI40 */ ++ ++ /* set volume rate if it is set by user or default value as */ ++ /* 100% */ ++ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_CAPTURE] >= 0) ++ ? ctr_if->tdm_vol_rate[DIRECT_CAPTURE] : (1 << 20); ++ ++ /* set input rate if it is set by user */ ++ if (ctr_if->tdm_sample_rate[DIRECT_CAPTURE] >= 0) { ++ params->in_rate = ++ ctr_if->tdm_sample_rate[DIRECT_CAPTURE]; ++ } ++ ++ /* allocate buffer pool to prepare the execution */ ++ tdm_capture->buf_pool = xf_adsp_allocate_mem_pool( ++ XF_BUF_POOL_SIZE, base->buf_bytes); ++ ++ if (IS_ERR(tdm_capture->buf_pool)) /* PRQA S 306 */ ++ return -EINVAL; ++ ++ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { ++ base->buffer[i] = xf_adsp_get_data_from_pool( ++ tdm_capture->buf_pool, i); ++ ++ base->buf_queue++; ++ } ++ ++ /* set parameters to ADSP TDM Capture plugin */ ++ if (xf_adsp_tdm_capture_set_params(tdm_capture) != 0) ++ return -EINVAL; ++ ++ /* mark TDM Capture ready */ ++ tdm_record->state |= XF_HANDLE_READY; ++ ++ /* kick init process by sending a zero buffer length */ ++ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* wait until finishing initialization */ ++ while (base->buf_queue != XF_BUF_POOL_SIZE) { ++ schedule_timeout_interruptible(2); ++ if (signal_pending(current)) ++ break; ++ ++ /* check the error from initialization */ ++ if (base->runtime_err) ++ return -EINVAL; ++ } ++ ++ /* reset hw data position */ ++ base->hw_idx = 0; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize TDM playback function ++ * ++ * \param[out] tdm_playback Pointer to TDM playback data ++ * \retval -EINVAL Failed to deinitialize TDM playback function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_tdm_playback_deinit(struct snd_adsp_tdm_playback *tdm_playback) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if TDM playback has been created */ ++ if (!tdm_playback) ++ return ret; ++ ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(tdm_playback->state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process */ ++ /* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(tdm_playback->base.handle_id, ++ NULL, 0); ++ ++ /* free buffer pool *//* PRQA S 3200 2 */ ++ xf_adsp_free_mem_pool(tdm_playback->tdm_renderer->buf_pool); ++ ++ /* destroy TDM Renderer component */ ++ if (xf_adsp_tdm_renderer_destroy( ++ tdm_playback->tdm_renderer) != 0) ++ ret = -EINVAL; ++ ++ tdm_playback->tdm_renderer = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(tdm_playback->base.hrt_state) == TRUE) ++ hrtimer_cancel(&tdm_playback->base.hrtimer); ++ ++ /* free playback data */ ++ kfree(tdm_playback); ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Deinitialize TDM record function ++ * ++ * \param[out] tdm_record Pointer to TDM record data ++ * \retval -EINVAL Failed to deinitialize TDM record function ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record) ++{ ++ int ret = 0; ++ ++ /* perform de-initialization if TDM record has been created already */ ++ if (!tdm_record) ++ return ret; ++ ++ /* perform completion process */ ++ if (COMPONENT_IS_CREATED(tdm_record->state) == TRUE) { ++ /* send buffer with zero length to plugin for */ ++ /* completion process */ ++ /* PRQA S 3200 2 */ ++ xf_adsp_empty_this_buffer(tdm_record->base.handle_id, NULL, 0); ++ ++ /* free buffer pool *//* PRQA S 3200 2 */ ++ xf_adsp_free_mem_pool(tdm_record->tdm_capture->buf_pool); ++ ++ /* destroy TDM Capture component */ ++ if (xf_adsp_tdm_capture_destroy(tdm_record->tdm_capture) != 0) ++ ret = -EINVAL; ++ ++ tdm_record->tdm_capture = NULL; ++ } ++ ++ /* canncel timer interrupt */ ++ if (COMPONENT_IS_CREATED(tdm_record->base.hrt_state) == TRUE) ++ hrtimer_cancel(&tdm_record->base.hrtimer); ++ ++ /* free record data */ ++ kfree(tdm_record); ++ ++ return ret; ++} ++ ++/***************************************************************************** ++ * callback functions of ADSP ALSA driver ++ * ***************************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Open a playback/TDM playback or record/TDM record stream ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_open(struct snd_pcm_substream *substream) ++{ ++ /* get ADSP soundcard and CPU DAI index */ ++ struct snd_adsp_card *adsp_card; ++ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ struct snd_adsp_control *ctr_if; ++ ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ ctr_if = &adsp_card->ctr_if; ++ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ /* register data for playback/record functions */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* perform playback initialization */ ++ if (snd_adsp_playback_init( ++ &adsp_card->playback[dai_idx], ++ ctr_if->eqz_switch[DIRECT_PLAYBACK][dai_idx], ++ substream) < 0) { ++ /* perform playback de-initialization when */ ++ /* the initialization fails */ ++ snd_adsp_playback_deinit( ++ adsp_card->playback[dai_idx]); ++ ++ adsp_card->playback[dai_idx] = NULL; ++ return -EINVAL; ++ } ++ } else { ++ /* perform record initialization */ ++ if (snd_adsp_record_init( ++ &adsp_card->record[dai_idx], ++ ctr_if->eqz_switch[DIRECT_CAPTURE][dai_idx], ++ substream) < 0) { ++ /* perform record de-initialization when the */ ++ /* initialization fails */ ++ snd_adsp_record_deinit( ++ adsp_card->record[dai_idx]); ++ ++ adsp_card->record[dai_idx] = NULL; ++ return -EINVAL; ++ } ++ } ++ ++ /* save the hardware parameters */ ++ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_hw); ++ ++ /* each period has a frame size */ ++ snd_pcm_hw_constraint_single(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, ++ FRAME_SIZE); ++ } else { ++ /* register data for TDM playback/record functions */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* perform TDM playback initialization */ ++ if (snd_adsp_tdm_playback_init( ++ &adsp_card->tdm_playback, ++ substream) < 0) { ++ /* perform TDM playback de-initialization */ ++ /* when the initialization fails */ ++ snd_adsp_tdm_playback_deinit( ++ adsp_card->tdm_playback); ++ ++ adsp_card->tdm_playback = NULL; ++ return -EINVAL; ++ } ++ } else { ++ /* perform TDM record initialization */ ++ if (snd_adsp_tdm_record_init(&adsp_card->tdm_record, ++ substream) < 0) { ++ /* perform TDM record de-initialization */ ++ /* when the initialization fails */ ++ snd_adsp_tdm_record_deinit( ++ adsp_card->tdm_record); ++ ++ adsp_card->tdm_record = NULL; ++ return -EINVAL; ++ } ++ } ++ ++ /* save the hardware parameters */ ++ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_tdm_hw); ++ ++ /* each period has a frame size */ ++ snd_pcm_hw_constraint_single(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, ++ TDM_FRAME_SIZE); ++ } ++ ++ snd_pcm_hw_constraint_integer(substream->runtime, ++ SNDRV_PCM_HW_PARAM_PERIODS); ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Close a playback/TDM playback or record/TDM record stream ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_close(struct snd_pcm_substream *substream) ++{ ++ /* get ADSP soundcard and CPU DAI index */ ++ struct snd_adsp_card *adsp_card = ++ snd_adsp_get_drvdata_from_substream(substream); ++ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ int err = 0; ++ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ /* destroy Renderer/Capture or Equalizer (if used) */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (snd_adsp_playback_deinit( ++ adsp_card->playback[dai_idx]) < 0) ++ err = -EINVAL; ++ ++ adsp_card->playback[dai_idx] = NULL; ++ } else { ++ if (snd_adsp_record_deinit( ++ adsp_card->record[dai_idx]) < 0) ++ err = -EINVAL; ++ ++ adsp_card->record[dai_idx] = NULL; ++ } ++ } else { ++ /* destroy TDM Renderer/TDM Capture */ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (snd_adsp_tdm_playback_deinit( ++ adsp_card->tdm_playback) < 0) ++ err = -EINVAL; ++ ++ adsp_card->tdm_playback = NULL; ++ } else { ++ if (snd_adsp_tdm_record_deinit( ++ adsp_card->tdm_record) < 0) ++ err = -EINVAL; ++ ++ adsp_card->tdm_record = NULL; ++ } ++ } ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ * \brief Allocate ALSA buffer and calculate expire time of hr timer ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -ENOMEM Cannot allocate ALSA buffer ++ *****************************************************************************/ ++static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params) ++{ ++ struct snd_adsp_base_info *base; ++ int err = 0; ++ ++ base = snd_adsp_get_base_from_substream(substream); ++ ++ /* set expire time of hrtimer, this value should be time for */ ++ /* transfer a frame */ ++ base->ktime = ns_to_ktime((1000000000 / params_rate(hw_params)) * ++ params_period_size(hw_params)); ++ ++ err = snd_pcm_lib_malloc_pages(substream, ++ params_buffer_bytes(hw_params)); ++ ++ /* reset DMA buffer area */ ++ memset(substream->runtime->dma_area, 0, substream->runtime->dma_bytes); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ * \brief Free the allocated ALSA buffer ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Cannot deallocate buffer ++ *****************************************************************************/ ++static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++/** ************************************************************************** ++ * \brief Prepare playback/TDM playback or record/TDM record function ++ * before transferring data ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ /* get ADSP soundcard and CPU DAI index */ ++ struct snd_adsp_card * ++ adsp_card = snd_adsp_get_drvdata_from_substream(substream); ++ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); ++ int err = 0; ++ ++ if (dai_idx == RDR_DAI_IDX0 || dai_idx == RDR_DAI_IDX1 || ++ dai_idx == RDR_DAI_IDX2 || dai_idx == RDR_DAI_IDX3) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ /* get playback prepared to execute */ ++ err = snd_adsp_playback_prepare( ++ adsp_card->playback[dai_idx], substream); ++ else ++ /* get record prepared to execute */ ++ err = snd_adsp_record_prepare( ++ adsp_card->record[dai_idx], substream); ++ } else { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ /* get TDM playback prepared to execute */ ++ err = snd_adsp_tdm_playback_prepare( ++ adsp_card->tdm_playback, substream); ++ else ++ /* get TDM record prepared to execute */ ++ err = snd_adsp_tdm_record_prepare( ++ adsp_card->tdm_record, substream); ++ } ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ * \brief Trigger playback/TDM playback or record/TDM record stream ++ * to go to next phase ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ ++ switch (idx) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ /* start high-resolution timer */ ++ hrtimer_start(&base->hrtimer, base->ktime, HRTIMER_MODE_REL); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ int buf_queue = 0; ++ ++ /* get current available buffer */ ++ spin_lock(&base->lock); ++ buf_queue = base->buf_queue; ++ spin_unlock(&base->lock); ++ ++ /* send all available buffer to plugin to */ ++ /* get data */ ++ for (; buf_queue > 0; buf_queue--) { ++ if (xf_adsp_fill_this_buffer( ++ base->handle_id, ++ base->buffer[base->buf_idx], ++ base->buf_bytes) != 0) ++ return -EINVAL; ++ ++ spin_lock(&base->lock); ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ base->buf_idx++; ++ ++ if (base->buf_idx >= XF_BUF_POOL_SIZE) ++ base->buf_idx = 0; ++ } ++ } ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Return HW data position ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval position HW data position ++ *****************************************************************************/ ++static snd_pcm_uframes_t ++snd_adsp_pcm_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ unsigned int hw_idx, hw_buffer_size; ++ snd_pcm_uframes_t pointer; ++ ++ /* convert hw index to correct as submitted bytes */ ++ spin_lock(&base->lock); ++ hw_idx = (base->hw_idx / base->buf_bytes) * base->period_bytes; ++ spin_unlock(&base->lock); ++ ++ hw_buffer_size = base->pcm_indirect.hw_buffer_size; ++ ++ if (hw_idx >= hw_buffer_size) { ++ spin_lock(&base->lock); ++ ++ base->hw_idx -= (hw_buffer_size / base->period_bytes) * ++ base->buf_bytes; ++ ++ spin_unlock(&base->lock); ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ pointer = snd_pcm_indirect_playback_pointer(substream, ++ &base->pcm_indirect, ++ hw_idx); ++ else ++ pointer = snd_pcm_indirect_capture_pointer(substream, ++ &base->pcm_indirect, ++ hw_idx); ++ ++ return pointer; ++} ++ ++/** ************************************************************************** ++ * \brief Call read/write process to transfer data ++ * ++ * \param[in] substream Pointer to substream object ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ ++ if (base->runtime_err) ++ return -EINVAL; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ snd_pcm_indirect_playback_transfer(substream, ++ &base->pcm_indirect, ++ snd_adsp_pcm_transfer); ++ else ++ snd_pcm_indirect_capture_transfer(substream, ++ &base->pcm_indirect, ++ snd_adsp_pcm_transfer); ++ ++ return 0; ++} ++ ++/** *************************************************************************** ++ * \brief Copy data from source buffer to destination buffer ++ * ++ * \params[in] dst Destination buffer pointer ++ * \params[out] src Source buffer pointer ++ * \params[in] dst_size Destination buffer size in byte ++ * \params[in] src_size Source buffer size in byte ++ * \retval None ++ *****************************************************************************/ ++static inline void ++snd_adsp_copy_data(void *dst, void *src, int dst_size, int src_size) ++{ ++ unsigned char *data_dst = dst; ++ unsigned char *data_src = src; ++ int i; ++ ++ if (dst_size == src_size) { ++ /* src and dst bufs are same size, does not need to convert */ ++ memcpy(data_dst, data_src, dst_size); ++ ++ } else if (dst_size < src_size) { ++ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_3LE)); ++ i += BYTES_PER_SAMPLE(S24_3LE)) { ++ *(u32 *)data_dst = *(u32 *)data_src; ++ ++ data_dst += BYTES_PER_SAMPLE(S24_3LE); ++ data_src += BYTES_PER_SAMPLE(S24_LE); ++ } ++ ++ /* copy a S24_3LE sample from S24_LE sample */ ++ data_dst[0] = data_src[0]; ++ data_dst[1] = data_src[1]; ++ data_dst[2] = data_src[2]; ++ ++ } else { ++ unsigned int tmp; ++ ++ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_LE)); ++ i += BYTES_PER_SAMPLE(S24_LE)) { ++ tmp = *(u32 *)data_src; ++ *(u32 *)data_dst = tmp & 0x0FFFFFF; ++ ++ data_dst += BYTES_PER_SAMPLE(S24_LE); ++ data_src += BYTES_PER_SAMPLE(S24_3LE); ++ } ++ ++ /* copy a S24_LE sample from S24_3LE sample */ ++ data_dst[0] = data_src[0]; ++ data_dst[1] = data_src[1]; ++ data_dst[2] = data_src[2]; ++ data_dst[3] = 0; ++ } ++} ++ ++/** ************************************************************************** ++ * \brief Transfer data process between ALSA buffer and ADSP buffer ++ * ++ * \param[in] substream Pointer to substream object ++ * \param[in] rec Pointer to indirect PCM data ++ * \param[in] bytes Number of byte need to be transferred ++ * \retval None ++ *****************************************************************************/ ++static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, ++ size_t bytes) ++{ ++ struct snd_adsp_base_info * ++ base = snd_adsp_get_base_from_substream(substream); ++ int direct = substream->stream; ++ int trans_bytes = bytes; ++ int buf_bytes, period_bytes; ++ void *dma_buf, *data_buff; ++ ++ /* get the DMA buffer pointer */ ++ dma_buf = (void *)(substream->runtime->dma_area + rec->sw_data); ++ ++ /* get information from base */ ++ buf_bytes = base->buf_bytes; ++ period_bytes = base->period_bytes; ++ ++ /* make sure the available buffer and transfer size - TBD */ ++ while (trans_bytes > 0) { ++ spin_lock(&base->lock); ++ if (base->buf_queue > 0 && trans_bytes >= period_bytes) { ++ base->buf_queue--; ++ spin_unlock(&base->lock); ++ ++ /* get the buffer pointer from stream */ ++ data_buff = base->buffer[base->buf_idx]; ++ ++ if (direct == SNDRV_PCM_STREAM_PLAYBACK) { ++ /* copy data from user *//* PRQA S 3200 2 */ ++ snd_adsp_copy_data(data_buff, dma_buf, ++ buf_bytes, period_bytes); ++ ++ /* send buffer to plugin */ ++ if (xf_adsp_empty_this_buffer(base->handle_id, ++ data_buff, ++ buf_bytes) < 0) ++ base->runtime_err = TRUE; ++ } else { ++ /* copy data to user *//* PRQA S 3200 2 */ ++ snd_adsp_copy_data(dma_buf, data_buff, ++ period_bytes, buf_bytes); ++ ++ /* send buffer to plugin */ ++ if (xf_adsp_fill_this_buffer(base->handle_id, ++ data_buff, ++ buf_bytes) < 0) ++ base->runtime_err = TRUE; ++ } ++ ++ base->buf_idx++; ++ if (base->buf_idx >= XF_BUF_POOL_SIZE) ++ base->buf_idx = 0; ++ } else { ++ spin_unlock(&base->lock); ++ break; ++ } ++ ++ trans_bytes -= period_bytes; ++ } ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Volume control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of volume control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = -1; ++ uinfo->value.integer.max = 799; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get volume value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to volume value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; ++ int handle_state, handle_id; ++ int volume, cmd_idx, direction; ++ unsigned int index; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* determine command index, direction, handle state, handle ID */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ handle_id = ++ adsp_card->playback[index]->renderer->handle_id; ++ } ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ handle_id = ++ adsp_card->record[index]->capture->handle_id; ++ } ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) { ++ handle_state = adsp_card->tdm_playback->state; ++ ++ handle_id = ++ adsp_card->tdm_playback->tdm_renderer->handle_id; ++ } ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) { ++ handle_state = adsp_card->tdm_record->state; ++ ++ handle_id = ++ adsp_card->tdm_record->tdm_capture->handle_id; ++ } ++ } ++ } ++ ++ /* get the volume's value */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* get the volume's value from the plugin */ ++ if (xf_adsp_get_param(handle_id, cmd_idx, &volume) != 0) ++ return -EINVAL; ++ ++ /* check the value after getting it and adjust it */ ++ ucontrol->value.integer.value[0] = (volume == 0xFFFFFFFF) ? ++ (-1) : (volume * VOLUME_SCALE) >> 20; ++ } else { ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ ucontrol->value.integer.value[0] = ++ (ctr_if->vol_rate[direction][index] * ++ VOLUME_SCALE) >> 20; ++ else ++ ucontrol->value.integer.value[0] = ++ (ctr_if->tdm_vol_rate[direction] * ++ VOLUME_SCALE) >> 20; ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set volume value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to volume value ++ * \retval 1 Volume change ++ * \retval 0 Volume does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1*/ ++static int ++snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; ++ int volume; ++ int ret; ++ int handle_state, handle_id, cmd_idx, volume_get; ++ int direction; ++ unsigned int index; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state and handle ID */ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* get the value to set */ ++ if (ucontrol->value.integer.value[0] == -1) { ++ volume = 0xFFFFFFFF; ++ } else { ++ /* round up the value if needed */ ++ volume = (ucontrol->value.integer.value[0] * (1 << 20)) / ++ VOLUME_SCALE; ++ ++ if ((ucontrol->value.integer.value[0] * (1 << 20)) > ++ (VOLUME_SCALE * volume)) ++ volume += 1; ++ } ++ ++ /* determine command index, direction, handle state, handle ID */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ handle_id = ++ adsp_card->playback[index]->renderer->handle_id; ++ } ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ handle_id = ++ adsp_card->record[index]->capture->handle_id; ++ } ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) { ++ handle_state = adsp_card->tdm_playback->state; ++ ++ handle_id = ++ adsp_card->tdm_playback->tdm_renderer->handle_id; ++ } ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) { ++ handle_state = adsp_card->tdm_record->state; ++ ++ handle_id = ++ adsp_card->tdm_record->tdm_capture->handle_id; ++ } ++ } ++ } ++ ++ /* set volume to plugin */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* TDM does not support set volume in runtime state */ ++ if (kcontrol->id.name[0] == PREFIX_OF_TDM_CTR_NAME) ++ return -EINVAL; ++ ++ /* apply set volume value to ADSP from user setting */ ++ if (xf_adsp_set_param(handle_id, cmd_idx, volume) != 0) ++ return -EINVAL; ++ ++ /* get volume from ADSP after setting to confirm */ ++ if (xf_adsp_get_param(handle_id, cmd_idx, &volume_get) != 0) ++ return -EINVAL; ++ ++ /* check if the value has changed */ ++ ret = (volume_get == volume) ? 1 : 0; ++ } else { ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ ctr_if->vol_rate[direction][index] = volume; ++ else ++ ctr_if->tdm_vol_rate[direction] = volume; ++ ++ ret = 1; ++ } ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Sample Rate Converter control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of sample rate ++ * converter control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = -1; ++ uinfo->value.integer.max = 48000; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get sample rate value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to sample rate value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int *rate; ++ int handle_id, handle_state, cmd_idx, direction; ++ unsigned int index; ++ ++ rate = (int *)&ucontrol->value.integer.value[0]; /* PRQA S 310 */ ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state and handle ID */ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* determine command, direction, handle state, handle ID */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ handle_id = ++ adsp_card->playback[index]->renderer->handle_id; ++ } ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ handle_id = ++ adsp_card->record[index]->capture->handle_id; ++ } ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) { ++ handle_state = adsp_card->tdm_playback->state; ++ ++ handle_id = ++ adsp_card->tdm_playback->tdm_renderer->handle_id; ++ } ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) { ++ handle_state = adsp_card->tdm_record->state; ++ ++ handle_id = ++ adsp_card->tdm_record->tdm_capture->handle_id; ++ } ++ } ++ } ++ ++ /* get parameter from plugin */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ if (xf_adsp_get_param(handle_id, cmd_idx, rate) != 0) ++ return -EINVAL; ++ } else { ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ *rate = adsp_card->ctr_if.sample_rate[direction][index]; ++ else ++ *rate = adsp_card->ctr_if.tdm_sample_rate[direction]; ++ } ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set sample rate value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to sample rate value ++ * \retval 1 Sample rate change ++ * \retval 0 Sample rate does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1 */ ++static int ++snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ unsigned int index; ++ int rate; ++ int handle_state, cmd_idx, direction; ++ int ret = 1; ++ ++ rate = (int)ucontrol->value.integer.value[0]; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* determine command, direction and handle state */ ++ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { ++ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { ++ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->record[index]) ++ handle_state = adsp_card->record[index]->cap_state; ++ ++ } else { ++ if (kcontrol->id.name[3] == TDM_PLAYBACK) { ++ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ direction = DIRECT_PLAYBACK; ++ ++ if (adsp_card->tdm_playback) ++ handle_state = adsp_card->tdm_playback->state; ++ ++ } else { ++ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ direction = DIRECT_CAPTURE; ++ ++ if (adsp_card->tdm_record) ++ handle_state = adsp_card->tdm_record->state; ++ } ++ } ++ ++ /* get the value to set */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) ++ return -EINVAL; ++ ++ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) ++ adsp_card->ctr_if.sample_rate[direction][index] = rate; ++ else ++ adsp_card->ctr_if.tdm_sample_rate[direction] = rate; ++ ++ ret = 1; ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Equalizer control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of Equalizer control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = MAX_EQZ_PARAM_NUMBER; ++ uinfo->value.integer.min = -1; ++ uinfo->value.integer.max = 0x7fffffff; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get equalizer parameters value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer parameters value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int handle_state, direction; ++ int i, j, filter_index; ++ unsigned int index; ++ struct xf_adsp_equalizer *equalizer; ++ struct xf_adsp_equalizer_params *eqz_params; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determin direction of stream */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* set handle state as NULL state, handle ID, equalizer pointer */ ++ handle_state = XF_HANDLE_NULL; ++ equalizer = NULL; ++ ++ /* get component's state */ ++ if (direction == DIRECT_PLAYBACK) { ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->eqz_state; ++ equalizer = adsp_card->playback[index]->equalizer; ++ } ++ } else { ++ if (adsp_card->record[index]) { ++ handle_state = adsp_card->record[index]->eqz_state; ++ equalizer = adsp_card->record[index]->equalizer; ++ } ++ } ++ ++ /* perform parameters' values getting */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* get equalizer's parameters */ ++ if (xf_adsp_equalizer_get_params(equalizer) != 0) ++ return -EINVAL; ++ ++ eqz_params = &equalizer->params; ++ } else { ++ eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; ++ } ++ ++ /* get equalizer type: PARAMETRIC or GRAPHIC */ ++ ucontrol->value.integer.value[0] = eqz_params->eqz_type; ++ ++ /* get parameters' value from Equalizer plugin */ ++ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { ++ for (i = 0, filter_index = 1; ++ filter_index <= XA_REL_EQZ_FILTER_NUM; ++ i++, filter_index++) { ++ /* get filter index */ ++ ucontrol->value.integer.value[(i * 6) + 1] = ++ filter_index; ++ ++ /* get frequency centre */ ++ ucontrol->value.integer.value[(i * 6) + 2] = ++ eqz_params->p_coef.fc[i]; ++ ++ /* get bandwidth */ ++ ucontrol->value.integer.value[(i * 6) + 3] = ++ eqz_params->p_coef.band_width[i]; ++ ++ /* get filter type */ ++ ucontrol->value.integer.value[(i * 6) + 4] = ++ eqz_params->p_coef.type[i]; ++ ++ /* get gain base */ ++ ucontrol->value.integer.value[(i * 6) + 5] = ++ eqz_params->p_coef.gain_base[i]; ++ ++ /* get gain */ ++ ucontrol->value.integer.value[(i * 6) + 6] = ++ eqz_params->p_coef.gain[i]; ++ } ++ } else { ++ for (i = 0, filter_index = 1; ++ filter_index <= XA_REL_EQZ_GRAPHIC_BAND_NUM; ++ i++, filter_index++) { ++ /* get band index */ ++ ucontrol->value.integer.value[(i * 2) + 1] = ++ filter_index; ++ ++ /* get graphic gain */ ++ ucontrol->value.integer.value[(i * 2) + 2] = ++ eqz_params->g_coef.gain_g[i]; ++ } ++ ++ j = (i * 2) + 1; ++ ++ /* make the rest of values silent */ ++ while (j < MAX_EQZ_PARAM_NUMBER) { ++ ucontrol->value.integer.value[j] = -1; ++ j++; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set equalizer parameters value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer parameters value ++ * \retval 1 Equalizer parameters change ++ * \retval 0 Equalizer parameters does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1*/ ++static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int handle_state, direction, filter_idx; ++ int i; ++ int index; ++ struct xf_adsp_equalizer_params *eqz_params = NULL; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determine the direction */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* get the handle state */ ++ if (direction == DIRECT_PLAYBACK) { ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->eqz_state; ++ } else { ++ if (adsp_card->record[index]) ++ handle_state = adsp_card->record[index]->eqz_state; ++ } ++ ++ /* perform equalizer's parameters setting */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) ++ return -EINVAL; ++ ++ /* PRQA S 310 1*/ ++ eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; ++ ++ i = 0; ++ /* PRQA S 3440 1*/ ++ eqz_params->eqz_type = ucontrol->value.integer.value[i]; ++ i++; ++ filter_idx = 0; ++ ++ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { ++ while (i < MAX_EQZ_PARAM_NUMBER) { ++ /* get index filter */ ++ /* PRQA S 3440*/ ++ filter_idx = ucontrol->value.integer.value[i]; ++ i++; ++ ++ /* valid index filter is range */ ++ /* (1 to XA_REL_EQZ_FILTER_NUM) */ ++ if (filter_idx >= 1 && ++ filter_idx <= XA_REL_EQZ_FILTER_NUM) { ++ /* PRQA S 3440 5*/ ++ eqz_params->p_coef.fc[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.band_width[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.type[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.gain_base[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ eqz_params->p_coef.gain[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ ++ i++; ++ } ++ /* index filter = -1 means that user */ ++ /* does not set this filter */ ++ else if (filter_idx == -1 || filter_idx == 0) { ++ i += 5; ++ } else { ++ return -EINVAL; ++ } ++ } ++ } else if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_GRAPHIC) { ++ while (i < ((XA_REL_EQZ_GRAPHIC_BAND_NUM * 2) + 1)) { ++ /*get index filter */ ++ /* PRQA S 3440 */ ++ filter_idx = ucontrol->value.integer.value[i++]; ++ ++ if (filter_idx >= 1 && ++ filter_idx <= XA_REL_EQZ_GRAPHIC_BAND_NUM) { ++ eqz_params->g_coef.gain_g[filter_idx - 1] = ++ ucontrol->value.integer.value[i]; ++ i++; ++ ++ } else if (filter_idx == -1 || filter_idx == 0) { ++ i += 1; ++ } else { ++ return -EINVAL; ++ } ++ } ++ } else { ++ return -EINVAL; ++ } ++ ++ return 1; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Equalizer Switch control ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of Equalizer ++ * Switch control ++ * \retval 0 Success ++ *****************************************************************************/ ++static int snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 1; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get equalizer switch value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer switch value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int ++snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int direction; ++ unsigned int index; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determine the direction */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* get the Equalizer switch status */ ++ ucontrol->value.integer.value[0] = ++ adsp_card->ctr_if.eqz_switch[direction][index]; ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set equalizer switch value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to equalizer switch value ++ * \retval 1 Equalizer switch change ++ * \retval 0 Equalizer switch does not change ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++/* PRQA S 3673 1 */ ++static int ++snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int eqz_switch; ++ int handle_state, direction; ++ unsigned int index; ++ int ret = 0; ++ ++ eqz_switch = ucontrol->value.integer.value[0]; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ /* determine the direction */ ++ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? ++ DIRECT_PLAYBACK : DIRECT_CAPTURE; ++ ++ /* set handle state as NULL state */ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* determine handle state */ ++ if (direction == DIRECT_PLAYBACK) { ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->rdr_state; ++ } else { ++ if (adsp_card->record[index]) ++ handle_state = adsp_card->record[index]->cap_state; ++ } ++ ++ /* set the status of Equalizer */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* runtime setting is not supported */ ++ ret = -EINVAL; ++ } else { ++ adsp_card->ctr_if.eqz_switch[direction][index] = eqz_switch; ++ ret = 1; ++ } ++ ++ return ret; ++} ++ ++/** ************************************************************************** ++ * \brief Get info of Renderer output channel ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] uinfo Pointer to info structure of Renderer output channel ++ * \retval 0 Success ++ *****************************************************************************/ ++static int ++snd_adsp_control_rdr_out_channel_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = MONAURAL; ++ uinfo->value.integer.max = STEREO; ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Get Renderer output channel's value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to Renderer output channel value ++ * \retval 0 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int ++snd_adsp_control_rdr_out_channel_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ int rdr_out_ch; ++ unsigned int index; ++ int handle_state, handle_id; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ handle_state = XF_HANDLE_NULL; ++ handle_id = -1; ++ ++ /* determine handle state and handle ID */ ++ if (adsp_card->playback[index]) { ++ handle_state = adsp_card->playback[index]->rdr_state; ++ handle_id = adsp_card->playback[index]->renderer->handle_id; ++ } ++ ++ /* get Renderer output channel's value */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) { ++ /* get Renderer output channel's value from Renderer plugin */ ++ if (xf_adsp_get_param(handle_id, ++ XA_RDR_CONFIG_PARAM_OUT_CHANNELS, ++ &rdr_out_ch) != 0) { ++ return -EINVAL; ++ } ++ ++ ucontrol->value.integer.value[0] = rdr_out_ch; ++ } else { ++ ucontrol->value.integer.value[0] = ++ adsp_card->ctr_if.rdr_out_ch[index]; ++ } ++ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Set Renderer output channel's value ++ * ++ * \param[in] kcontrol Pointer to control instance ++ * \param[in] ucontrol Pointer to Renderer output channel value ++ * \retval 1 Success ++ * \retval -EINVAL Error ++ *****************************************************************************/ ++static int ++snd_adsp_control_rdr_out_channel_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); ++ unsigned int index; ++ int handle_state; ++ int ret = 1; ++ ++ /* get the index */ ++ index = kcontrol->id.index; ++ ++ handle_state = XF_HANDLE_NULL; ++ ++ /* determine handle state and handle ID */ ++ if (adsp_card->playback[index]) ++ handle_state = adsp_card->playback[index]->rdr_state; ++ ++ /* get Renderer output channel's value */ ++ if (COMPONENT_IS_READY(handle_state) == TRUE) ++ /* not support runtime setting */ ++ ret = -EINVAL; ++ else ++ adsp_card->ctr_if.rdr_out_ch[index] = ++ ucontrol->value.integer.value[0]; ++ ++ return ret; ++} ++ ++/** control interface for playback's volume rate */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_playback_volume_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ } ++}; ++ ++/** control interface for Capture's volume rate */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_capture_volume_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++ } ++}; ++ ++/** control interface for playback's output sample rate */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_playback_sample_rate_out_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ } ++}; ++ ++/** control interface for Capture's input sample rate */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_capture_sample_rate_in_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++ } ++}; ++ ++/** control interface for Equalizer parameters in playback */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_playback_equalizer_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ } ++}; ++ ++/** control interface for Equalizer parameters in record */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_capture_equalizer_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_EQZ_CTR_NAME, ++ .info = &snd_adsp_control_eqz_info, ++ .get = &snd_adsp_control_eqz_get, ++ .put = &snd_adsp_control_eqz_put ++ } ++}; ++ ++/** control interface for Equalizer usage in playback */ ++/* PRQA S 3218 */ ++static struct snd_kcontrol_new ++snd_adsp_playback_equalizer_switch_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ } ++}; ++ ++/** control interface for Equalizer usage in record */ ++/* PRQA S 3218 1*/ ++static struct snd_kcontrol_new ++snd_adsp_capture_equalizer_switch_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX1, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX2, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX3, ++ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, ++ .info = &snd_adsp_control_eqz_switch_info, ++ .get = &snd_adsp_control_eqz_switch_get, ++ .put = &snd_adsp_control_eqz_switch_put ++ } ++}; ++ ++/** control interface for playback's output channel */ ++static struct snd_kcontrol_new ++snd_adsp_playback_out_channel_control[MAX_DAI_IDX - 1] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .index = RDR_DAI_IDX0, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = RDR_DAI_IDX1, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = RDR_DAI_IDX2, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .index = RDR_DAI_IDX3, ++ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, ++ .info = &snd_adsp_control_rdr_out_channel_info, ++ .get = &snd_adsp_control_rdr_out_channel_get, ++ .put = &snd_adsp_control_rdr_out_channel_put ++ } ++}; ++ ++/** control interface for TDM playback's volume rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_playback_volume_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_PLAYBACK_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++}; ++ ++/** control interface for TDM capture's volume rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_capture_volume_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_CAPTURE_VOLUME_CTR_NAME, ++ .info = &snd_adsp_control_volume_info, ++ .get = &snd_adsp_control_volume_get, ++ .put = &snd_adsp_control_volume_put ++}; ++ ++/** control interface for TDM playback's output sample rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_playback_sample_rate_out_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_PLAYBACK_OUT_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++}; ++ ++/** control interface for TDM capture's input sample rate */ ++static struct snd_kcontrol_new snd_adsp_tdm_capture_sample_rate_in_control = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ ++ .name = TDM_CAPTURE_IN_RATE_CTR_NAME, ++ .info = &snd_adsp_control_sample_rate_info, ++ .get = &snd_adsp_control_sample_rate_get, ++ .put = &snd_adsp_control_sample_rate_put ++}; ++ ++/** PCM callback function of the sound card */ ++static struct snd_pcm_ops snd_adsp_pcm_ops = { ++ .open = &snd_adsp_pcm_open, /* PRQA S 1053 10 */ ++ .close = &snd_adsp_pcm_close, ++ .ioctl = &snd_pcm_lib_ioctl, ++ .hw_params = &snd_adsp_pcm_hw_params, ++ .hw_free = &snd_adsp_pcm_hw_free, ++ .prepare = &snd_adsp_pcm_prepare, ++ .trigger = &snd_adsp_pcm_trigger, ++ .pointer = &snd_adsp_pcm_pointer, ++ .ack = &snd_adsp_pcm_ack ++}; ++ ++/******************************************************************* ++ * Internal functions ++ * ****************************************************************/ ++ ++/** ************************************************************************** ++ * \brief Process information get from control structure ++ * ++ * \param[in] eqz_params Equalizer parameters object ++ * \param[in] eqz_ctr_params Equalizer parameters stored in control object ++ * \param[in] flag Indicate playback or capture stream ++ *****************************************************************************/ ++static void snd_adsp_get_eqz_params_from_control( ++ struct xf_adsp_equalizer_params *eqz_params, ++ struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag) ++{ ++ int filter_idx; ++ ++ if (flag) { ++ if (eqz_ctr_params->eqz_type >= 0) ++ eqz_params->eqz_type = eqz_ctr_params->eqz_type; ++ ++ for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; ++ filter_idx++) { ++ if (eqz_ctr_params->p_coef.fc[filter_idx] >= 0) ++ eqz_params->p_coef.fc[filter_idx] = ++ eqz_ctr_params->p_coef.fc[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.band_width[filter_idx] >= 0) ++ eqz_params->p_coef.band_width[filter_idx] = ++ eqz_ctr_params->p_coef.band_width[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.type[filter_idx] >= 0) ++ eqz_params->p_coef.type[filter_idx] = ++ eqz_ctr_params->p_coef.type[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.gain_base[filter_idx] >= 0) ++ eqz_params->p_coef.gain_base[filter_idx] = ++ eqz_ctr_params->p_coef.gain_base[filter_idx]; ++ ++ if (eqz_ctr_params->p_coef.gain[filter_idx] >= 0) ++ eqz_params->p_coef.gain[filter_idx] = ++ eqz_ctr_params->p_coef.gain[filter_idx]; ++ } ++ for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; ++ filter_idx++) { ++ if (eqz_ctr_params->g_coef.gain_g[filter_idx] >= 0) ++ eqz_params->g_coef.gain_g[filter_idx] = ++ eqz_ctr_params->g_coef.gain_g[filter_idx]; ++ } ++ } else { ++ memcpy(eqz_ctr_params, eqz_params, sizeof(*eqz_params)); ++ } ++} ++ ++/******************************************************************* ++ * ALSA ADSP Platform driver interface ++ * ****************************************************************/ ++ ++/** **************************************************************************** ++ * \brief Register control interface and preallocate ALSA buffer ++ * ++ * \param[in] runtime Pointer to runtime PCM data ++ * \retval 0 Success ++ * \retval -EINVAL Cannot register control interface ++ ******************************************************************************/ ++static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime) ++{ ++ int i = 0, err = 0; ++ int id; ++ struct snd_card *card; ++ struct snd_adsp_card *adsp_card; ++ int alsa_buf_sz = 0; ++ ++ /* get sound card data */ ++ card = runtime->card->snd_card; ++ ++ /* get driver data */ ++ adsp_card = snd_soc_dai_get_drvdata(runtime->cpu_dai); ++ ++ /* get the ID of CPU DAI */ ++ id = runtime->cpu_dai->id; ++ ++ /* register control interfaces */ ++ if (id == RDR_DAI_IDX0 || id == RDR_DAI_IDX1 || ++ id == RDR_DAI_IDX2 || id == RDR_DAI_IDX3) { ++ struct snd_kcontrol *kctl[RDR_CONTROL_NUM]; ++ void *rdr_ctr[RDR_CONTROL_NUM] = { ++ &snd_adsp_playback_volume_control[id], /* PRQA S 1031 */ ++ &snd_adsp_capture_volume_control[id], ++ &snd_adsp_playback_sample_rate_out_control[id], ++ &snd_adsp_capture_sample_rate_in_control[id], ++ &snd_adsp_playback_equalizer_control[id], ++ &snd_adsp_capture_equalizer_control[id], ++ &snd_adsp_playback_equalizer_switch_control[id], ++ &snd_adsp_capture_equalizer_switch_control[id], ++ &snd_adsp_playback_out_channel_control[id] ++ }; ++ ++ /* add basic control instance */ ++ for (i = 0; i < RDR_CONTROL_NUM; i++) { ++ kctl[i] = snd_ctl_new1(rdr_ctr[i], adsp_card); ++ err = snd_ctl_add(card, kctl[i]); ++ if (err < 0) ++ return -EINVAL; ++ } ++ ++ /* assign ALSA buffer size */ ++ alsa_buf_sz = MAX_BUFFER_BYTES; ++ ++ /* enable MIX feature from the 2nd playback/record stream */ ++ if (adsp_card->ctr_if.mix_usage == MIX_UNUSED) ++ adsp_card->ctr_if.mix_usage = FIRST_RUN; ++ else if (adsp_card->ctr_if.mix_usage == FIRST_RUN) ++ adsp_card->ctr_if.mix_usage = SECOND_RUN; ++ ++ } else { ++ struct snd_kcontrol *kctl[TDM_CONTROL_NUM]; ++ void *tdm_ctr[TDM_CONTROL_NUM] = { ++ &snd_adsp_tdm_playback_volume_control, ++ &snd_adsp_tdm_playback_sample_rate_out_control, ++ &snd_adsp_tdm_capture_volume_control, ++ &snd_adsp_tdm_capture_sample_rate_in_control ++ }; ++ ++ /* add basic control instances */ ++ for (i = 0; i < TDM_CONTROL_NUM; i++) { ++ kctl[i] = snd_ctl_new1(tdm_ctr[i], adsp_card); ++ err = snd_ctl_add(card, kctl[i]); ++ if (err < 0) ++ return -EINVAL; ++ } ++ ++ /* assign ALSA buffer size */ ++ alsa_buf_sz = TDM_MAX_BUFFER_BYTES; ++ } ++ ++ return snd_pcm_lib_preallocate_pages_for_all(runtime->pcm, ++ SNDRV_DMA_TYPE_CONTINUOUS, ++ snd_dma_continuous_data(GFP_KERNEL), ++ alsa_buf_sz, alsa_buf_sz); ++} ++ ++/* **************************************************************************** ++ * ALSA ADSP DAI register ++ * ***************************************************************************/ ++ ++/** callback function of platform driver */ ++static struct snd_soc_platform_driver snd_adsp_platform = { ++ .pcm_new = &snd_adsp_pcm_new, /* PRQA S 1053 *//* PRQA S 0674 */ ++ .ops = &snd_adsp_pcm_ops, ++}; ++ ++/** component information of driver */ ++static const struct snd_soc_component_driver snd_adsp_component = { ++ .name = "snd_adsp", /* PRQA S 1053 */ ++}; ++ ++/** DAI information of ADSP ALSA driver */ ++static struct snd_soc_dai_driver snd_adsp_dai[MAX_DAI_IDX] = { ++ { ++ /* PRQA S 1053 */ ++ .id = RDR_DAI_IDX0, ++ .name = "adsp-dai.0", ++ .playback.stream_name = "Playback0", ++ .capture.stream_name = "Capture0", ++ }, ++ { ++ .id = RDR_DAI_IDX1, ++ .name = "adsp-dai.1", ++ .playback.stream_name = "Playback1", ++ .capture.stream_name = "Capture1", ++ }, ++ { ++ .id = RDR_DAI_IDX2, ++ .name = "adsp-dai.2", ++ .playback.stream_name = "Playback2", ++ .capture.stream_name = "Capture2", ++ }, ++ { ++ .id = RDR_DAI_IDX3, ++ .name = "adsp-dai.3", ++ .playback.stream_name = "Playback3", ++ .capture.stream_name = "Capture3", ++ }, ++ { ++ .id = TDM_DAI_IDX, ++ .name = "adsp-tdm-dai", ++ .playback.stream_name = "TDM Playback", ++ .capture.stream_name = "TDM Capture", ++ } ++}; ++ ++/** *************************************************************************** ++ * \brief Register platform driver and ADSP ALSA sound card ++ * ++ * \param[in] pdev Pointer to platform driver data ++ * \retval 0 Success ++ * \retval -ENOMEM Cannot allocate driver's data ++ * \retval -EINVAL Cannot register platform driver or sound card ++ ****************************************************************************/ ++static int snd_adsp_probe(struct platform_device *pdev) ++{ ++ struct snd_adsp_card *adsp_card; ++ int i; ++ ++ /* allocate a card data structure */ ++ adsp_card = kmalloc(sizeof(*adsp_card), GFP_KERNEL); ++ if (!adsp_card) ++ return -ENOMEM; ++ ++ /* init parameters */ ++ memset(adsp_card, 0, sizeof(*adsp_card)); /* PRQA S 3200 */ ++ ++ /* PRQA S 3200 1*/ ++ memset(&adsp_card->ctr_if, -1, sizeof(struct snd_adsp_control)); ++ ++ /* disable Equalizer for all streams */ ++ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { ++ adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][i] = 0; ++ adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][i] = 0; ++ } ++ ++ /* disable MIX function for all */ ++ adsp_card->ctr_if.mix_usage = MIX_UNUSED; ++ ++ /* save driver data */ ++ dev_set_drvdata(&pdev->dev, adsp_card); ++ ++ /* register platform device */ ++ if (snd_soc_register_platform(&pdev->dev, &snd_adsp_platform) < 0) { ++ snd_soc_unregister_platform(&pdev->dev); ++ return -EINVAL; ++ } ++ ++ /* fill format information of sound DAI driver for Rdr/Cap function */ ++ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { ++ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].playback.channels_min = MIN_CHANNEL; ++ snd_adsp_dai[i].playback.channels_max = MAX_CHANNEL; ++ ++ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].capture.channels_min = MIN_CHANNEL; ++ snd_adsp_dai[i].capture.channels_max = MAX_CHANNEL; ++ } ++ ++ /* fill format information of sound DAI driver for TDM function */ ++ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].playback.channels_min = TDM_MIN_CHANNEL; ++ snd_adsp_dai[i].playback.channels_max = TDM_MAX_CHANNEL; ++ ++ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; ++ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; ++ snd_adsp_dai[i].capture.channels_min = TDM_MIN_CHANNEL; ++ snd_adsp_dai[i].capture.channels_max = TDM_MAX_CHANNEL; ++ ++ /* register CPU dai */ ++ if (snd_soc_register_component(&pdev->dev, &snd_adsp_component, ++ snd_adsp_dai, ++ ARRAY_SIZE(snd_adsp_dai)) < 0) { ++ snd_soc_unregister_platform(&pdev->dev); ++ return -EINVAL; ++ } ++ ++ dev_info(&pdev->dev, "probed\n"); ++ ++ /* success */ ++ return 0; ++} ++ ++/** ************************************************************************** ++ * \brief Unregister platform driver and ADSP ALSA sound card ++ * ++ * \param[in] pdev Pointer platform driver data ++ * \retval 0 Success ++ * \retval -EINVAL Invalid driver's data ++ *****************************************************************************/ ++static int snd_adsp_remove(struct platform_device *pdev) ++{ ++ /* get ADSP sound card data */ ++ struct snd_adsp_card *adsp_card = dev_get_drvdata(&pdev->dev); ++ ++ if (!adsp_card) ++ return -ENODEV; ++ ++ /* release the ADSP sound card */ ++ kfree(adsp_card); ++ ++ /* unregister platform driver */ ++ snd_soc_unregister_component(&pdev->dev); ++ snd_soc_unregister_platform(&pdev->dev); ++ ++ /* success */ ++ return 0; ++} ++ ++/** ADSP ALSA driver information */ ++static const struct of_device_id snd_adsp_id[] = { ++ { .compatible = "renesas,rcar_adsp_sound_gen3", }, /* PRQA S 1053 */ ++}; ++MODULE_DEVICE_TABLE(of, snd_adsp_id); ++ ++/** platform driver of ADSP ALSA sound card */ ++static struct platform_driver snd_adsp_driver = { ++ .driver = { /* PRQA S 1053 */ ++ .name = "rcar_adsp_sound", ++ .of_match_table = snd_adsp_id, ++ }, ++ .probe = snd_adsp_probe, ++ .remove = snd_adsp_remove, ++}; ++module_platform_driver(snd_adsp_driver); /* PRQA S 0651 */ ++ ++MODULE_AUTHOR("Renesas AudioDSP"); ++MODULE_DESCRIPTION("Platform driver for ADSP"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:ADSP-PCM-AUDIO"); +diff --git a/sound/soc/adsp/xf-adsp-base.c b/sound/soc/adsp/xf-adsp-base.c +new file mode 100644 +index 000000000000..3ad944583800 +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-base.c +@@ -0,0 +1,2259 @@ ++/** *************************************************************************** ++ *\file xf-adsp-base.c ++ *\brief Source file for ADSP Base Control layer ++ *\addtogroup ADSP Driver ++ ****************************************************************************** ++ *\date Oct. 21, 2017 ++ *\author Renesas Electronics Corporation ++ ****************************************************************************** ++ *\par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#include ++#include ++#include ++ ++#include "xf-adsp-base.h" ++ ++#define XF_AUX_POOL_SIZE (16) /**< size of auxiliary pool*/ ++#define XF_AUX_POOL_MSG_LENGTH (256) /**< size of auxiliary buffer */ ++ ++#define XF_PROXY_ALIGN (64) /**< proxy alignment */ ++ ++/** \def XF_ALIGNED(size) ++ * Get properly aligned buffer length ++ */ ++#define XF_ALIGNED(size)\ ++((((size) + XF_PROXY_ALIGN) - 1) & ~(XF_PROXY_ALIGN - 1)) /* PRQA S 3453 */ ++ ++#ifndef offset_of ++/** \def offset_of(type, member) ++ * Return the offset of member in type structuer in byte ++ */ ++#define offset_of(type, member) \ ++ ((int)(long int)&(((const type *)(0))->member)) /* PRQA S 3453 */ ++#endif ++ ++/************************************************* ++ * Variable and and function declaration ++ * **********************************************/ ++ ++/** ADSP base control data */ ++static struct xf_adsp_base *base; ++ ++/* function declaration */ ++static int xf_adsp_base_register_handle(void *private_data, ++ struct xf_callback_func *cb, ++ int comp_id); ++static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id); ++static int xf_adsp_base_free_handle(int handle_id); ++static void xf_adsp_base_init_handle(void); ++static int xf_adsp_base_get_valid_handle(void); ++static int xf_send_and_receive(struct xf_message *msg); ++static int xf_response_thread(void *data); ++static void xf_buffer_put(struct xf_buffer *buffer); ++static u32 xf_buffer_length(struct xf_buffer *b); ++static struct xf_buffer *xf_buffer_get(struct xf_pool *pool); ++static void *xf_buffer_data(struct xf_buffer *b); ++static int xf_adsp_unregister(int comp_id); ++static int xf_adsp_register(char *name, int *comp_id); ++ ++/************************************************* ++ * Helper function to process pool data ++ * **********************************************/ ++ ++/** *********************************************************** ++ * \brief get buffer from given pool ++ * ++ * \param[in] pool Data pool address ++ * \retval b Pointer to buffer address in pool ++ **************************************************************/ ++static struct xf_buffer *xf_buffer_get(struct xf_pool *pool) ++{ ++ struct xf_buffer *b; ++ ++ b = pool->free; ++ if (b) { ++ pool->free = b->link.next; ++ b->link.pool = pool; ++ } ++ return b; ++} ++ ++/*********************************************************** ++ *\brief return buffer back to pool ++ * ++ *\param[in] buffer Pointer to the buffer data ++ ************************************************************/ ++static void xf_buffer_put(struct xf_buffer *buffer) ++{ ++ struct xf_pool *pool = buffer->link.pool; ++ ++ buffer->link.next = pool->free; ++ pool->free = buffer; ++} ++ ++/*********************************************************** ++ *\brief get the address of the given buffer data ++ * ++ *\param[in] b Pointer to the buffer data ++ *\retval address Address of buffer data ++ ************************************************************/ ++static void *xf_buffer_data(struct xf_buffer *b) ++{ ++ return b->address; ++} ++ ++/************************************************************ ++ *\brief get the length of the given buffer data ++ * ++ *\param[in] b Pointer to the buffer data ++ *\retval length Size of buffer data ++ ************************************************************/ ++static u32 xf_buffer_length(struct xf_buffer *b) /* PRQA S 3673 */ ++{ ++ return b->link.pool->length; ++} ++ ++/************************************************************ ++ *\brief set data to the given command message ++ * ++ *\param[out] m Pointer to the command message ++ *\param[in] id Message ID ++ *\param[in] opcode Message opcode ++ *\param[in] length Message length ++ *\param[in] buf Pointer to the buffer data ++ *\param[in] next Pointer to the next message ++ *\retval m Pointer to the command message ++ ************************************************************/ ++static inline struct xf_message * ++xf_create_msg(struct xf_message *m, u32 id, u32 opcode, u32 length, void *buf, ++ struct xf_message *next) ++{ ++ if (m) { ++ m->id = id; ++ m->opcode = opcode; ++ m->length = length; ++ m->buffer = buf; ++ m->next = next; ++ } ++ ++ return m; ++} ++ ++/***************************************************************** ++ *\brief synchronous send and wait for response message from proxy ++ * ++ *\param[in] msg Pointer to the command message ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ ****************************************************************/ ++static int xf_send_and_receive(struct xf_message *msg) ++{ ++ int err; ++ int opcode = msg->opcode; ++ ++ /* reset the base flag */ ++ spin_lock(&base->lock); ++ base->base_flag = FALSE; ++ spin_unlock(&base->lock); ++ ++ err = base->cmd.send(base->client, (void *)msg); ++ if (err != 0) ++ return err; ++ ++ /* sleep and wait for the response wake up event */ ++ if (wait_event_interruptible(base->base_wait, ++ base->base_flag || base->err_flag)) { ++ return -EINVAL; ++ } ++ ++ if (base->err_flag != 0) { ++ spin_lock(&base->lock); ++ base->err_flag = FALSE; ++ spin_unlock(&base->lock); ++ return -EINVAL; ++ } ++ ++ /* save the response message */ ++ /* PRQA S 3200 */ ++ memcpy(msg, &base->base_msg, sizeof(struct xf_message)); ++ ++ /* check if the reponsed message is right */ ++ if (msg->opcode != opcode) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/************************************************************* ++ *\brief send a message to proxy ++ * ++ *\param[in] msg Pointer to the command message ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++static inline int xf_send(struct xf_message *msg) ++{ ++ return base->cmd.send(base->client, (void *)msg); ++} ++ ++/** *********************************************************** ++ *\brief receive message from proxy ++ * ++ *\param[in] msg Pointer to store the response message ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++static inline int xf_receive(struct xf_message *msg) ++{ ++ /* do not wait here */ ++ return base->cmd.recv(base->client, (void *)msg); ++} ++ ++/** *********************************************************** ++ *\brief thread for receive response data ++ **************************************************************/ ++static int xf_response_thread(void *data) ++{ ++ struct xf_message msg; ++ struct xf_handle *handle; ++ int id; ++ ++ /* set polling to wait the response message */ ++ spin_lock(&base->lock); ++ base->wait_flag = FALSE; ++ spin_unlock(&base->lock); ++ ++ while (!kthread_should_stop()) { ++ if (base->cmd.poll(base->client, &base->wait_flag) != 0) ++ continue; ++ ++ if (xf_receive(&msg) != 0) ++ continue; ++ ++ /* get the handle id */ ++ id = XF_AP_CLIENT(msg.id); ++ ++ /* check the destination of the response message */ ++ if (id == 0) { ++ /* message is from base control */ ++ /* PRQA S 3200 1*/ ++ memcpy(&base->base_msg, &msg, ++ sizeof(struct xf_message)); ++ ++ spin_lock(&base->lock); ++ base->base_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ wake_up(&base->base_wait); ++ continue; ++ } ++ ++ /* get handle data */ ++ handle = xf_adsp_base_get_handle(id); ++ ++ if (handle == 0) ++ continue; ++ ++ switch (msg.opcode) { ++ case XF_EMPTY_THIS_BUFFER: /* PRQA S 0594 */ ++ handle->cb->empty_buf_done(handle->private_data, ++ msg.opcode, ++ msg.length, ++ msg.buffer); ++ break; ++ case XF_FILL_THIS_BUFFER: /* PRQA S 0594 */ ++ handle->cb->fill_buf_done(handle->private_data, ++ msg.opcode, ++ msg.length, ++ msg.buffer); ++ break; ++ case XF_SET_PARAM: /* PRQA S 0594 4 */ ++ case XF_GET_PARAM: ++ case XF_ROUTE: ++ case XF_UNROUTE: ++ /* message is from base control */ ++ memcpy(&base->base_msg, &msg, ++ sizeof(struct xf_message)); /* PRQA S 3200 */ ++ ++ spin_lock(&base->lock); ++ base->base_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ wake_up(&base->base_wait); ++ break; ++ default: ++ /* error has occurred */ ++ handle->cb->event_handler(handle->private_data); ++ ++ xf_adsp_base_free_handle(id); /* PRQA S 3200 */ ++ ++ spin_lock(&base->lock); ++ base->err_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ wake_up(&base->base_wait); ++ break; ++ } ++ } ++ ++ pr_info("ADSP base thread was exited\n"); ++ ++ do_exit(0); ++ return 0; ++} ++ ++/************************************************************* ++ * \brief register component to ADSP ++ * ++ * \param[in] name Name string of component ++ * \param[out] comp_id Store the registered component ID ++ * \retval 0 Success ++ * \retval -EINVAL Failed ++ **************************************************************/ ++static int xf_adsp_register(char *name, int *comp_id) /* PRQA S 3673 */ ++{ ++ struct xf_message msg; ++ struct xf_buffer *b = xf_buffer_get(base->aux_pool); ++ int err = 0; ++ ++ msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); ++ msg.opcode = XF_REGISTER; ++ msg.length = strlen(name) + 1; ++ msg.buffer = xf_buffer_data(b); ++ ++ /* copy identify name of ADSP component */ ++ if (msg.length <= xf_buffer_length(b)) ++ strncpy(msg.buffer, name, msg.length); /* PRQA S 3200 */ ++ else ++ strncpy(msg.buffer, name, xf_buffer_length(b));/* PRQA S 3200 */ ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the registered component ID */ ++ *comp_id = XF_MSG_SRC(msg.id); ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ * \brief unregister component from ADSP ++ * \param[in] comp_id Registered component ID ++ * \retval 0 Success ++ * \retval -EINVAL Failed ++ **************************************************************/ ++static int xf_adsp_unregister(int comp_id) ++{ ++ struct xf_message msg; ++ ++ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), comp_id), ++ XF_UNREGISTER, 0, NULL, NULL); /* PRQA S 3200 */ ++ ++ return xf_send_and_receive(&msg); ++} ++ ++/*************************************************************** ++ * APIs for ADSP component helper ++ * ************************************************************/ ++/** *********************************************************** ++ * \brief allocate memory pool from shared memory ++ * \param[in] pool_size Number of buffer need to allocate ++ * \param[in] buf_length Size of each buffer in bytes ++ * \retval pool Pointer to allocated pool ++ * \retval -EINVAL Invalid base data ++ * \retval -ENOMEM Out of memory resource ++ **************************************************************/ ++struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length) ++{ ++ void *data; ++ u32 number; ++ struct xf_buffer *b; ++ struct xf_message msg; ++ struct xf_pool *pool; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return ERR_PTR(-EINVAL); /* PRQA S 0306 */ ++ ++ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), ++ XF_ALLOC, ++ buf_length * pool_size, NULL, NULL); /* PRQA S 3200 */ ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ ++ ++ /* PRQA S 0306 1 */ ++ pool = kmalloc(offset_of(struct xf_pool, buffer) + ++ (pool_size * sizeof(struct xf_buffer)), GFP_KERNEL); ++ ++ if (!pool) ++ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ ++ ++ pool->length = buf_length; ++ pool->number = pool_size; ++ pool->p = msg.buffer; ++ ++ number = pool_size; ++ for (pool->free = b = &pool->buffer[0], data = pool->p; ++ number > 0; number--, b++) { /* PRQA S 2462,3418,0489 */ ++ /* set address of the buffer */ ++ b->address = data; ++ ++ /* fill buffer into free list */ ++ if (number == 1) ++ b->link.next = NULL; ++ else ++ b->link.next = b + 1; /* PRQA S 0489 */ ++ ++ /* advance data pointer in contigous buffer */ ++ data += buf_length; /* PRQA S 0550 */ ++ } ++ ++ return pool; ++} ++ ++/** *********************************************************** ++ *\brief return memory to shared memory ++ *\param[in] pool Data pool address ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or pool data ++ **************************************************************/ ++int xf_adsp_free_mem_pool(struct xf_pool *pool) ++{ ++ struct xf_message msg; ++ ++ /* check the sane ADSP base pool data*/ ++ if (!base || !pool) ++ return -EINVAL; ++ ++ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), ++ XF_FREE, pool->number * pool->length, ++ pool->p, NULL); /* PRQA S 3200 */ ++ ++ xf_send_and_receive(&msg); /* PRQA S 3200 */ ++ ++ kfree(pool); ++ ++ return 0; ++} ++ ++/** *********************************************************** ++ *\brief get buffer from given pool ++ * ++ *\param[in] pool Data pool address ++ *\param[in] index Buffer index ++ *\retval b Pointer to buffer address in pool ++ *\retval -EINVAL Invalid pool or index ++ **************************************************************/ ++char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index) ++{ ++ struct xf_buffer *buf[XF_BUF_POOL_SIZE] = {0}; ++ char *data; ++ int i; ++ ++ /* check the sane pool data*/ ++ if (!pool) ++ return ERR_PTR(-EINVAL); /* PRQA S 306 */ ++ ++ /* check the index is valid */ ++ if (index > (pool->number - 1)) ++ return ERR_PTR(-EINVAL); /* PRQA S 306 */ ++ ++ /* get buffer from pool */ ++ for (i = 0; i <= index; i++) ++ buf[i] = xf_buffer_get(pool); ++ ++ /* get data from buffer */ ++ data = xf_buffer_data(buf[index]); ++ ++ /* return buffer to pool */ ++ for (i = index; i >= 0; i--) ++ xf_buffer_put(buf[i]); ++ ++ return data; ++} ++ ++/** *********************************************************** ++ *\brief send empty this buffer command to ADSP framework ++ * ++ *\param[in] handle_id ID of the registered handle ++ *\param[in] buffer Pointer to data buffer ++ *\param[in] length Size of buffer in bytes ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length) ++{ ++ struct xf_message msg; ++ struct xf_handle *handle; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ /* submit message to port 0 of component */ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_EMPTY_THIS_BUFFER, length, buffer, NULL); ++ ++ xf_send(&msg); /* PRQA S 3200 */ ++ ++ return 0; ++} ++ ++/** *********************************************************** ++ *\brief send fill this buffer command to ADSP framework ++ * ++ *\param[in] handle_id ID of the registered handle ++ *\param[in] buffer Pointer to data buffer ++ *\param[in] length Size of buffer in bytes ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length) ++{ ++ struct xf_message msg; ++ struct xf_handle *handle; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ /* submit message to port 1 of component */ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 1)), ++ XF_FILL_THIS_BUFFER, length, buffer, NULL); ++ ++ xf_send(&msg); /* PRQA S 3200 */ ++ ++ return 0; ++} ++ ++/** *********************************************************** ++ *\brief route data between two registered ADSP plugins ++ * ++ *\param[in] src_handle_id Handle ID of source plugin ++ *\param[in] dst_handle_id Handle ID of sink plugin ++ *\param[in] buf_cnt Number of buffer in tunnel ++ *\param[in] buf_size Size of each buffer in tunnel ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int ++xf_adsp_route(int src_handle_id, int dst_handle_id, int buf_cnt, int buf_size) ++{ ++ struct xf_route_port_msg *route_msg; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ struct xf_handle *dst_handle, *src_handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ /* get handle data */ ++ dst_handle = xf_adsp_base_get_handle(dst_handle_id); ++ src_handle = xf_adsp_base_get_handle(src_handle_id); ++ ++ if (!dst_handle || !src_handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ route_msg = xf_buffer_data(b); ++ ++ /* route information */ ++ route_msg->dst = __XF_PORT_SPEC2(dst_handle->comp_id, 0); ++ route_msg->alloc_align = 4; ++ route_msg->alloc_number = buf_cnt; ++ route_msg->alloc_size = buf_size; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, src_handle_id), ++ __XF_PORT_SPEC2(src_handle->comp_id, 1)), ++ XF_ROUTE, sizeof(*route_msg), route_msg, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief set a single parameter ++ * ++ *\param[in] handle_id ID of registered handle ++ *\param[in] index Sub-command index of parameter ++ *\param[in] value the setting value ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_set_param(int handle_id, int index, int value) ++{ ++ struct xf_message msg; ++ struct xf_buffer *b; ++ struct xf_set_param_msg *msg_params; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ msg_params->item[0].id = index; ++ msg_params->item[0].value = value; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(1), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get a single parameter ++ * ++ *\param[in] handle_id ID of registered handle ++ *\param[in] index Sub-command index of parameter ++ *\param[out] value Store the getting value ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_get_param(int handle_id, int index, int *value) ++{ ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base and value data */ ++ if (!base || !value) ++ return -EINVAL; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ msg_params->c.id[0] = index; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(1), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ *value = msg_params->r.value[0]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/*************************************************** ++ * APIs for ADSP base control ++ * ************************************************/ ++ ++/** *********************************************************** ++ *\brief initialize ADSP base's instance ++ * ++ *\retval 0 Success ++ *\retval -EINVAL ADSP base's instance has been initialized ++ *\retval -ENOMEM Cannot allocate memory for ADSP base ++ *\retval -EBUSY Cannot register client to proxy ++ **************************************************************/ ++int xf_adsp_base_create(struct xf_adsp_base_cmd *cmd) ++{ ++ int err = 0; ++ ++ if (base != 0) ++ return -EINVAL; ++ ++ if (!cmd || !cmd->recv || !cmd->send || !cmd->poll || ++ !cmd->client_register || !cmd->client_unregister) ++ return -EINVAL; ++ ++ base = kmalloc(sizeof(*base), GFP_KERNEL); ++ if (!base) ++ return -ENOMEM; ++ ++ memset(base, 0, sizeof(struct xf_adsp_base)); /* PRQA S 3200 */ ++ ++ /* store the proxy command */ ++ memcpy(&base->cmd, cmd, sizeof(struct xf_adsp_base_cmd)); ++ ++ /* create client to connect from proxy driver */ ++ err = base->cmd.client_register(&base->client); ++ if (err != 0) ++ goto err3; /* PRQA S 2001 */ ++ ++ /* initialize waiting queue */ ++ init_waitqueue_head(&base->base_wait); ++ ++ /* initialize handle */ ++ xf_adsp_base_init_handle(); ++ ++ /* create thread to get the responsed message from proxy */ ++ base->rsp_thread = kthread_run(&xf_response_thread, ++ (void *)base, "adsp base"); ++ ++ if (base->rsp_thread != 0) { ++ pr_info("ADSP base thread has been started.\n"); ++ } else { ++ pr_info("Failed in create base thread\n"); ++ err = -ENOMEM; ++ goto err2; /* PRQA S 2001 */ ++ } ++ ++ /* allocate auxiliary pool for component usage */ ++ base->aux_pool = xf_adsp_allocate_mem_pool( ++ XF_AUX_POOL_SIZE, ++ XF_ALIGNED(XF_AUX_POOL_MSG_LENGTH)); ++ ++ if (IS_ERR(base->aux_pool)) { /* PRQA S 306 */ ++ err = -ENOMEM; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ pr_info("ADSP base was created\n"); ++ return 0; ++ ++err1: ++ /* cancel the waitting queue */ ++ spin_lock(&base->lock); ++ base->wait_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ /* stop thread inadvance */ ++ kthread_stop(base->rsp_thread); ++ ++err2: ++ base->cmd.client_unregister(base->client); ++ ++err3: ++ kfree(base); ++ base = NULL; ++ ++ return err; ++} ++EXPORT_SYMBOL(xf_adsp_base_create); /* PRQA S 0651 */ ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP base's instance ++ * ++ *\retval 0 Success ++ *\retval -EINVAL Invalid ADSP base's instance ++ **************************************************************/ ++int xf_adsp_base_destroy(void) ++{ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ /* free auxiliary pool to shared memory */ ++ xf_adsp_free_mem_pool(base->aux_pool); /* PRQA S 3200 */ ++ ++ /* cancel wait the response message, go to stop process */ ++ spin_lock(&base->lock); ++ base->wait_flag = TRUE; ++ spin_unlock(&base->lock); ++ ++ /* stop response thread */ ++ kthread_stop(base->rsp_thread); ++ ++ /* unregister client */ ++ base->cmd.client_unregister(base->client); ++ ++ kfree(base); ++ base = NULL; ++ ++ pr_info("ADSP base was destroyed\n"); ++ return 0; ++} ++EXPORT_SYMBOL(xf_adsp_base_destroy); /* PRQA S 0651 */ ++ ++/** *********************************************************** ++ * \brief initialize handle instance ++ **************************************************************/ ++static inline void xf_adsp_base_init_handle(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_HANDLE; i++) ++ base->handle[i] = NULL; ++} ++ ++/** *********************************************************** ++ *\brief get the next available handle ID for register ++ * ++ *\retval -1 Unavailable handle ID ++ *\retval 0 to 255 Available handle ID ++ **************************************************************/ ++static inline int xf_adsp_base_get_valid_handle(void) ++{ ++ int id = -1; ++ int i; ++ ++ for (i = 0; i < MAX_HANDLE; i++) { ++ /* get the id of the first available handler */ ++ if (!base->handle[i]) { ++ id = i; ++ break; ++ } ++ } ++ ++ return id; ++} ++ ++/** *********************************************************** ++ *\brief register a handle instance for component usage ++ * ++ *\param[in] private_data Private data of this component ++ *\param[in] cb Callback function ++ *\param[in] comp_id ID of register component ++ *\retval id ID of registered handle ++ *\retval -EINVAL Cannot get the handle instance ++ *\retval -ENOMEM Cannot allocate handle memory ++ **************************************************************/ ++static int xf_adsp_base_register_handle(void *private_data, ++ struct xf_callback_func *cb, ++ int comp_id) ++{ ++ struct xf_handle *handle; ++ int id; ++ ++ /* get the next handle id */ ++ id = xf_adsp_base_get_valid_handle(); ++ ++ /* check available handle in base */ ++ if (id < 0) ++ return -EINVAL; ++ ++ /* allocate handle data */ ++ handle = kmalloc(sizeof(*handle), GFP_KERNEL); ++ if (!handle) ++ return -ENOMEM; ++ ++ /* save handle data */ ++ handle->private_data = private_data; ++ handle->cb = cb; ++ handle->comp_id = comp_id; ++ ++ /* save the hanle data */ ++ base->handle[id] = handle; ++ ++ /* return the id numbering in base handle */ ++ return (id + 1); ++} ++ ++/** *********************************************************** ++ *\brief get handle instance from handle ID ++ * ++ *\param[in] handle_id ID of registered handle ++ *\retval handle Pointer to handle instance ++ **************************************************************/ ++static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id) ++{ ++ return base->handle[handle_id - 1]; ++} ++ ++/** *********************************************************** ++ *\brief free the registered handle instance ++ * ++ *\param[in] handle_id ID of registered handle ++ *\retval 0 Success ++ *\retval -EINVAL Invalid handle ID ++ **************************************************************/ ++static int xf_adsp_base_free_handle(int handle_id) ++{ ++ if (handle_id < 1 || handle_id > MAX_HANDLE) ++ return -EINVAL; ++ ++ kfree(base->handle[handle_id - 1]); ++ base->handle[handle_id - 1] = NULL; ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for Renderer component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP Renderer parameters ++ * ++ *\param[in] renderer Pointer to Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_renderer_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !renderer) ++ return -EINVAL; ++ ++ params = &renderer->params; ++ ++ /* get Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_CHANNELS; ++ msg_params->item[i++].value = params->channel; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; ++ msg_params->item[i++].value = params->out_channel; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_MIX_CONTROL; ++ msg_params->item[i++].value = params->mix_ctrl; ++ ++ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_STATE; ++ msg_params->item[i++].value = params->state; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP Renderer parameters ++ * ++ *\param[in] renderer Pointer to Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 */ ++int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer) ++{ ++ struct xf_adsp_renderer_params *rdr_params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !renderer) ++ return -EINVAL; ++ ++ rdr_params = &renderer->params; ++ ++ /* get Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 13 1*/ ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_CHANNELS; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_MIX_CONTROL; ++ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_STATE; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ rdr_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ ++ rdr_params->channel = msg_params->r.value[i++]; ++ rdr_params->pcm_width = msg_params->r.value[i++]; ++ rdr_params->frame_size = msg_params->r.value[i++]; ++ rdr_params->dev1 = msg_params->r.value[i++]; ++ rdr_params->dev2 = msg_params->r.value[i++]; ++ rdr_params->dma1 = msg_params->r.value[i++]; ++ rdr_params->dma2 = msg_params->r.value[i++]; ++ rdr_params->out_rate = msg_params->r.value[i++]; ++ rdr_params->vol_rate = msg_params->r.value[i++]; ++ rdr_params->out_channel = msg_params->r.value[i++]; ++ rdr_params->mix_ctrl = msg_params->r.value[i++]; ++ rdr_params->state = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create Renderer component ++ * ++ *\param[in,out] renderer Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Renderer instance ++ *****************************************************************************/ ++int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_renderer *rdr; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ rdr = kmalloc(sizeof(*rdr), GFP_KERNEL); ++ if (!rdr) ++ return -ENOMEM; ++ ++ memset(rdr, 0, sizeof(struct xf_adsp_renderer)); /* PRQA S 3200 */ ++ ++ /* register renderer component */ ++ err = xf_adsp_register("renderer", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register Renderer to ADSP base control */ ++ rdr->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (rdr->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from Renderer plugin */ ++ err = xf_adsp_renderer_get_params(rdr); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save renderer compoent data */ ++ *renderer = rdr; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(rdr); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP Renderer component ++ * ++ *\param[in] renderer Pointer to Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Renderer data ++ **************************************************************/ ++/* PRQA S 3673 */ ++int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !renderer) ++ return -EINVAL; ++ ++ handle_id = renderer->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(renderer); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for Capture component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP Capture parameters ++ * ++ *\param[in] capture Pointer to Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_capture_set_params(struct xf_adsp_capture *capture) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_capture_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !capture) ++ return -EINVAL; ++ ++ params = &capture->params; ++ ++ /* get Capture's handle data */ ++ handle = xf_adsp_base_get_handle(capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_CHANNELS; ++ msg_params->item[i++].value = params->channel; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_STATE; ++ msg_params->item[i++].value = params->state; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP Capture parameters ++ * ++ *\param[in] capture Pointer to Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 */ ++int xf_adsp_capture_get_params(struct xf_adsp_capture *capture) ++{ ++ struct xf_adsp_capture_params *cap_params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !capture) ++ return -EINVAL; ++ ++ cap_params = &capture->params; ++ ++ /* get Capture's handle data */ ++ handle = xf_adsp_base_get_handle(capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 11 1*/ ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_CHANNELS; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_STATE; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ cap_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 11 */ ++ cap_params->channel = msg_params->r.value[i++]; ++ cap_params->pcm_width = msg_params->r.value[i++]; ++ cap_params->frame_size = msg_params->r.value[i++]; ++ cap_params->dev1 = msg_params->r.value[i++]; ++ cap_params->dev2 = msg_params->r.value[i++]; ++ cap_params->dma1 = msg_params->r.value[i++]; ++ cap_params->dma2 = msg_params->r.value[i++]; ++ cap_params->out_rate = msg_params->r.value[i++]; ++ cap_params->vol_rate = msg_params->r.value[i++]; ++ cap_params->state = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create Capture component ++ * ++ *\param[in,out] capture Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Capture instance ++ *****************************************************************************/ ++int xf_adsp_capture_create(struct xf_adsp_capture **capture, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_capture *cap; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ cap = kmalloc(sizeof(*cap), GFP_KERNEL); ++ if (!cap) ++ return -ENOMEM; ++ ++ memset(cap, 0, sizeof(struct xf_adsp_capture)); /* PRQA S 3200 */ ++ ++ /* register capture component */ ++ err = xf_adsp_register("capture", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register capture to ADSP base control */ ++ cap->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (cap->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from capture plugin */ ++ err = xf_adsp_capture_get_params(cap); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save capture compoent data */ ++ *capture = cap; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(cap); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP Capture component ++ * ++ *\param[in] capture Pointer to Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Capture data ++ **************************************************************/ ++int xf_adsp_capture_destroy(struct xf_adsp_capture *capture) /* PRQA S 3673 */ ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !capture) ++ return -EINVAL; ++ ++ handle_id = capture->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(capture); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for Equalizer component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP Equalizer parameters ++ * ++ *\param[in] equalizer Pointer to Equalizer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_equalizer_params *params; ++ struct xf_buffer *b; ++ int i, n; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !equalizer) ++ return -EINVAL; ++ ++ params = &equalizer->params; ++ ++ /* get Equalizer's handle data */ ++ handle = xf_adsp_base_get_handle(equalizer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_COEF_FS; ++ msg_params->item[i++].value = params->rate; ++ ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_CH; ++ msg_params->item[i++].value = params->channel; ++ ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; ++ msg_params->item[i++].value = params->eqz_type; ++ ++ if (params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { ++ struct xf_equalizer_parametric_coef *coef = ¶ms->p_coef; ++ ++ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; ++ msg_params->item[i++].value = coef->type[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; ++ msg_params->item[i++].value = coef->fc[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; ++ msg_params->item[i++].value = coef->band_width[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; ++ msg_params->item[i++].value = coef->gain[n]; ++ ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; ++ msg_params->item[i++].value = coef->gain_base[n]; ++ } ++ } else { ++ struct xf_equalizer_graphic_coef *coef = ¶ms->g_coef; ++ ++ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { ++ msg_params->item[i].id = ++ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; ++ msg_params->item[i++].value = coef->gain_g[n]; ++ } ++ } ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP Equalizer parameters ++ * ++ *\param[in] equalizer Pointer to Equalizer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 1*/ ++int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer) ++{ ++ struct xf_adsp_equalizer_params *eqz_params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i, n; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !equalizer) ++ return -EINVAL; ++ ++ eqz_params = &equalizer->params; ++ ++ /* get Equalizer's handle data */ ++ handle = xf_adsp_base_get_handle(equalizer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_COEF_FS; /* PRQA S 3440 4 */ ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_CH; ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; ++ ++ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { ++ /* PRQA S 3440 5 */ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; ++ ++ msg_params->c.id[i++] = ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; ++ } ++ ++ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) ++ /* PRQA S 3440 1 */ ++ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; ++ ++ /* PRQA S 3200 2 */ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ eqz_params->rate = msg_params->r.value[i++]; /* PRQA S 3440 4 */ ++ eqz_params->channel = msg_params->r.value[i++]; ++ eqz_params->pcm_width = msg_params->r.value[i++]; ++ eqz_params->eqz_type = msg_params->r.value[i++]; ++ ++ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { ++ /* PRQA S 3440 5 */ ++ eqz_params->p_coef.type[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.fc[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.band_width[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.gain[n] = msg_params->r.value[i++]; ++ eqz_params->p_coef.gain_base[n] = msg_params->r.value[i++]; ++ } ++ ++ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { ++ /* PRQA S 3440 1 */ ++ eqz_params->g_coef.gain_g[n] = msg_params->r.value[i++]; ++ } ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create Equalizer component ++ * ++ *\param[in,out] equalizer Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Equalier instance ++ *****************************************************************************/ ++int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_equalizer *eqz; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ eqz = kmalloc(sizeof(*eqz), GFP_KERNEL); ++ if (!eqz) ++ return -ENOMEM; ++ ++ memset(eqz, 0, sizeof(struct xf_adsp_equalizer)); /* PRQA S 3200 */ ++ ++ /* register equalizer component */ ++ err = xf_adsp_register("equalizer", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register equalizer to ADSP base control */ ++ eqz->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (eqz->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from equalizer plugin */ ++ err = xf_adsp_equalizer_get_params(eqz); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save equalizer compoent data */ ++ *equalizer = eqz; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(eqz); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP Equalizer component ++ * ++ *\param[in] equalizer Pointer to Equalizer component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Equalizer data ++ **************************************************************/ ++/* PRQA S 3673 */ ++int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base and Equalizer data */ ++ if (!base || !equalizer) ++ return -EINVAL; ++ ++ handle_id = equalizer->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(equalizer); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for TDM Renderer component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP TDM Renderer parameters ++ * ++ *\param[in] tdm_renderer Pointer to TDM Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_tdm_renderer_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_renderer) ++ return -EINVAL; ++ ++ params = &tdm_renderer->params; ++ ++ /* get TDM Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->item[i++].value = params->ch_mode; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP TDM Renderer parameters ++ * ++ *\param[in] tdm_renderer Pointer to TDM Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 1*/ ++int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer) ++{ ++ struct xf_adsp_tdm_renderer_params *params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_renderer) ++ return -EINVAL; ++ ++ params = &tdm_renderer->params; ++ ++ /* get TDM Renderer's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 13 1*/ ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ ++ params->ch_mode = msg_params->r.value[i++]; ++ params->pcm_width = msg_params->r.value[i++]; ++ params->frame_size = msg_params->r.value[i++]; ++ params->dev1 = msg_params->r.value[i++]; ++ params->dev2 = msg_params->r.value[i++]; ++ params->dma1 = msg_params->r.value[i++]; ++ params->dma2 = msg_params->r.value[i++]; ++ params->out_rate = msg_params->r.value[i++]; ++ params->vol_rate = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create TDM Renderer component ++ * ++ *\param[in,out] tdm_renderer Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Renderer instance ++ *****************************************************************************/ ++int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer, ++ struct xf_callback_func *cb, ++ void *private_data) ++{ ++ struct xf_adsp_tdm_renderer *tdm_rdr; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ tdm_rdr = kmalloc(sizeof(*tdm_rdr), GFP_KERNEL); ++ if (!tdm_rdr) ++ return -ENOMEM; ++ ++ /* PRQA S 3200 */ ++ memset(tdm_rdr, 0, sizeof(struct xf_adsp_tdm_renderer)); ++ ++ /* register TDM Renderer component */ ++ err = xf_adsp_register("tdm-renderer", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register TDM Renderer to ADSP base control */ ++ tdm_rdr->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (tdm_rdr->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from plugin */ ++ err = xf_adsp_tdm_renderer_get_params(tdm_rdr); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save compoent data */ ++ *tdm_renderer = tdm_rdr; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(tdm_rdr); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP TDM Renderer component ++ * ++ *\param[in] tdm_renderer Pointer to TDM Renderer component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Renderer data ++ **************************************************************/ ++/* PRQA S 3673 1*/ ++int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_renderer) ++ return -EINVAL; ++ ++ handle_id = tdm_renderer->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(tdm_renderer); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * APIs for TDM Capture component ++ * ********************************************************************/ ++ ++/** *********************************************************** ++ *\brief set ADSP TDM Capture parameters ++ * ++ *\param[in] tdm_capture Pointer to TDM Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture) ++{ ++ struct xf_message msg; ++ struct xf_set_param_msg *msg_params; ++ struct xf_adsp_tdm_capture_params *params; ++ struct xf_buffer *b; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_capture) ++ return -EINVAL; ++ ++ params = &tdm_capture->params; ++ ++ /* get TDM Capture's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->item[i++].value = params->in_rate; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->item[i++].value = params->ch_mode; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->item[i++].value = params->pcm_width; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->item[i++].value = params->frame_size; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->item[i++].value = params->dev1; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->item[i++].value = params->dev2; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->item[i++].value = params->dma1; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->item[i++].value = params->dma2; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->item[i++].value = params->out_rate; ++ ++ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ msg_params->item[i++].value = params->vol_rate; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief get ADSP TDM Capture parameters ++ * ++ *\param[in] tdm_capture Pointer to TDM Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Failed ++ **************************************************************/ ++/* PRQA S 1505 1*/ ++int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture) ++{ ++ struct xf_adsp_tdm_capture_params *params; ++ struct xf_message msg; ++ struct xf_buffer *b; ++ union xf_get_param_msg *msg_params; ++ int i; ++ struct xf_handle *handle; ++ int err = 0; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_capture) ++ return -EINVAL; ++ ++ params = &tdm_capture->params; ++ ++ /* get TDM Capture's handle data */ ++ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); ++ if (!handle) ++ return -EINVAL; ++ ++ b = xf_buffer_get(base->aux_pool); ++ msg_params = xf_buffer_data(b); ++ ++ i = 0; ++ /* PRQA S 3440 13 1*/ ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT1; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT2; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; ++ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; ++ ++ /* PRQA S 3200 2*/ ++ xf_create_msg(&msg, ++ __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id), ++ __XF_PORT_SPEC2(handle->comp_id, 0)), ++ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); ++ ++ err = xf_send_and_receive(&msg); ++ if (err != 0) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* save the received parameters */ ++ i = 0; ++ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ ++ params->ch_mode = msg_params->r.value[i++]; ++ params->pcm_width = msg_params->r.value[i++]; ++ params->frame_size = msg_params->r.value[i++]; ++ params->dev1 = msg_params->r.value[i++]; ++ params->dev2 = msg_params->r.value[i++]; ++ params->dma1 = msg_params->r.value[i++]; ++ params->dma2 = msg_params->r.value[i++]; ++ params->out_rate = msg_params->r.value[i++]; ++ params->vol_rate = msg_params->r.value[i++]; ++ ++exit: ++ /* return msg to pool */ ++ xf_buffer_put(b); ++ ++ return err; ++} ++ ++/** ************************************************************************** ++ *\brief create TDM Capture component ++ * ++ *\param[in,out] tdm_capture Pointer to the registered component ++ *\param[in] cb Callback function ++ *\param[in] private_data Private data ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base instance or register fail ++ *\retval -ENOMEM Cannot allocate Renderer instance ++ *****************************************************************************/ ++int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture, ++ struct xf_callback_func *cb, void *private_data) ++{ ++ struct xf_adsp_tdm_capture *tdm_cap; ++ int err; ++ int comp_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base) ++ return -EINVAL; ++ ++ tdm_cap = kmalloc(sizeof(*tdm_cap), GFP_KERNEL); ++ if (!tdm_cap) ++ return -ENOMEM; ++ ++ /* PRQA S 3200 */ ++ memset(tdm_cap, 0, sizeof(struct xf_adsp_tdm_capture)); ++ ++ /* register TDM Capture component */ ++ err = xf_adsp_register("tdm-capture", &comp_id); ++ if (err != 0) ++ goto err2; /* PRQA S 2001 */ ++ ++ /* register TDM Capture to ADSP base control */ ++ tdm_cap->handle_id = xf_adsp_base_register_handle(private_data, ++ cb, comp_id); ++ ++ if (tdm_cap->handle_id <= 0) { ++ err = -EINVAL; ++ goto err1; /* PRQA S 2001 */ ++ } ++ ++ /* get the default parameter from plugin */ ++ err = xf_adsp_tdm_capture_get_params(tdm_cap); ++ if (err != 0) ++ goto err1; /* PRQA S 2001 */ ++ ++ /* save compoent data */ ++ *tdm_capture = tdm_cap; ++ ++ return 0; ++ ++err1: ++ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ ++ ++err2: ++ kfree(tdm_cap); ++ ++ return err; ++} ++ ++/** *********************************************************** ++ *\brief deinitialize ADSP TDM Capture component ++ * ++ *\param[in] tdm_capture Pointer to TDM Capture component ++ *\retval 0 Success ++ *\retval -EINVAL Invalid base or Renderer data ++ **************************************************************/ ++/* PRQA S 3673 */ ++int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture) ++{ ++ struct xf_handle *handle; ++ int handle_id; ++ ++ /* check the sane ADSP base data */ ++ if (!base || !tdm_capture) ++ return -EINVAL; ++ ++ handle_id = tdm_capture->handle_id; ++ ++ handle = xf_adsp_base_get_handle(handle_id); ++ if (!handle) ++ goto exit; /* PRQA S 2001 */ ++ ++ /* unregister component */ ++ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ ++ ++ /* free handle data from base control */ ++ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ ++ ++exit: ++ kfree(tdm_capture); ++ ++ return 0; ++} +diff --git a/sound/soc/adsp/xf-adsp-base.h b/sound/soc/adsp/xf-adsp-base.h +new file mode 100644 +index 000000000000..27eb084a99a5 +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-base.h +@@ -0,0 +1,275 @@ ++/** ************************************************************************* ++ *\file xf-adsp-base.h ++ *\brief Header file for ADSP Base Control layer ++ *\addtogroup ADSP Driver ++ **************************************************************************** ++ *\date Oct. 21, 2017 ++ *\author Renesas Electronics Corporation ++ **************************************************************************** ++ *\par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#ifndef __XF_ADSP_BASE_H ++#define __XF_ADSP_BASE_H ++ ++#include "xf-adsp-config.h" ++#include ++ ++#define XF_BUF_POOL_SIZE (4) /**< number of buffer in a data pool */ ++ ++/**< maximum number of DSP component can be registered */ ++#define MAX_HANDLE (256) ++ ++/* define boolean */ ++#define TRUE (1) ++#define FALSE (0) ++ ++/** \struct xf_callback_func ++ * \brief callback function for ADSP's response message ++ */ ++struct xf_callback_func { ++ /** callback for empty buffer done message */ ++ int (*empty_buf_done)(void *data, int opcode, int length, char *buffer); ++ ++ /** callback for fill buffer done message */ ++ int (*fill_buf_done)(void *data, int opcode, int length, char *buffer); ++ ++ /** callback for event handler */ ++ int (*event_handler)(void *data); ++}; ++ ++/** \struct xf_adsp_renderer_params ++ * \brief parameter structure for Renderer component ++ */ ++struct xf_adsp_renderer_params { ++ int channel; /**< channel number */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++ int out_channel; /**< output channels */ ++ int mix_ctrl; /**< mix control flag */ ++ int state; /**< operation state */ ++}; ++ ++/** \struct xf_adsp_renderer ++ * \brief Renderer component structure ++ */ ++struct xf_adsp_renderer { ++ struct xf_adsp_renderer_params params; /**< parameter structure*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle*/ ++}; ++ ++/** \struct xf_adsp_capture_params ++ *\brief parameter structure of Capture component ++ */ ++struct xf_adsp_capture_params { ++ int channel; /**< channel number */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++ int state; /**< operation state */ ++}; ++ ++/** \struct xf_adsp_capture ++ * \brief Capture component structure ++ */ ++struct xf_adsp_capture { ++ struct xf_adsp_capture_params params; /**< parameter structuer*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle*/ ++}; ++ ++/** \struct xf_equalizer_parametric_coef ++ *\brief Parametric Equalizer type's parameters ++ */ ++struct xf_equalizer_parametric_coef { ++ int type[XA_REL_EQZ_FILTER_NUM]; /**< Filter type */ ++ int fc[XA_REL_EQZ_FILTER_NUM]; /**< Filter center frequency */ ++ int gain[XA_REL_EQZ_FILTER_NUM]; /**< Filter gain */ ++ int band_width[XA_REL_EQZ_FILTER_NUM]; /**< Filter band width */ ++ int gain_base[XA_REL_EQZ_FILTER_NUM]; /**< Filter base gain */ ++}; ++ ++/** \struct xf_equalizer_graphic_coef ++ * \brief Graphic Equalizer type's parameters ++ */ ++struct xf_equalizer_graphic_coef { ++ int gain_g[XA_REL_EQZ_GRAPHIC_BAND_NUM];/**< Graphic equalizer gain */ ++}; ++ ++/** \struct xf_adsp_equalizer_params ++ *\brief Equalizer parameters ++ */ ++struct xf_adsp_equalizer_params { ++ int channel; /**< channel number */ ++ int pcm_width; /**< PCM width */ ++ int rate; /**< sampling rate */ ++ int eqz_type; /**< Equalizer type */ ++ struct xf_equalizer_parametric_coef p_coef; /**< Parametric params */ ++ struct xf_equalizer_graphic_coef g_coef; /**< Graphic params */ ++}; ++ ++/** \struct xf_adsp_equalizer ++ * \brief Equalizer component's structure ++ */ ++struct xf_adsp_equalizer { ++ struct xf_adsp_equalizer_params params;/**< Equalizer parameters */ ++ struct xf_pool *buf_pool; /**< buffer pool for transfer data */ ++ int handle_id; /**< ID of registered handle */ ++}; ++ ++/** \struct xf_adsp_tdm_renderer_params ++ * \brief parameter structure for TDM Renderer component ++ */ ++struct xf_adsp_tdm_renderer_params { ++ int ch_mode; /**< channel mode */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++}; ++ ++/** \struct xf_adsp_tdm_renderer ++ * \brief TDM Renderer component structure ++ */ ++struct xf_adsp_tdm_renderer { ++ struct xf_adsp_tdm_renderer_params params; /**< parameter structure*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle */ ++}; ++ ++/** \struct xf_adsp_tdm_capture_params ++ * \brief parameter structure for TDM Capture component ++ */ ++struct xf_adsp_tdm_capture_params { ++ int ch_mode; /**< channel mode */ ++ int pcm_width; /**< PCM width */ ++ int frame_size; /**< frame size */ ++ int in_rate; /**< input sampling rate */ ++ int out_rate; /**< output sampling rate */ ++ int vol_rate; /**< volume rate */ ++ int dev1; /**< 1st device index */ ++ int dev2; /**< 2nd device index */ ++ int dma1; /**< 1st DMA index */ ++ int dma2; /**< 2nd DMA index */ ++}; ++ ++/** \struct xf_adsp_tdm_capture ++ * \brief TDM Capture component structure ++ */ ++struct xf_adsp_tdm_capture { ++ struct xf_adsp_tdm_capture_params params; /**< parameter structure*/ ++ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ ++ int handle_id; /**< ID of registered handle*/ ++}; ++ ++/** \struct xf_handle ++ * \brief Handle struct for each ADSP component ++ */ ++struct xf_handle { ++ int comp_id;/**< ADSP component ID */ ++ struct xf_callback_func *cb;/**< callback functions */ ++ void *private_data; /**< private data for callback functions*/ ++}; ++ ++/** \struct xf_adsp_base ++ * \brief Base component structure ++ */ ++struct xf_adsp_base { ++ struct xf_adsp_base_cmd cmd; /**< proxy commands */ ++ void *client; /**< client data which registered to proxy */ ++ struct xf_pool *aux_pool; /**< auxiliary buffer pool data */ ++ struct xf_handle *handle[MAX_HANDLE]; /**< handler data */ ++ struct task_struct *rsp_thread;/**< thread for response message*/ ++ wait_queue_head_t base_wait; /**< ADSP base's waiting queue */ ++ struct xf_message base_msg; /**< ADSP base's response message */ ++ int base_flag; /**< flag to control its waiting queue */ ++ int err_flag; /**< flag to indicate a error from plugins */ ++ int wait_flag; /**< flag to control the polling waiting*/ ++ spinlock_t lock; /**< spinlock data */ ++}; ++ ++struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length); ++int xf_adsp_free_mem_pool(struct xf_pool *pool); ++char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index); ++ ++int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length); ++int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length); ++ ++int xf_adsp_route(int src_handle_id, int dst_handle_id ++ , int buf_cnt, int buf_size); ++ ++int xf_adsp_set_param(int handle_id, int index, int value); ++int xf_adsp_get_param(int handle_id, int index, int *value); ++ ++int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer, ++ struct xf_callback_func *cb, void *private_data); ++int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer); ++int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer); ++int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer); ++ ++int xf_adsp_capture_create(struct xf_adsp_capture **capture, ++ struct xf_callback_func *cb, void *private_data); ++int xf_adsp_capture_destroy(struct xf_adsp_capture *capture); ++int xf_adsp_capture_set_params(struct xf_adsp_capture *capture); ++int xf_adsp_capture_get_params(struct xf_adsp_capture *capture); ++ ++int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer, ++ struct xf_callback_func *cb, void *private_data); ++int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer); ++int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer); ++int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer); ++ ++int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer, ++ struct xf_callback_func *cb, ++ void *private_data); ++int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer); ++int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer); ++int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer); ++ ++int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture, ++ struct xf_callback_func *cb, ++ void *private_data); ++int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture); ++int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture); ++int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture); ++ ++#endif +diff --git a/sound/soc/adsp/xf-adsp-config.h b/sound/soc/adsp/xf-adsp-config.h +new file mode 100644 +index 000000000000..818a46a66600 +--- /dev/null ++++ b/sound/soc/adsp/xf-adsp-config.h +@@ -0,0 +1,604 @@ ++/** **************************************************************************** ++ *\file xf-adsp-config.h ++ *\brief Header file for ADSP configuration ++ *\addtogroup ADSP Driver ++ ******************************************************************************* ++ *\date Oct. 21, 2017 ++ *\author Renesas Electronics Corporation ++ ******************************************************************************* ++ *\par Copyright ++ * ++ * Copyright(c) 2016 Renesas Electoronics Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ ******************************************************************************/ ++ ++#ifndef __XF_ADSP_CONFIG_H ++#define __XF_ADSP_CONFIG_H ++ ++/* Equalizer definition */ ++#define XA_REL_EQZ_FILTER_NUM (9) /**< number of filter */ ++#define XA_REL_EQZ_GRAPHIC_BAND_NUM (5) /**< number of graphic band */ ++ ++struct xf_buffer { ++ void *address; ++ union { /* PRQA S 750 3 */ ++ struct xf_buffer *next; ++ struct xf_pool *pool; ++ } link; ++}; ++ ++struct xf_pool { ++ /* length of individual buffer in a pool */ ++ u32 length; ++ ++ /* number of buffer in a pool */ ++ u32 number; ++ ++ /* pointer to pool memory */ ++ void *p; ++ ++ /* pointer to first free buffer in a pool */ ++ struct xf_buffer *free; ++ ++ /* individual buffer */ ++ struct xf_buffer buffer[0]; /* PRQA S 1037 */ ++}; ++ ++struct xf_message { ++ /* pointer to the next item in the list */ ++ struct xf_message *next; ++ ++ /* shmem session_id */ ++ u32 id; ++ ++ /* operation code */ ++ u32 opcode; ++ ++ /* length of attached message buffer */ ++ u32 length; ++ ++ /* message buffer */ ++ void *buffer; ++}; ++ ++/******************************************************************************* ++ * XF_GET_PARAM message ++ ******************************************************************************/ ++ ++/* ...message body (command/response) */ ++union xf_get_param_msg { /* PRQA S 750 18 */ ++ /* ...command structure */ ++ struct { ++ /* ...array of parameters requested */ ++ u32 id[0]; /* PRQA S 1037 */ ++ ++ } __attribute__((__packed__)) c; ++ ++ /* ...response structure */ ++ struct { ++ /* ...array of parameters values */ ++ u32 value[0];/* PRQA S 1037 */ ++ ++ } __attribute__((__packed__)) r; ++ ++}; ++ ++/* ...length of the XF_GET_PARAM command/response */ ++/* PRQA S 3453 2 */ ++#define XF_GET_PARAM_CMD_LEN(params) (sizeof(u32) * (params)) ++#define XF_GET_PARAM_RSP_LEN(params) (sizeof(u32) * (params)) ++ ++/******************************************************************************* ++ * XF_SET_PARAM message ++ ******************************************************************************/ ++ ++/* ...component initialization parameter */ ++struct xf_set_param_item { ++ /* ...index of parameter passed to SET_CONFIG_PARAM call */ ++ u32 id; ++ ++ /* ...value of parameter */ ++ u32 value; ++ ++} __attribute__ ((__packed__)); ++ ++/* ...message body (no response message? - tbd) */ ++struct xf_set_param_msg { ++ /* ...command message */ ++ struct xf_set_param_item item[0]; /* PRQA S 1037 */ ++ ++} __attribute__ ((__packed__)); ++ ++/* ...length of the command message */ ++/* PRQA S 3453 */ ++#define XF_SET_PARAM_CMD_LEN(params) \ ++ (sizeof(struct xf_set_param_item) * (params)) ++ ++/******************************************************************************* ++ * XF_ROUTE definition ++ ******************************************************************************/ ++ ++/* ...port routing command */ ++struct xf_route_port_msg { ++ /* ...source port specification */ ++ u32 src; ++ ++ /* ...destination port specification */ ++ u32 dst; ++ ++ /* ...number of buffers to allocate */ ++ u32 alloc_number; ++ ++ /* ...length of buffer to allocate */ ++ u32 alloc_size; ++ ++ /* ...alignment restriction for a buffer */ ++ u32 alloc_align; ++ ++} __attribute__((__packed__)); ++ ++/******************************************************************************* ++ * XF_UNROUTE definition ++ ******************************************************************************/ ++ ++/* ...port unrouting command */ ++struct xf_unroute_port_msg { ++ /* ...source port specification */ ++ u32 src; ++ ++ /* ...destination port specification */ ++ u32 dst; ++ ++} __attribute__((__packed__)); ++ ++/* ...Capture states */ ++enum xa_capture_state { ++ XA_CAP_STATE_RUN = 0, ++ XA_CAP_STATE_IDLE = 1, ++ XA_CAP_STATE_PAUSE = 2 ++}; ++ ++/* ...Renderer states */ ++enum xa_renderer_state { ++ XA_RDR_STATE_RUN = 0, ++ XA_RDR_STATE_IDLE = 1, ++ XA_RDR_STATE_PAUSE = 2 ++}; ++ ++/******************************************************************************* ++ * Message routing composition - move somewhere else - tbd ++ ******************************************************************************/ ++ ++/* ...adjust IPC client of message going from user-space */ ++#define XF_MSG_AP_FROM_USER(id, client) \ ++ (((id) & ~(0xF << 2)) | ((client) << 2)) ++ ++/* ...wipe out IPC client from message going to user-space */ ++#define XF_MSG_AP_TO_USER(id) \ ++ ((id) & ~(0xF << 18)) ++ ++/* ...port specification (12 bits) */ ++#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8)) ++#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8)) ++#define XF_PORT_CORE(spec) ((spec) & 0x3) ++#define XF_PORT_CLIENT(spec) (((spec) >> 2) & 0x3F) ++#define XF_PORT_ID(spec) (((spec) >> 8) & 0xF) ++ ++/* ...message id contains source and destination ports specification */ ++#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) ++#define XF_MSG_SRC(id) (((id) >> 0) & 0xFFFF) ++#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3) ++#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F) ++#define XF_MSG_SRC_PORT(id) (((id) >> 8) & 0xF) ++#define XF_MSG_SRC_PROXY(id) (((id) >> 15) & 0x1) ++#define XF_MSG_DST(id) (((id) >> 16) & 0xFFFF) ++#define XF_MSG_DST_CORE(id) (((id) >> 16) & 0x3) ++#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F) ++#define XF_MSG_DST_PORT(id) (((id) >> 24) & 0xF) ++#define XF_MSG_DST_PROXY(id) (((id) >> 31) & 0x1) ++ ++/* ...special treatment of AP-proxy destination field */ ++#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) ++#define XF_AP_CLIENT(id) (((id) >> 22) & 0x1FF) ++#define __XF_AP_PROXY(core) ((core) | 0x8000) ++#define __XF_DSP_PROXY(core) ((core) | 0x8000) ++#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 0x8000) ++ ++/******************************************************************************* ++ * Opcode composition ++ ******************************************************************************/ ++ ++/* ...opcode composition with command/response data tags */ ++#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) ++ ++/* ...accessors */ ++#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31)) ++#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30)) ++#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F)) ++ ++/******************************************************************************* ++ * Opcode types ++ ******************************************************************************/ ++ ++/* ...unregister client */ ++#define XF_UNREGISTER __XF_OPCODE(0, 0, 0) ++ ++/* ...register client at proxy */ ++#define XF_REGISTER __XF_OPCODE(1, 0, 1) ++ ++/* ...port routing command */ ++#define XF_ROUTE __XF_OPCODE(1, 0, 2) ++ ++/* ...port unrouting command */ ++#define XF_UNROUTE __XF_OPCODE(1, 0, 3) ++ ++/* ...shared buffer allocation */ ++#define XF_ALLOC __XF_OPCODE(0, 0, 4) ++ ++/* ...shared buffer freeing */ ++#define XF_FREE __XF_OPCODE(0, 0, 5) ++ ++/* ...set component parameters */ ++#define XF_SET_PARAM __XF_OPCODE(1, 0, 6) ++ ++/* ...get component parameters */ ++#define XF_GET_PARAM __XF_OPCODE(1, 1, 7) ++ ++/* ...input buffer reception */ ++#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8) ++ ++/* ...output buffer reception */ ++#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9) ++ ++/* ...flush specific port */ ++#define XF_FLUSH __XF_OPCODE(0, 0, 10) ++ ++/* ...start component operation */ ++#define XF_START __XF_OPCODE(0, 0, 11) ++ ++/* ...stop component operation */ ++#define XF_STOP __XF_OPCODE(0, 0, 12) ++ ++/* ...pause component operation */ ++#define XF_PAUSE __XF_OPCODE(0, 0, 13) ++ ++/* ...resume component operation */ ++#define XF_RESUME __XF_OPCODE(0, 0, 14) ++ ++/* ...total amount of supported decoder commands */ ++#define __XF_OP_NUM (15) ++ ++/************************************************* ++ * Renderer - specific configuration parameters ++ * **********************************************/ ++ ++enum xa_config_param_renderer { ++ XA_RDR_CONFIG_PARAM_STATE = 0, ++ XA_RDR_CONFIG_PARAM_PCM_WIDTH = 1, ++ XA_RDR_CONFIG_PARAM_CHANNELS = 2, ++ XA_RDR_CONFIG_PARAM_SAMPLE_RATE = 3, ++ XA_RDR_CONFIG_PARAM_FRAME_SIZE = 4, ++ XA_RDR_CONFIG_PARAM_OUTPUT1 = 5, ++ XA_RDR_CONFIG_PARAM_DMACHANNEL1 = 6, ++ XA_RDR_CONFIG_PARAM_OUTPUT2 = 7, ++ XA_RDR_CONFIG_PARAM_DMACHANNEL2 = 8, ++ XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 9, ++ XA_RDR_CONFIG_PARAM_VOLUME_RATE = 10, ++ XA_RDR_CONFIG_PARAM_OUT_CHANNELS = 11, ++ XA_RDR_CONFIG_PARAM_MIX_CONTROL = 12, ++ XA_RDR_CONFIG_PARAM_NUM = 13 ++}; ++ ++/************************************************* ++ * Capture - specific configuration parameters ++ * **********************************************/ ++ ++enum xa_config_param_capture { ++ XA_CAP_CONFIG_PARAM_CB = 0, ++ XA_CAP_CONFIG_PARAM_STATE = 1, ++ XA_CAP_CONFIG_PARAM_PCM_WIDTH = 2, ++ XA_CAP_CONFIG_PARAM_CHANNELS = 3, ++ XA_CAP_CONFIG_PARAM_SAMPLE_RATE = 4, ++ XA_CAP_CONFIG_PARAM_FRAME_SIZE = 5, ++ XA_CAP_CONFIG_PARAM_INPUT1 = 6, ++ XA_CAP_CONFIG_PARAM_DMACHANNEL1 = 7, ++ XA_CAP_CONFIG_PARAM_INPUT2 = 8, ++ XA_CAP_CONFIG_PARAM_DMACHANNEL2 = 9, ++ XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 10, ++ XA_CAP_CONFIG_PARAM_VOLUME_RATE = 11, ++ XA_CAP_CONFIG_PARAM_NUM = 12 ++}; ++ ++/************************************************* ++ * Equalizer - specific configuration parameters ++ * **********************************************/ ++ ++enum xa_rel_eqz_filter_type { ++ XA_REL_EQZ_TYPE_THROUGH = 0, ++ XA_REL_EQZ_TYPE_PEAK = 1, ++ XA_REL_EQZ_TYPE_BASS = 2, ++ XA_REL_EQZ_TYPE_TREBLE = 3 ++}; ++ ++enum xa_rel_eqz_type { ++ XA_REL_EQZ_TYPE_PARAMETRIC = 0, ++ XA_REL_EQZ_TYPE_GRAPHIC = 1 ++}; ++ ++/*****************************************************************************/ ++/* Additional subcommand indices */ ++/*****************************************************************************/ ++ ++enum xa_add_cmd_type_generic { ++ /* XA_API_CMD_SET_CONFIG_PARAM indices */ ++ XA_EQZ_CONFIG_PARAM_COEF_FS = 0x0000, ++ XA_EQZ_CONFIG_PARAM_PCM_WIDTH = 0x0001, ++ XA_EQZ_CONFIG_PARAM_CH = 0x0002, ++ XA_EQZ_CONFIG_PARAM_EQZ_TYPE = 0x0003, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC = 0x0010, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_FC = 0x0011, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_FC = 0x0012, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_FC = 0x0013, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_FC = 0x0014, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_FC = 0x0015, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_FC = 0x0016, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_FC = 0x0017, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_FC = 0x0018, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE = 0x0020, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_TYPE = 0x0021, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_TYPE = 0x0022, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_TYPE = 0x0023, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_TYPE = 0x0024, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_TYPE = 0x0025, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_TYPE = 0x0026, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_TYPE = 0x0027, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_TYPE = 0x0028, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW = 0x0030, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BW = 0x0031, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BW = 0x0032, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BW = 0x0033, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BW = 0x0034, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BW = 0x0035, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BW = 0x0036, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BW = 0x0037, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BW = 0x0038, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA = 0x0040, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_GA = 0x0041, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_GA = 0x0042, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_GA = 0x0043, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_GA = 0x0044, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_GA = 0x0045, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_GA = 0x0046, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_GA = 0x0047, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_GA = 0x0048, ++ ++ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA = 0x0050, ++ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BA = 0x0051, ++ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BA = 0x0052, ++ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BA = 0x0053, ++ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BA = 0x0054, ++ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BA = 0x0055, ++ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BA = 0x0056, ++ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BA = 0x0057, ++ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BA = 0x0058, ++ ++ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA = 0x0060, ++ XA_EQZ_CONFIG_PARAM_BAND_1_GCOEF_GA = 0x0061, ++ XA_EQZ_CONFIG_PARAM_BAND_2_GCOEF_GA = 0x0062, ++ XA_EQZ_CONFIG_PARAM_BAND_3_GCOEF_GA = 0x0063, ++ XA_EQZ_CONFIG_PARAM_BAND_4_GCOEF_GA = 0x0064 ++}; ++ ++/* ...tdm-renderer-specific configuration parameters */ ++enum xa_config_param_tdm_renderer { ++ XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH = 0, ++ XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE = 1, ++ XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE = 2, ++ XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE = 3, ++ XA_TDM_RDR_CONFIG_PARAM_OUTPUT1 = 4, ++ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1 = 5, ++ XA_TDM_RDR_CONFIG_PARAM_OUTPUT2 = 6, ++ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2 = 7, ++ XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, ++ XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE = 9 ++}; ++ ++enum xa_rel_tdm_renderer_channel_mode { ++ XA_TDM_RDR_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ ++ XA_TDM_RDR_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ ++ /**< 1 six-channels plus 1 two-channels TDM data */ ++ XA_TDM_RDR_CHANNEL_MODE_6_2 = 2, ++ XA_TDM_RDR_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ ++ XA_TDM_RDR_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ ++}; ++ ++/* ...TDM Capture-specific configuration parameters */ ++enum xa_config_param_tdm_capture { ++ XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH = 0, ++ XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE = 1, ++ XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE = 2, ++ XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE = 3, ++ XA_TDM_CAP_CONFIG_PARAM_INPUT1 = 4, ++ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1 = 5, ++ XA_TDM_CAP_CONFIG_PARAM_INPUT2 = 6, ++ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2 = 7, ++ XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, ++ XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE = 9 ++}; ++ ++enum xa_rel_tdm_capture_channel_mode { ++ XA_TDM_CAP_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ ++ XA_TDM_CAP_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ ++ /**< 1 six-channels plus 1 two-channels TDM data */ ++ XA_TDM_CAP_CHANNEL_MODE_6_2 = 2, ++ XA_TDM_CAP_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ ++ XA_TDM_CAP_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ ++}; ++ ++/*****************************************************************************/ ++/* HW supported */ ++/*****************************************************************************/ ++/* ...SSI modules supported by HW */ ++enum ssi_module { ++ SSI00 = 0, ++ SSI01 = 1, ++ SSI02 = 2, ++ SSI03 = 3, ++ SSI04 = 4, ++ SSI05 = 5, ++ SSI06 = 6, ++ SSI07 = 7, ++ SSI10 = 10, ++ SSI11 = 11, ++ SSI12 = 12, ++ SSI13 = 13, ++ SSI14 = 14, ++ SSI15 = 15, ++ SSI16 = 16, ++ SSI17 = 17, ++ SSI20 = 20, ++ SSI21 = 21, ++ SSI22 = 22, ++ SSI23 = 23, ++ SSI24 = 24, ++ SSI25 = 25, ++ SSI26 = 26, ++ SSI27 = 27, ++ SSI30 = 30, ++ SSI31 = 31, ++ SSI32 = 32, ++ SSI33 = 33, ++ SSI34 = 34, ++ SSI35 = 35, ++ SSI36 = 36, ++ SSI37 = 37, ++ SSI40 = 40, ++ SSI41 = 41, ++ SSI42 = 42, ++ SSI43 = 43, ++ SSI44 = 44, ++ SSI45 = 45, ++ SSI46 = 46, ++ SSI47 = 47, ++ SSI5 = 50, ++ SSI6 = 60, ++ SSI7 = 70, ++ SSI8 = 80, ++ SSI90 = 90, ++ SSI91 = 91, ++ SSI92 = 92, ++ SSI93 = 93, ++ SSI94 = 94, ++ SSI95 = 95, ++ SSI96 = 96, ++ SSI97 = 97 ++}; ++ ++/* ...SRC modules supported by HW */ ++enum src_module { ++ SRC0 = 110, /* SRC0 */ ++ SRC1 = 111, /* SRC1 */ ++ SRC2 = 112, /* SRC2 */ ++ SRC3 = 113, /* SRC3 */ ++ SRC4 = 114, /* SRC4 */ ++ SRC5 = 115, /* SRC5 */ ++ SRC6 = 116, /* SRC6 */ ++ SRC7 = 117, /* SRC7 */ ++ SRC8 = 118, /* SRC8 */ ++ SRC9 = 119, /* SRC9 */ ++ SRCMAX = 120 /* Maximum number of SRC modules */ ++}; ++ ++/* ...PDMA supported by HW */ ++enum { ++ PDMA_CH00 = 0, ++ PDMA_CH01 = 1, ++ PDMA_CH02 = 2, ++ PDMA_CH03 = 3, ++ PDMA_CH04 = 4, ++ PDMA_CH05 = 5, ++ PDMA_CH06 = 6, ++ PDMA_CH07 = 7, ++ PDMA_CH08 = 8, ++ PDMA_CH09 = 9, ++ PDMA_CH10 = 10, ++ PDMA_CH11 = 11, ++ PDMA_CH12 = 12, ++ PDMA_CH13 = 13, ++ PDMA_CH14 = 14, ++ PDMA_CH15 = 15, ++ PDMA_CH16 = 16, ++ PDMA_CH17 = 17, ++ PDMA_CH18 = 18, ++ PDMA_CH19 = 19, ++ PDMA_CH20 = 20, ++ PDMA_CH21 = 21, ++ PDMA_CH22 = 22, ++ PDMA_CH23 = 23, ++ PDMA_CH24 = 24, ++ PDMA_CH25 = 25, ++ PDMA_CH26 = 26, ++ PDMA_CH27 = 27, ++ PDMA_CH28 = 28, ++ PDMA_CHMAX = 29 ++}; ++ ++/* ...DMAC supported by HW */ ++enum { ++ ADMAC_CH00 = PDMA_CHMAX + 0, ++ ADMAC_CH01 = PDMA_CHMAX + 1, ++ ADMAC_CH02 = PDMA_CHMAX + 2, ++ ADMAC_CH03 = PDMA_CHMAX + 3, ++ ADMAC_CH04 = PDMA_CHMAX + 4, ++ ADMAC_CH05 = PDMA_CHMAX + 5, ++ ADMAC_CH06 = PDMA_CHMAX + 6, ++ ADMAC_CH07 = PDMA_CHMAX + 7, ++ ADMAC_CH08 = PDMA_CHMAX + 8, ++ ADMAC_CH09 = PDMA_CHMAX + 9, ++ ADMAC_CH10 = PDMA_CHMAX + 10, ++ ADMAC_CH11 = PDMA_CHMAX + 11, ++ ADMAC_CH12 = PDMA_CHMAX + 12, ++ ADMAC_CH13 = PDMA_CHMAX + 13, ++ ADMAC_CH14 = PDMA_CHMAX + 14, ++ ADMAC_CH15 = PDMA_CHMAX + 15, ++ ADMAC_CH16 = PDMA_CHMAX + 16, ++ ADMAC_CH17 = PDMA_CHMAX + 17, ++ ADMAC_CH18 = PDMA_CHMAX + 18, ++ ADMAC_CH19 = PDMA_CHMAX + 19, ++ ADMAC_CH20 = PDMA_CHMAX + 20, ++ ADMAC_CH21 = PDMA_CHMAX + 21, ++ ADMAC_CH22 = PDMA_CHMAX + 22, ++ ADMAC_CH23 = PDMA_CHMAX + 23, ++ ADMAC_CH24 = PDMA_CHMAX + 24, ++ ADMAC_CH25 = PDMA_CHMAX + 25, ++ ADMAC_CH26 = PDMA_CHMAX + 26, ++ ADMAC_CH27 = PDMA_CHMAX + 27, ++ ADMAC_CH28 = PDMA_CHMAX + 28, ++ ADMAC_CH29 = PDMA_CHMAX + 29, ++ ADMAC_CH30 = PDMA_CHMAX + 30, ++ ADMAC_CH31 = PDMA_CHMAX + 31, ++ ADMAC_CHMAX = PDMA_CHMAX + 32 ++}; ++ ++#endif +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-Add-document-file-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-Add-document-file-for-ADSP-sound-driver.patch deleted file mode 100644 index f4305ad..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-Add-document-file-for-ADSP-sound-driver.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 35f2052da7ebf049daaf85ff8c8eb8d31617c80f Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 17:59:33 +0700 -Subject: [PATCH 2/4] Add document file for ADSP sound driver - -Signed-off-by: tienphitran - -diff --git a/Documentation/devicetree/bindings/sound/renesas,adsp.txt b/Documentation/devicetree/bindings/sound/renesas,adsp.txt -new file mode 100644 -index 0000000..b529bca ---- /dev/null -+++ b/Documentation/devicetree/bindings/sound/renesas,adsp.txt -@@ -0,0 +1,11 @@ -+Renesas ADSP sound driver -+ -+Required properties: -+- compatible : "renesas,rcar_adsp_sound_gen3" -+ -+Example: -+ -+rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+}; --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch deleted file mode 100644 index e7c17d6..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d25996a812524c338423b9da86233564d18f0042 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:41 +0900 -Subject: [PATCH 2/6] arm64: dts: r8a7796-salvator-xs: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts -index 2f4bd3ae3678..ba040341aa26 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts -@@ -101,11 +101,6 @@ - "dclkin.0", "dclkin.1", "dclkin.2"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1>; /* HDMI0 */ --}; -- - &hdmi0 { - status = "okay"; - --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-ADSP-add-build-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-ADSP-add-build-for-ADSP-sound-driver.patch new file mode 100644 index 0000000..ecab412 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-ADSP-add-build-for-ADSP-sound-driver.patch @@ -0,0 +1,35 @@ +From 3ae5cb9feda031f660becc94f5496d5ee9b90e22 Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Mon, 15 Oct 2018 17:57:56 +0700 +Subject: [PATCH 3/6] ADSP: add build for ADSP sound driver + +Signed-off-by: tienphitran +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig +index c0abad2067e1..f5f6abbd6e14 100644 +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -71,6 +71,7 @@ source "sound/soc/txx9/Kconfig" + source "sound/soc/ux500/Kconfig" + source "sound/soc/xtensa/Kconfig" + source "sound/soc/zte/Kconfig" ++source "sound/soc/adsp/Kconfig" + + # Supported codecs + source "sound/soc/codecs/Kconfig" +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index bf8c1e2ce0bf..6e77abba2b01 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -52,3 +52,4 @@ obj-$(CONFIG_SND_SOC) += txx9/ + obj-$(CONFIG_SND_SOC) += ux500/ + obj-$(CONFIG_SND_SOC) += xtensa/ + obj-$(CONFIG_SND_SOC) += zte/ ++obj-$(CONFIG_SND_SOC) += adsp/ +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch deleted file mode 100644 index d25c2b1..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch +++ /dev/null @@ -1,7172 +0,0 @@ -From 1705856b55d8f93a22843a9577eadac4212342e7 Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 18:00:42 +0700 -Subject: [PATCH 3/4] Add ADSP sound driver source - -Signed-off-by: tienphitran - -diff --git a/include/adsp_drv/xf-adsp-drv-ext.h b/include/adsp_drv/xf-adsp-drv-ext.h -new file mode 100644 -index 0000000..6e56b45 ---- /dev/null -+++ b/include/adsp_drv/xf-adsp-drv-ext.h -@@ -0,0 +1,60 @@ -+/***************************************************************************** -+ * \file xf-adsp-driver-ext.h -+ * \brief Header file for ADSP driver extension part -+ * \addtogroup ADSP Driver -+ ****************************************************************************** -+ * \date Oct. 21, 2017 -+ * \author Renesas Electronics Corporation -+ ****************************************************************************** -+ * \par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#ifndef __XF_ADSP_DRV_EXT_H -+#define __XF_ADSP_DRV_EXT_H -+ -+/*********************************************************** -+ * Extension client APIs -+ * ********************************************************/ -+ -+typedef struct xf_adsp_base_cmd xf_adsp_base_cmd_t; -+ -+struct xf_adsp_base_cmd { -+ /* register new client for ADSP base control */ -+ int (*client_register)(void **private_data); -+ /* unregister client */ -+ int (*client_unregister)(void *private_data); -+ /* get data from proxy */ -+ int (*recv)(void *private_data, void *buf); -+ /* send data to proxy */ -+ int (*send)(void *private_data, void *buf); -+ /* wait the valid message in the response queue */ -+ int (*poll)(void *private_data, volatile int *condition); -+}; -+ -+/* create ADSP base control data */ -+int xf_adsp_base_create(xf_adsp_base_cmd_t *cmd); -+ -+/* destroy ADSP base control data */ -+int xf_adsp_base_destroy(void); -+ -+#endif -diff --git a/sound/soc/adsp/Kconfig b/sound/soc/adsp/Kconfig -new file mode 100644 -index 0000000..605261f ---- /dev/null -+++ b/sound/soc/adsp/Kconfig -@@ -0,0 +1,14 @@ -+## SoC for ADSP driver configuration -+menu "ASoC ADSP driver" -+ -+config SND_SOC_ADSP -+ tristate "SoC Audio for R-Car ADSP" -+ select SND_SIMPLE_CARD -+ select SND_SIMPLE_SCU_CARD -+ select SND_AUDIO_GRAPH_CARD -+ select SND_AUDIO_GRAPH_SCU_CARD -+ default y -+ help -+ This option enables ALSA ADSP sound supports ADSP module -+ -+endmenu -diff --git a/sound/soc/adsp/Makefile b/sound/soc/adsp/Makefile -new file mode 100644 -index 0000000..8277fdb ---- /dev/null -+++ b/sound/soc/adsp/Makefile -@@ -0,0 +1,3 @@ -+## Makefile for SoC ADSP driver -+snd-soc-adsp-objs := xf-adsp-alsa.o xf-adsp-base.o -+obj-$(CONFIG_SND_SOC_ADSP) += snd-soc-adsp.o -diff --git a/sound/soc/adsp/xf-adsp-alsa.c b/sound/soc/adsp/xf-adsp-alsa.c -new file mode 100644 -index 0000000..b6c5752 ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-alsa.c -@@ -0,0 +1,3924 @@ -+/** *************************************************************************** -+ * \file xf-adsp-alsa.c -+ * \brief Source file for ADSP ALSA Driver -+ * \addtogroup ADSP Driver -+ ****************************************************************************** -+ * \date Oct. 21, 2017 -+ * \author Renesas Electronics Corporation -+ ****************************************************************************** -+ * \par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ *****************************************************************************/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xf-adsp-base.h" -+ -+ -+/* Name of Volume control for playback */ -+#define PLAYBACK_VOLUME_CTR_NAME "PlaybackVolume" -+ -+/* Name of Volume control for capture */ -+#define CAPTURE_VOLUME_CTR_NAME "CaptureVolume" -+ -+/* Name of Sample Rate control for playback */ -+#define PLAYBACK_OUT_RATE_CTR_NAME "PlaybackOutRate" -+ -+/* Name of Output Channel control for playback */ -+#define PLAYBACK_OUT_CHANNEL_CTR_NAME "PlaybackOutChannel" -+ -+/* Name of Sample Rate control for capture */ -+#define CAPTURE_IN_RATE_CTR_NAME "CaptureInRate" -+ -+/* Name of Equalizer parameters control for playback */ -+#define PLAYBACK_EQZ_CTR_NAME "PlaybackEQZControl" -+ -+/* Name of Equalizer parameters control for capture */ -+#define CAPTURE_EQZ_CTR_NAME "CaptureEQZControl" -+ -+/* Name of Equalizer Switch control for playback */ -+#define PLAYBACK_EQZ_SWITCH_CTR_NAME "PlaybackEQZSwitch" -+ -+/* Name of Equalizer Switch control for capture */ -+#define CAPTURE_EQZ_SWITCH_CTR_NAME "CaptureEQZSwitch" -+ -+/* Name of Volume control for TDM playback */ -+#define TDM_PLAYBACK_VOLUME_CTR_NAME "TDMPlaybackVolume" -+ -+/* Name of Volume control for TDM capture */ -+#define TDM_CAPTURE_VOLUME_CTR_NAME "TDMCaptureVolume" -+ -+/* Name of Sample Rate control for TDM playback */ -+#define TDM_PLAYBACK_OUT_RATE_CTR_NAME "TDMPlaybackOutRate" -+ -+/* Name of Sample Rate control for TDM capture */ -+#define TDM_CAPTURE_IN_RATE_CTR_NAME "TDMCaptureInRate" -+ -+/* Prefix of Playback control name */ -+#define PREFIX_OF_PLAYBACK_CTR_NAME PLAYBACK_VOLUME_CTR_NAME[0] -+ -+/* Prefix of Capture control name */ -+#define PREFIX_OF_CAPTURE_CTR_NAME CAPTURE_VOLUME_CTR_NAME[0] -+ -+/* Prefix of TDM control name */ -+#define PREFIX_OF_TDM_CTR_NAME TDM_PLAYBACK_VOLUME_CTR_NAME[0] -+ -+/* Prefix of TDM playback */ -+#define TDM_PLAYBACK TDM_PLAYBACK_VOLUME_CTR_NAME[3] -+ -+/* Prefix of TDM record */ -+#define TDM_CAPTURE TDM_CAPTURE_VOLUME_CTR_NAME[3] -+ -+/* Number of control for playback & capture */ -+#define RDR_CONTROL_NUM (9) -+ -+/* Number of controls for TDM */ -+#define TDM_CONTROL_NUM (4) -+ -+/* Indicate playback stream */ -+#define DIRECT_PLAYBACK (0) -+ -+/* Indicate capture stream */ -+#define DIRECT_CAPTURE (1) -+ -+/* Indicate stream number */ -+#define DIRECT_NUM (2) -+ -+/* Supported frame size for playback/record function in driver */ -+#define FRAME_SIZE (1024) -+ -+/* Supported frame size for TDM playback/record function in driver */ -+#define TDM_FRAME_SIZE (1024) -+ -+/* Supported sample rate in driver */ -+#define SND_ADSP_SAMPLE_RATES (SNDRV_PCM_RATE_32000 | \ -+ SNDRV_PCM_RATE_44100 | \ -+ SNDRV_PCM_RATE_48000) -+ -+/* Supported PCM width in driver */ -+#define SND_ADSP_PCM_WIDTHS (SNDRV_PCM_FMTBIT_S16_LE | \ -+ SNDRV_PCM_FMTBIT_S24_LE) -+ -+/* Macro to control DAI index */ -+/* DAI 0 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX0 (0) -+ -+/* DAI 1 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX1 (1) -+ -+/* DAI 2 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX2 (2) -+ -+/* DAI 3 index for playback/record functions of stereo/mono formats */ -+#define RDR_DAI_IDX3 (3) -+ -+/* DAI 4 index for playback/record functions of TDM formats */ -+#define TDM_DAI_IDX (4) -+ -+/* Maximum number of DAI supported by driver */ -+#define MAX_DAI_IDX (5) -+ -+/* Renderer/Capture software information */ -+/* Minimum channel number supported */ -+#define MIN_CHANNEL (1) -+ -+/* Maximum channel number supported */ -+#define MAX_CHANNEL (2) -+ -+/* Minimum buffer size in byte */ -+#define MIN_BUF_SIZE (FRAME_SIZE * MIN_CHANNEL * 2) -+ -+/* Maximum buffer size in byte */ -+#define MAX_BUF_SIZE (FRAME_SIZE * MAX_CHANNEL * 4) -+ -+/* Minimum numbers of period in the buffer */ -+#define MIN_PERIOD (1) -+ -+/* Maximum numbers of period in the buffer */ -+#define MAX_PERIOD (4) -+ -+/* Maximun numbers of bytes in ALSA buffer */ -+#define MAX_BUFFER_BYTES (MAX_PERIOD * MAX_BUF_SIZE) -+ -+/* TDM software information */ -+/*< Minimum channel number supported in TDM plugin */ -+#define TDM_MIN_CHANNEL (6) -+ -+/* Maximum channel number supported in TDM plugin */ -+#define TDM_MAX_CHANNEL (8) -+ -+/* Minimum buffer size in byte for TDM format */ -+#define TDM_MIN_BUF_SIZE (TDM_FRAME_SIZE * TDM_MIN_CHANNEL * 2) -+ -+/* Maximum buffer size in byte for TDM format */ -+#define TDM_MAX_BUF_SIZE (TDM_FRAME_SIZE * TDM_MAX_CHANNEL * 4) -+ -+/* Minimum numbers of period in the buffer for TDM format */ -+#define TDM_MIN_PERIOD (1) -+ -+/* Maximum numbers of period in the buffer for TDM format */ -+#define TDM_MAX_PERIOD (4) -+ -+/* Maximum numbers of bytes in ALSA buffer for TDM format */ -+#define TDM_MAX_BUFFER_BYTES (TDM_MAX_PERIOD * TDM_MAX_BUF_SIZE) -+ -+/* Volume scale used when user set */ -+#define VOLUME_SCALE (100) -+ -+/* Maximum element in Equalizer parameter control */ -+#define MAX_EQZ_PARAM_NUMBER (55) -+ -+/* Equalizer control is disabled */ -+#define EQZ_OFF (0) -+ -+/* Equalizer control is enabled */ -+#define EQZ_ON (1) -+ -+/* Component status */ -+/* Handle state is NULL */ -+#define XF_HANDLE_NULL (0) -+ -+/* Handle state is CREATED after creating handle successfully */ -+#define XF_HANDLE_CREATED (1 << 0) -+ -+/* Handle state is READY after finishing handle init */ -+#define XF_HANDLE_READY (1 << 1) -+ -+/* channels */ -+/* Mono stream */ -+#define MONAURAL (1) -+ -+/* Stereo stream */ -+#define STEREO (2) -+ -+/* define number of bytes in a sample of 24 bits format types */ -+/* store 24 bits data in 4 bytes LE */ -+#define FMTBIT_S24_LE_BYTES_PER_SAMPLE (4) -+ -+/* store 24 bits data in 3 bytes LE */ -+#define FMTBIT_S24_3LE_BYTES_PER_SAMPLE (3) -+ -+/* helper macro to get bytes per sample number */ -+#define BYTES_PER_SAMPLE(fmt) (FMTBIT_##fmt##_BYTES_PER_SAMPLE) -+ -+/* copy a sample from S24_LE format to S24_3LE format type */ -+#define SAMPLE_COPY_FROM_S24_LE_TO_S24_3LE(dst, src) \ -+ do { \ -+ dst[0] = src[0]; \ -+ dst[1] = src[1]; \ -+ dst[2] = src[2]; \ -+ } while (0) -+ -+/* copy a sample from S24_3LE format to S24_LE format type */ -+#define SAMPLE_COPY_FROM_S24_3LE_TO_S24_LE(dst, src) \ -+ do { \ -+ dst[0] = src[0]; \ -+ dst[1] = src[1]; \ -+ dst[2] = src[2]; \ -+ dst[3] = 0; \ -+ } while (0) -+ -+/* helper macro to copy a sample from difference format data */ -+#define SAMPLE_COPY(dst, src, dst_fmt, src_fmt) \ -+ SAMPLE_COPY_FROM_##src_fmt##_TO_##dst_fmt(dst, src) -+ -+/* check if data is valid */ -+#define IS_VALID(data) (data != NULL) -+ -+/* check component is created */ -+#define COMPONENT_IS_CREATED(n) (((n & XF_HANDLE_CREATED) != 0) ? TRUE : FALSE) -+ -+/* check component is ready */ -+#define COMPONENT_IS_READY(n) (((n & XF_HANDLE_READY) != 0) ? TRUE : FALSE) -+ -+/* indicator of stream order */ -+#define MIX_UNUSED (0) -+#define FIRST_RUN (2) -+#define SECOND_RUN (1) -+ -+/* check MIX usage */ -+#define MIX_ENABLED(mix_ctl) ((mix_ctl == SECOND_RUN) ? TRUE : FALSE) -+ -+/******************************************************************* -+ * base structures for ADSP ALSA driver -+ * ****************************************************************/ -+ -+/** \struct snd_adsp_control -+ * \brief Structure stores parameters from user -+ */ -+struct snd_adsp_control { -+ /* Volume rate for playback/record */ -+ int vol_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Volume rate for TDM playback/TDM record */ -+ int tdm_vol_rate[DIRECT_NUM]; -+ -+ /* Out sample rate with Renderer, in sample rate with Capture */ -+ int sample_rate[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Out sample rate for TDM Renderer, in sample rate for TDM Capture */ -+ int tdm_sample_rate[DIRECT_NUM]; -+ -+ /* Output channel of playback */ -+ int rdr_out_ch[MAX_DAI_IDX - 1]; -+ -+ /* Equalizer parameters */ -+ struct xf_adsp_equalizer_params eqz_params[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Equalizer switch */ -+ int eqz_switch[DIRECT_NUM][MAX_DAI_IDX - 1]; -+ -+ /* Indicator of MIX usage */ -+ int mix_usage; -+}; -+ -+/** \struct snd_adsp_base_info -+ * \brief Structure stores some base information of a stream -+ */ -+struct snd_adsp_base_info { -+ /* high resolution timer data */ -+ struct hrtimer hrtimer; -+ -+ /* kernel time value in nanosecond */ -+ ktime_t ktime; -+ -+ /* high resolution timer state */ -+ int hrt_state; -+ -+ /* target handle id of ALSA driver */ -+ int handle_id; -+ -+ /* data buffer */ -+ char *buffer[XF_BUF_POOL_SIZE]; -+ -+ /* size of each allocated data buffer */ -+ int buf_bytes; -+ -+ /* data index of buffer */ -+ int buf_idx; -+ -+ /* queue index of buffer */ -+ int buf_queue; -+ -+ /* HW index in bytes */ -+ int hw_idx; -+ -+ /* number of bytes in a period */ -+ int period_bytes; -+ -+ /* substream runtime object */ -+ struct snd_pcm_substream *substream; -+ -+ /* indirect PCM data transfer */ -+ struct snd_pcm_indirect pcm_indirect; -+ -+ /* spinlock data */ -+ spinlock_t lock; -+ -+ /* runtime error indicator */ -+ int runtime_err; -+}; -+ -+/** \struct snd_adsp_playback -+ * \brief Structure stores data for playback function -+ */ -+struct snd_adsp_playback { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* Renderer component data */ -+ struct xf_adsp_renderer *renderer; -+ -+ /* Equalizer component data */ -+ struct xf_adsp_equalizer *equalizer; -+ -+ /* Renderer component state */ -+ int rdr_state; -+ -+ /* Equalizer component state */ -+ int eqz_state; -+}; -+ -+/** \struct snd_adsp_record -+ * \brief Structure stores data for record function -+ */ -+struct snd_adsp_record { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* Capture component data */ -+ struct xf_adsp_capture *capture; -+ -+ /* Equalizer component data */ -+ struct xf_adsp_equalizer *equalizer; -+ -+ /* Capture component state */ -+ int cap_state; -+ -+ /* Equalizer component state */ -+ int eqz_state; -+}; -+ -+/** \struct snd_adsp_tdm_playback -+ * \brief Structure stores data for TDM playback function -+ */ -+struct snd_adsp_tdm_playback { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* TDM Renderer component data */ -+ struct xf_adsp_tdm_renderer *tdm_renderer; -+ -+ /* TDM Renderer component state */ -+ int state; -+}; -+ -+/** \struct snd_adsp_tdm_record -+ * \brief Structure stores data for TDM record function -+ */ -+struct snd_adsp_tdm_record { -+ /* base information of stream */ -+ struct snd_adsp_base_info base; -+ -+ /* TDM Capture component data */ -+ struct xf_adsp_tdm_capture *tdm_capture; -+ -+ /* TDM Capture component state */ -+ int state; -+}; -+ -+/** \struct snd_adsp_card -+ * \brief Structure stores data for ALSA sound card -+ */ -+struct snd_adsp_card { -+ /* playback data */ -+ struct snd_adsp_playback *playback[MAX_DAI_IDX - 1]; -+ -+ /* record data */ -+ struct snd_adsp_record *record[MAX_DAI_IDX - 1]; -+ -+ /* TDM playback data */ -+ struct snd_adsp_tdm_playback *tdm_playback; -+ -+ /* TDM record data */ -+ struct snd_adsp_tdm_record *tdm_record; -+ -+ /* Structure contains params information for control */ -+ struct snd_adsp_control ctr_if; -+}; -+ -+/** HW configuration of ALSA ADSP card for Renderer/Capture */ -+static struct snd_pcm_hardware snd_pcm_adsp_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ -+ | SNDRV_PCM_INFO_RESUME -+ | SNDRV_PCM_INFO_BLOCK_TRANSFER -+ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = SND_ADSP_PCM_WIDTHS, -+ .rates = SND_ADSP_SAMPLE_RATES, -+ .rate_min = 32000, -+ .rate_max = 48000, -+ .channels_min = MIN_CHANNEL, -+ .channels_max = MAX_CHANNEL, -+ -+ /* maximum buffer size in bytes */ -+ .buffer_bytes_max = MAX_BUFFER_BYTES, -+ -+ /* minimum size of the periods (frame) in bytes */ -+ .period_bytes_min = MIN_BUF_SIZE, -+ -+ /* maximum size of the periods (frame) in bytes */ -+ .period_bytes_max = MAX_BUF_SIZE, -+ -+ /* minimum periods (frames) in a buffer */ -+ .periods_min = MIN_PERIOD, -+ -+ /* maximum periods (frames) in a buffer */ -+ .periods_max = MAX_PERIOD, -+}; -+ -+/* HW configuration of ALSA ADSP card for TDM */ -+static struct snd_pcm_hardware snd_pcm_adsp_tdm_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED /* PRQA S 1053 14 */ -+ | SNDRV_PCM_INFO_RESUME -+ | SNDRV_PCM_INFO_BLOCK_TRANSFER -+ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = SND_ADSP_PCM_WIDTHS, -+ .rates = SND_ADSP_SAMPLE_RATES, -+ .rate_min = 32000, -+ .rate_max = 48000, -+ .channels_min = TDM_MIN_CHANNEL, -+ .channels_max = TDM_MAX_CHANNEL, -+ -+ /* maximum buffer size in bytes */ -+ .buffer_bytes_max = TDM_MAX_BUFFER_BYTES, -+ -+ /* minimum size of the periods (frame) in bytes */ -+ .period_bytes_min = TDM_MIN_BUF_SIZE, -+ -+ /* maximum size of the periods (frame) in bytes */ -+ .period_bytes_max = TDM_MAX_BUF_SIZE, -+ -+ /* minimum periods (frames) in a buffer */ -+ .periods_min = TDM_MIN_PERIOD, -+ -+ /* maximum periods (frames) in a buffer */ -+ .periods_max = TDM_MAX_PERIOD, -+}; -+ -+/******************************************************************* -+ * function declaration -+ * ****************************************************************/ -+ -+static int snd_adsp_rdr_empty_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_rdr_fill_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_cap_empty_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_cap_fill_buf_done -+ (void *data, int opcode, int length, char *buffer); -+static int snd_adsp_get_dai_id_from_substream -+ (struct snd_pcm_substream *substream); -+static void *snd_adsp_get_drvdata_from_substream -+ (struct snd_pcm_substream *substream); -+static struct snd_adsp_base_info *snd_adsp_get_base_from_substream -+ (struct snd_pcm_substream *substream); -+static struct snd_adsp_base_info *snd_adsp_get_base_from_hrt -+ (struct hrtimer *hrt); -+static enum hrtimer_restart snd_adsp_hrtimer_func -+ (struct hrtimer *hrt); -+static int snd_adsp_playback_init -+ (struct snd_adsp_playback **data, int eqz_flag, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_record_init -+ (struct snd_adsp_record **data, int eqz_flag, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_playback_prepare -+ (struct snd_adsp_playback *playback, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_record_prepare -+ (struct snd_adsp_record *record, struct snd_pcm_substream *substream); -+static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback); -+static int snd_adsp_record_deinit(struct snd_adsp_record *record); -+static int snd_adsp_tdm_playback_init -+ (struct snd_adsp_tdm_playback **data, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_record_init -+ (struct snd_adsp_tdm_record **data, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_playback_prepare -+ (struct snd_adsp_tdm_playback *tdm_playback, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_record_prepare -+ (struct snd_adsp_tdm_record *tdm_record, -+ struct snd_pcm_substream *substream); -+static int snd_adsp_tdm_playback_deinit -+ (struct snd_adsp_tdm_playback *tdm_playback); -+static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record); -+static int snd_adsp_pcm_open(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_close(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_hw_params -+ (struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params); -+static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx); -+static snd_pcm_uframes_t snd_adsp_pcm_pointer -+ (struct snd_pcm_substream *substream); -+static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream); -+static void snd_adsp_pcm_transfer -+ (struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes); -+static int snd_adsp_control_volume_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_volume_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_volume_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_eqz_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_switch_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_switch_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_sample_rate_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_sample_rate_info -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -+static int snd_adsp_control_sample_rate_get -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static int snd_adsp_control_eqz_switch_put -+ (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -+static void snd_adsp_get_eqz_params_from_control -+ (struct xf_adsp_equalizer_params *eqz_params, -+ struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag); -+static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime); -+static int snd_adsp_probe(struct platform_device *pdev); -+static int snd_adsp_remove(struct platform_device *pdev); -+ -+/******************************************************************* -+ * callback function of ADSP control interface -+ * ****************************************************************/ -+/** ************************************************************************** -+ * \brief event handler callback to notify error from ADSP -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_event_handler(void *data) -+{ -+ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; -+ -+ if (base != NULL) -+ base->runtime_err = TRUE; -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief empty buf done callback for playback/TDM playback functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_rdr_empty_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; -+ -+ if (base != NULL) { -+ spin_lock(&base->lock); -+ -+ base->buf_queue++; -+ base->hw_idx += length; /* increase the DMA buffer index */ -+ -+ spin_unlock(&base->lock); -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief fill buf done callback for playback/TDM playback functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_rdr_fill_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief empty buf done callback for record/TDM record functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_cap_empty_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief fill buf done callback for record/TDM record functions -+ * -+ * \param[in] data Pointer to ADSP ALSA sound card -+ * \param[in] opcode Opcode of message -+ * \param[in] length Length of data buffer -+ * \param[in] buffer Pointer to data buffer -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_cap_fill_buf_done -+ (void *data, int opcode, int length, char *buffer) -+{ -+ struct snd_adsp_base_info *base = (struct snd_adsp_base_info *)data; -+ -+ if (base != NULL) { -+ spin_lock(&base->lock); -+ -+ base->buf_queue++; -+ base->hw_idx += length; /* increase the DMA buffer index */ -+ -+ spin_unlock(&base->lock); -+ } -+ -+ return 0; -+} -+ -+/** callback functions for playback/TDM playback */ -+static struct xf_callback_func rdr_callbacks = /* PRQA S 3218 */ -+{ -+ .empty_buf_done = &snd_adsp_rdr_empty_buf_done, /* PRQA S 1053 2 */ -+ .fill_buf_done = &snd_adsp_rdr_fill_buf_done, -+ .event_handler = &snd_adsp_event_handler -+}; -+ -+/** callback functions for record/TDM record */ -+static struct xf_callback_func cap_callbacks = /* PRQA S 3218 */ -+{ -+ .empty_buf_done = &snd_adsp_cap_empty_buf_done, /* PRQA S 1053 2 */ -+ .fill_buf_done = &snd_adsp_cap_fill_buf_done, -+ .event_handler = &snd_adsp_event_handler -+}; -+ -+/******************************************************************* -+ * helper functions to get some internal data -+ * ****************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Get current index of CPU DAI from runtime data of substream -+ * -+ * \param[in] substream Pointer to PCM stream data -+ * \retval id Index of current CPU DAI -+ *****************************************************************************/ -+static int snd_adsp_get_dai_id_from_substream -+ (struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; -+ return rtd->cpu_dai->id; -+} -+ -+/** ************************************************************************** -+ * \brief Get ADSP ALSA driver's data from runtime data of substream -+ * -+ * \param[in] substream Pointer to PCM stream data -+ * \retval pointer Pointer to driver's data -+ *****************************************************************************/ -+static void *snd_adsp_get_drvdata_from_substream -+ (struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ rtd = (struct snd_soc_pcm_runtime *)substream->private_data; -+ return snd_soc_dai_get_drvdata(rtd->cpu_dai); -+} -+ -+/** ************************************************************************** -+ * \brief Get base's data of playback/record from runtime data of substream -+ * -+ * \param[in] substream Pointer to PCM stream data -+ * \retval pointer Pointer to playback/record's base data -+ *****************************************************************************/ -+static struct snd_adsp_base_info *snd_adsp_get_base_from_substream -+ (struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ struct snd_adsp_base_info *base; -+ int dai_idx; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ -+ /* get DAI index of substream */ -+ dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ -+ /* get base data of the substream */ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ base = (adsp_card->playback[dai_idx] == NULL) ? -+ NULL : &adsp_card->playback[dai_idx]->base; -+ } else { -+ base = (adsp_card->record[dai_idx] == NULL) ? -+ NULL : &adsp_card->record[dai_idx]->base; -+ } -+ } else { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ base = (adsp_card->tdm_playback == NULL) ? -+ NULL : &adsp_card->tdm_playback->base; -+ } else { -+ base = (adsp_card->tdm_record == NULL) ? -+ NULL : &adsp_card->tdm_record->base; -+ } -+ } -+ -+ return base; -+} -+ -+/** *************************************************************************** -+ * \brief Get playback/record/TDM playback/TDM record's base data -+ * from hr timer data -+ * -+ * \param[in] hrt Pointer to hr timer data -+ * \retval pointer Pointer to playback/record's base data -+ *****************************************************************************/ -+static struct snd_adsp_base_info *snd_adsp_get_base_from_hrt -+ (struct hrtimer *hrt) -+{ -+ return (struct snd_adsp_base_info *)hrt; -+} -+ -+/***************************************************************************** -+ * hrtimer interrupt function -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Interrupt function of high resolution timer -+ * -+ * \param[in] hrt Pointer to hr timer data -+ * \retval HRTIMER_RESTART Restart the timer after expire time -+ *****************************************************************************/ -+static enum hrtimer_restart snd_adsp_hrtimer_func(struct hrtimer *hrt) -+{ -+ struct snd_adsp_base_info *base = snd_adsp_get_base_from_hrt(hrt); -+ -+ spin_lock(&base->lock); -+ if (base->hw_idx != 0) { -+ /* update PCM status for the next period */ -+ spin_unlock(&base->lock); -+ snd_pcm_period_elapsed(base->substream); -+ } else { -+ spin_unlock(&base->lock); -+ } -+ -+ hrtimer_forward_now(hrt, base->ktime); -+ -+ return HRTIMER_RESTART; -+} -+ -+/***************************************************************************** -+ * internal functions to manage playback and record functions -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Initialize playback data -+ * -+ * \param[out] playback_data Pointer to store playback data -+ * \param[in] eqz_flag Flag to indicate equalizer usage -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize playback data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_playback_init -+ (struct snd_adsp_playback **playback_data, int eqz_flag, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_playback *playback; -+ -+ /* allocate memory for playback data */ -+ playback = kmalloc(sizeof(struct snd_adsp_playback), GFP_KERNEL); -+ if (playback == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(playback, 0, sizeof(struct snd_adsp_playback)); -+ -+ /* save the playback data */ -+ *playback_data = playback; -+ -+ /* set handle state as NULL state */ -+ playback->rdr_state = XF_HANDLE_NULL; -+ playback->eqz_state = XF_HANDLE_NULL; -+ playback->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register renderer component */ -+ if (xf_adsp_renderer_create(&playback->renderer, &rdr_callbacks, -+ (void *)&playback->base) < 0) -+ return -EINVAL; -+ -+ /* mark renderer component created */ -+ playback->rdr_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as renderer ID */ -+ playback->base.handle_id = playback->renderer->handle_id; -+ -+ if (eqz_flag == EQZ_ON) { -+ /* create equalizer component when equalizer is used */ -+ if (xf_adsp_equalizer_create(&playback->equalizer, -+ &rdr_callbacks, -+ (void *)&playback->base) < 0) -+ return -EINVAL; -+ -+ /* mark equalizer component created */ -+ playback->eqz_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as equalizer ID */ -+ playback->base.handle_id = playback->equalizer->handle_id; -+ } -+ -+ /* init lock */ -+ spin_lock_init(&playback->base.lock); -+ -+ /* save the substream data */ -+ playback->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&playback->base.hrtimer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ playback->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ playback->base.hrt_state = XF_HANDLE_CREATED; -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Initialize record data -+ * -+ * \param[out] record_data Pointer to store record data -+ * \param[in] eqz_flag Flag to indicate equalizer usage -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize record data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_record_init(struct snd_adsp_record **record_data, -+ int eqz_flag, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_record *record; -+ -+ /* allocate memory for record data */ -+ record = kmalloc(sizeof(struct snd_adsp_record), GFP_KERNEL); -+ if (record == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(record, 0, sizeof(struct snd_adsp_record)); -+ -+ /* save the record data */ -+ *record_data = record; -+ -+ /* set handle state as NULL state */ -+ record->cap_state = XF_HANDLE_NULL; -+ record->eqz_state = XF_HANDLE_NULL; -+ record->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register capture component */ -+ if (xf_adsp_capture_create(&record->capture, -+ &cap_callbacks, -+ (void *)&record->base) < 0) -+ return -EINVAL; -+ -+ /* mark capture component created */ -+ record->cap_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as capture ID */ -+ record->base.handle_id = record->capture->handle_id; -+ -+ /* create equalizer component in case of it being used */ -+ if (eqz_flag == EQZ_ON) { -+ if (xf_adsp_equalizer_create(&record->equalizer, -+ &cap_callbacks, -+ (void *)&record->base) < 0) -+ return -EINVAL; -+ -+ /* mark equalizer component created */ -+ record->eqz_state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as equalizer ID */ -+ record->base.handle_id = record->equalizer->handle_id; -+ } -+ -+ /* init lock */ -+ spin_lock_init(&record->base.lock); -+ -+ /* save the substream data */ -+ record->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&record->base.hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ record->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ record->base.hrt_state = XF_HANDLE_CREATED; -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare playback function -+ * -+ * \param[out] playback Pointer to playback data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_playback_prepare(struct snd_adsp_playback *playback, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, hw_buffer_size; -+ int out_rate; -+ struct snd_adsp_control *ctr_if; -+ struct snd_pcm_runtime *runtime; -+ struct xf_adsp_renderer *renderer; -+ struct xf_adsp_equalizer *equalizer; -+ struct snd_adsp_base_info *base; -+ int i; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ ctr_if = &adsp_card->ctr_if; -+ runtime = substream->runtime; -+ renderer = playback->renderer; -+ equalizer = playback->equalizer; -+ base = &playback->base; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ ch = runtime->channels; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ vol_rate = ctr_if->vol_rate[DIRECT_PLAYBACK][dai_idx]; -+ out_rate = ctr_if->sample_rate[DIRECT_PLAYBACK][dai_idx]; -+ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ -+ if (pcm_width == 16) -+ base->buf_bytes = base->period_bytes; -+ else -+ base->buf_bytes = (base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = hw_buffer_size; -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ /* it should equal to a period size in bytes */ -+ base->pcm_indirect.hw_queue_size = base->period_bytes; -+ -+ /* set parameters when Renderer is not ready */ -+ if (COMPONENT_IS_READY(playback->rdr_state) == FALSE) { -+ struct xf_adsp_renderer_params *params = &renderer->params; -+ -+ /* apply renderer parameters */ -+ params->in_rate = fs; -+ params->channel = ch; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ if (ctr_if->mix_usage == SECOND_RUN) -+ params->mix_ctrl = ctr_if->mix_usage; -+ else -+ params->mix_ctrl = MIX_UNUSED; -+ -+ /* set flow as ADSP->PDMA0->SRC0->PDMA1->SSI0 */ -+ params->dev1 = SRC0; -+ params->dev2 = SSI00; -+ params->dma1 = PDMA_CH00; -+ params->dma2 = PDMA_CH01; -+ -+ /* when MIX is enabled, change to DMAC transfer type to save */ -+ /* hw FIFO */ -+ if (MIX_ENABLED(params->mix_ctrl) == TRUE) -+ params->dma1 = ADMAC_CH01; -+ -+ /* set volume rate if it is set by user or default value */ -+ /* is 100% */ -+ if (vol_rate >= 0) -+ params->vol_rate = vol_rate; -+ else -+ params->vol_rate = (1 << 20); -+ -+ /* set output channel if it is set by user */ -+ if (ctr_if->rdr_out_ch[dai_idx] >= MONAURAL) -+ params->out_channel = ctr_if->rdr_out_ch[dai_idx]; -+ else -+ params->out_channel = params->channel; -+ -+ /* set sample rate output if it is set by user */ -+ if (out_rate >= 0) -+ params->out_rate = out_rate; -+ -+ /* set parameters to ADSP Renderer plugin */ -+ if (xf_adsp_renderer_set_params(renderer) != 0) -+ return -EINVAL; -+ -+ /* allocate buffer pool to prepare the execution */ -+ renderer->buf_pool = xf_adsp_allocate_mem_pool( -+ XF_BUF_POOL_SIZE, base->buf_bytes); -+ if (IS_ERR(renderer->buf_pool)) /* PRQA S 306*/ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = xf_adsp_get_data_from_pool( -+ renderer->buf_pool, i); -+ base->buf_queue++; -+ memset(base->buffer[i], 0, base->buf_bytes); -+ } -+ -+ /* mark Renderer ready */ -+ playback->rdr_state |= XF_HANDLE_READY; -+ -+ /* set parameters for Equalizer if it is used */ -+ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { -+ /* apply Equalizer parameter setting */ -+ equalizer->params.channel = ch; -+ equalizer->params.pcm_width = pcm_width; -+ equalizer->params.rate = fs; -+ -+ /* get equalizer parameters from control interface */ -+ /* data */ -+ snd_adsp_get_eqz_params_from_control( -+ &equalizer->params, -+ &ctr_if->eqz_params[DIRECT_PLAYBACK][dai_idx], -+ true); -+ -+ /* set parameters to Equalizer plugin */ -+ if (xf_adsp_equalizer_set_params(equalizer) != 0) -+ return -EINVAL; -+ -+ /* route Equalizer to Renderer */ -+ if (xf_adsp_route(equalizer->handle_id, -+ renderer->handle_id, -+ XF_BUF_POOL_SIZE, -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ /* mark Equalizer ready */ -+ playback->eqz_state |= XF_HANDLE_READY; -+ -+ /* prepare data before start PCM */ -+ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ /* send buffer to plugin to kick */ -+ /* init-processing */ -+ if (xf_adsp_empty_this_buffer(base->handle_id, -+ base->buffer[i], base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ } -+ } else { -+ /* send zero buffer to plugin to kick */ -+ /* init-processing */ -+ if (xf_adsp_empty_this_buffer(base->handle_id, -+ base->buffer[0], base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ } -+ -+ /* wait until all the buffer have been consummed */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ /* reset HW index */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare record function -+ * -+ * \param[out] record Pointer to record data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_record_prepare(struct snd_adsp_record *record, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ int dai_idx, pcm_width, ch, fs, frame_size, vol_rate, in_rate; -+ int hw_buffer_size, hw_queue_size; -+ struct snd_adsp_control *ctr_if; -+ struct snd_pcm_runtime *runtime; -+ struct xf_adsp_capture *capture; -+ struct xf_adsp_equalizer *equalizer; -+ struct snd_adsp_base_info *base; -+ int i; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ ctr_if = &adsp_card->ctr_if; -+ runtime = substream->runtime; -+ capture = record->capture; -+ equalizer = record->equalizer; -+ base = &record->base; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ ch = runtime->channels; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ vol_rate = ctr_if->vol_rate[DIRECT_CAPTURE][dai_idx]; -+ in_rate = ctr_if->sample_rate[DIRECT_CAPTURE][dai_idx]; -+ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ /* total size of allocated buffers */ -+ hw_queue_size = base->period_bytes * XF_BUF_POOL_SIZE; -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ -+ if (pcm_width == 16) -+ base->buf_bytes = base->period_bytes; -+ else -+ base->buf_bytes = ((base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) / BYTES_PER_SAMPLE(S24_LE)); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = hw_buffer_size; -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ base->pcm_indirect.hw_queue_size = hw_queue_size; -+ -+ /* prepare parameters to set to Capture plugin when it is not yet */ -+ /* ready */ -+ if (COMPONENT_IS_READY(record->cap_state) == FALSE) { -+ struct xf_adsp_capture_params *params = &capture->params; -+ -+ /* apply capture parameters */ -+ params->out_rate = fs; -+ params->channel = ch; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ params->dev1 = SRC0; -+ params->dev2 = SSI10; -+ params->dma1 = PDMA_CH00; -+ params->dma2 = PDMA_CH01; -+ -+ /* set volume rate if it is set by user or default volume as */ -+ /* 100% */ -+ if (vol_rate >= 0) -+ params->vol_rate = vol_rate; -+ else -+ params->vol_rate = (1 << 20); -+ -+ /* set sample rate input if it is set by user */ -+ if (in_rate >= 0) -+ params->in_rate = in_rate; -+ -+ /* allocate buffer pool to prepare the execution */ -+ capture->buf_pool = xf_adsp_allocate_mem_pool(XF_BUF_POOL_SIZE, -+ base->buf_bytes); -+ if (IS_ERR(capture->buf_pool)) /* PRQA S 306 */ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = xf_adsp_get_data_from_pool( -+ capture->buf_pool, i); -+ base->buf_queue++; -+ } -+ -+ /* set parameters to ADSP Capture plugin */ -+ if (xf_adsp_capture_set_params(capture) != 0) -+ return -EINVAL; -+ -+ /* mark Capture ready */ -+ record->cap_state |= XF_HANDLE_READY; -+ -+ /* set parameters for Equalizer if it's used */ -+ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { -+ /* apply Equalizer parameter setting */ -+ equalizer->params.channel = ch; -+ equalizer->params.pcm_width = pcm_width; -+ equalizer->params.rate = fs; -+ -+ /* get equalizer parameter from control interface */ -+ /* data */ -+ snd_adsp_get_eqz_params_from_control( -+ &equalizer->params, -+ &ctr_if->eqz_params[DIRECT_CAPTURE][dai_idx], -+ true); -+ -+ /* set parameters to Equalizer plugin */ -+ if (xf_adsp_equalizer_set_params(equalizer) != 0) -+ return -EINVAL; -+ -+ /* route Capture to Equalizer */ -+ if (xf_adsp_route(capture->handle_id, -+ equalizer->handle_id, -+ XF_BUF_POOL_SIZE, -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ -+ /* mark Equalizer ready */ -+ record->eqz_state |= XF_HANDLE_READY; -+ } -+ -+ /* kick init process by sending a zero buffer length */ -+ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* wait until finishing initialization */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { -+ /* PRQA S 2462 1 */ /* PRQA S 2463 1 */ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ /* send buffer to plugin */ -+ if (xf_adsp_fill_this_buffer( -+ base->handle_id, -+ base->buffer[i], -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ } -+ -+ /* wait until all the buffer have been responsed */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ } -+ -+ /* reset hw data position */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize playback function -+ * -+ * \param[out] playback Pointer to playback data -+ * \retval -EINVAL Failed to deinitialize playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_playback_deinit(struct snd_adsp_playback *playback) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if playback has been created already */ -+ if (IS_VALID(playback)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(playback->rdr_state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process *//* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(playback->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool */ /* PRQA S 3200 1 */ -+ xf_adsp_free_mem_pool(playback->renderer->buf_pool); -+ -+ /* destroy Renderer */ -+ if (xf_adsp_renderer_destroy(playback->renderer) != 0) -+ ret = -EINVAL; -+ -+ playback->renderer = NULL; -+ } -+ -+ /* destroy Equalizer if it is used */ -+ if (COMPONENT_IS_CREATED(playback->eqz_state) == TRUE) { -+ if (xf_adsp_equalizer_destroy(playback->equalizer)) -+ ret = -EINVAL; -+ -+ playback->equalizer = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(playback->base.hrt_state) == TRUE) -+ hrtimer_cancel(&playback->base.hrtimer); -+ -+ /* free playback data */ -+ kfree(playback); -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize record function -+ * -+ * \param[out] record Pointer to record data -+ * \retval -EINVAL Failed to deinitialize record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_record_deinit(struct snd_adsp_record *record) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if record has been created already */ -+ if (IS_VALID(record)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(record->cap_state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process *//* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(record->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool */ /* PRQA S 3200 1 */ -+ xf_adsp_free_mem_pool(record->capture->buf_pool); -+ -+ if (xf_adsp_capture_destroy(record->capture)) -+ ret = -EINVAL; -+ -+ record->capture = NULL; -+ } -+ -+ /* destroy Equalizer if it is used */ -+ if (COMPONENT_IS_CREATED(record->eqz_state) == TRUE) { -+ if (xf_adsp_equalizer_destroy(record->equalizer) != 0) -+ ret = -EINVAL; -+ -+ record->equalizer = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(record->base.hrt_state) == TRUE) -+ hrtimer_cancel(&record->base.hrtimer); -+ -+ /* free record data */ -+ kfree(record); -+ } -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * internal functions to manage TDM playback and TDM record functions -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Initialize TDM playback data -+ * -+ * \param[out] tdm_playback_data Pointer to store TDM playback data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize TDM playback data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_playback_init( -+ struct snd_adsp_tdm_playback **tdm_playback_data, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_tdm_playback *tdm_playback; -+ -+ /* allocate memory for TDM playback data */ -+ tdm_playback = kmalloc(sizeof(struct snd_adsp_tdm_playback), -+ GFP_KERNEL); -+ if (tdm_playback == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(tdm_playback, 0, sizeof(struct snd_adsp_tdm_playback)); -+ -+ /* save the TDM playback data */ -+ *tdm_playback_data = tdm_playback; -+ -+ /* set handle state as NULL state */ -+ tdm_playback->state = XF_HANDLE_NULL; -+ tdm_playback->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register TDM renderer component */ -+ if (xf_adsp_tdm_renderer_create(&tdm_playback->tdm_renderer, -+ &rdr_callbacks, -+ (void *)&tdm_playback->base) < 0) -+ return -EINVAL; -+ -+ /* mark TDM renderer component created */ -+ tdm_playback->state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as TDM renderer ID */ -+ tdm_playback->base.handle_id = tdm_playback->tdm_renderer->handle_id; -+ -+ /* init lock */ -+ spin_lock_init(&tdm_playback->base.lock); -+ -+ /* save the substream data */ -+ tdm_playback->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&tdm_playback->base.hrtimer, -+ CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ tdm_playback->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ tdm_playback->base.hrt_state = XF_HANDLE_CREATED; -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Initialize TDM record data -+ * -+ * \param[out] tdm_record_data Pointer to store TDM record data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to initialize TDM record data -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_record_init( -+ struct snd_adsp_tdm_record **tdm_record_data, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_tdm_record *tdm_record; -+ -+ /* allocate memory for TDM record data */ -+ tdm_record = kmalloc(sizeof(struct snd_adsp_tdm_record), GFP_KERNEL); -+ if (tdm_record == NULL) -+ return -EINVAL; -+ -+ /* init params */ -+ memset(tdm_record, 0, sizeof(struct snd_adsp_tdm_record)); -+ -+ /* save the TDM record data */ -+ *tdm_record_data = tdm_record; -+ -+ /* set handle state as NULL state */ -+ tdm_record->state = XF_HANDLE_NULL; -+ tdm_record->base.hrt_state = XF_HANDLE_NULL; -+ -+ /* register TDM Capture component */ -+ if (xf_adsp_tdm_capture_create(&tdm_record->tdm_capture, -+ &cap_callbacks, -+ (void *)&tdm_record->base) != 0) -+ return -EINVAL; -+ -+ /* mark TDM capture component created */ -+ tdm_record->state = XF_HANDLE_CREATED; -+ -+ /* set target handle ID as TDM capture ID */ -+ tdm_record->base.handle_id = tdm_record->tdm_capture->handle_id; -+ -+ /* init lock */ -+ spin_lock_init(&tdm_record->base.lock); -+ -+ /* save the substream data */ -+ tdm_record->base.substream = substream; -+ -+ /* init high resolution timer for updating hw status */ -+ hrtimer_init(&tdm_record->base.hrtimer, -+ CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ -+ /* PRQA S 0563 1 */ -+ tdm_record->base.hrtimer.function = &snd_adsp_hrtimer_func; -+ tdm_record->base.hrt_state = XF_HANDLE_CREATED; -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare TDM playback function -+ * -+ * \param[out] tdm_playback Pointer to TDM playback data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare TDM playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_playback_prepare( -+ struct snd_adsp_tdm_playback *tdm_playback, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card; -+ struct snd_adsp_control *ctr_if; -+ struct snd_pcm_runtime *runtime; -+ struct xf_adsp_tdm_renderer *tdm_renderer; -+ struct snd_adsp_base_info *base; -+ int i; -+ int pcm_width, ch_mode, fs, frame_size, hw_buffer_size; -+ -+ adsp_card = snd_adsp_get_drvdata_from_substream(substream); -+ ctr_if = &adsp_card->ctr_if; -+ runtime = substream->runtime; -+ tdm_renderer = tdm_playback->tdm_renderer; -+ base = &tdm_playback->base; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ ch_mode = (runtime->channels == 8) ? -+ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; -+ hw_buffer_size = snd_pcm_lib_buffer_bytes(substream); -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ -+ if (pcm_width == 16) -+ base->buf_bytes = base->period_bytes; -+ else -+ base->buf_bytes = ((base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) / -+ BYTES_PER_SAMPLE(S24_LE)); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = hw_buffer_size; -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ /* it should equal to a period size in bytes */ -+ base->pcm_indirect.hw_queue_size = base->period_bytes; -+ -+ /* prepare parameters to set to TDM playback as it is not ready */ -+ if (COMPONENT_IS_READY(tdm_playback->state) == FALSE) { -+ struct xf_adsp_tdm_renderer_params *params = -+ &tdm_renderer->params; -+ -+ /* apply renderer parameters */ -+ params->in_rate = fs; -+ params->ch_mode = ch_mode; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ /* setting Audio device indexes */ -+ params->dma1 = ADMAC_CH00; /* use DMAC for transfer data */ -+ params->dma2 = PDMA_CH03; -+ params->dev1 = SRC1; -+ params->dev2 = SSI30; /* set SSI index to SSI30 */ -+ -+ /* set volume rate if it is set by user or default value as */ -+ /* 100% */ -+ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] >= 0) -+ ? ctr_if->tdm_vol_rate[DIRECT_PLAYBACK] : (1 << 20); -+ -+ /* set output sampling rate if it is set by user */ -+ if (ctr_if->tdm_sample_rate[DIRECT_PLAYBACK] >= 0) -+ params->out_rate = -+ ctr_if->tdm_sample_rate[DIRECT_PLAYBACK]; -+ -+ /* set parameters to ADSP TDM Renderer plugin */ -+ if (xf_adsp_tdm_renderer_set_params(tdm_renderer) != 0) -+ return -EINVAL; -+ -+ /* allocate buffer pool to prepare the execution */ -+ tdm_renderer->buf_pool = -+ xf_adsp_allocate_mem_pool(XF_BUF_POOL_SIZE, -+ base->buf_bytes); -+ if (IS_ERR(tdm_renderer->buf_pool)) /* PRQA S 306*/ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = -+ xf_adsp_get_data_from_pool( -+ tdm_renderer->buf_pool, i); -+ base->buf_queue++; -+ } -+ -+ /* mark TDM Renderer created */ -+ tdm_playback->state |= XF_HANDLE_READY; -+ -+ /* send zero buffer to plugin to kick init-processing */ -+ memset(base->buffer[0], 0, base->buf_bytes); -+ if (xf_adsp_empty_this_buffer(base->handle_id, base->buffer[0], -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* wait until all the buffer have been consummed */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ /* reset HW index */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Prepare TDM record function -+ * -+ * \param[out] tdm_record Pointer to TDM record data -+ * \param[in] substream Pointer to substream data -+ * \retval -EINVAL Failed to prepare TDM record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_record_prepare( -+ struct snd_adsp_tdm_record *tdm_record, -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct xf_adsp_tdm_capture *tdm_capture = tdm_record->tdm_capture; -+ struct snd_adsp_base_info *base = &tdm_record->base; -+ int i; -+ int pcm_width, ch_mode, fs, frame_size; -+ -+ /* runtime parameter */ -+ fs = runtime->rate; -+ ch_mode = (runtime->channels == 8) ? -+ XA_TDM_RDR_CHANNEL_MODE_1X8 : XA_TDM_RDR_CHANNEL_MODE_1X6; -+ pcm_width = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? 16 : 24; -+ frame_size = runtime->period_size; -+ -+ /* get number of bytes in a period */ -+ base->period_bytes = snd_pcm_lib_period_bytes(substream); -+ base->buf_bytes = (pcm_width == 16) ? base->period_bytes : -+ ((base->period_bytes * -+ BYTES_PER_SAMPLE(S24_3LE)) -+ / BYTES_PER_SAMPLE(S24_LE)); -+ -+ /* pcm indirect configuration */ -+ base->pcm_indirect.hw_buffer_size = -+ snd_pcm_lib_buffer_bytes(substream); -+ base->pcm_indirect.sw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ /* total size of allocated buffers */ -+ base->pcm_indirect.hw_queue_size = base->period_bytes * -+ XF_BUF_POOL_SIZE; -+ -+ /* prepare parameters to set to TDM Capture as it is not yet ready */ -+ if (COMPONENT_IS_READY(tdm_record->state) == FALSE) { -+ struct xf_adsp_tdm_capture_params *params = -+ &tdm_capture->params; -+ -+ /* apply capture parameters */ -+ params->out_rate = fs; -+ params->ch_mode = ch_mode; -+ params->pcm_width = pcm_width; -+ params->frame_size = frame_size; -+ -+ /* setting Audio device indexes */ -+ params->dma1 = PDMA_CH00; -+ params->dma2 = PDMA_CH01; -+ params->dev1 = SRC0; -+ params->dev2 = SSI40; /* set input device is SSI40 */ -+ -+ /* set volume rate if it is set by user or default value as */ -+ /* 100% */ -+ params->vol_rate = (ctr_if->tdm_vol_rate[DIRECT_CAPTURE] >= 0) -+ ? ctr_if->tdm_vol_rate[DIRECT_CAPTURE] : (1 << 20); -+ -+ /* set input rate if it is set by user */ -+ if (ctr_if->tdm_sample_rate[DIRECT_CAPTURE] >= 0) { -+ params->in_rate = -+ ctr_if->tdm_sample_rate[DIRECT_CAPTURE]; -+ } -+ -+ /* allocate buffer pool to prepare the execution */ -+ tdm_capture->buf_pool = xf_adsp_allocate_mem_pool( -+ XF_BUF_POOL_SIZE, base->buf_bytes); -+ if (IS_ERR(tdm_capture->buf_pool)) /* PRQA S 306 */ -+ return -EINVAL; -+ -+ for (i = 0; i < XF_BUF_POOL_SIZE; i++) { -+ base->buffer[i] = xf_adsp_get_data_from_pool( -+ tdm_capture->buf_pool, i); -+ base->buf_queue++; -+ } -+ -+ /* set parameters to ADSP TDM Capture plugin */ -+ if (xf_adsp_tdm_capture_set_params(tdm_capture) != 0) -+ return -EINVAL; -+ -+ /* mark TDM Capture ready */ -+ tdm_record->state |= XF_HANDLE_READY; -+ -+ /* kick init process by sending a zero buffer length */ -+ xf_adsp_fill_this_buffer(base->handle_id, base->buffer[0], 0); -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* wait until finishing initialization */ -+ while (base->buf_queue != XF_BUF_POOL_SIZE) { -+ schedule_timeout_interruptible(2); -+ if (signal_pending(current)) -+ break; -+ -+ /* check the error from initialization */ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ } -+ -+ /* reset hw data position */ -+ base->hw_idx = 0; -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize TDM playback function -+ * -+ * \param[out] tdm_playback Pointer to TDM playback data -+ * \retval -EINVAL Failed to deinitialize TDM playback function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_playback_deinit( -+ struct snd_adsp_tdm_playback *tdm_playback) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if TDM playback has been created */ -+ /* already */ -+ if (IS_VALID(tdm_playback)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(tdm_playback->state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process */ -+ /* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(tdm_playback->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool *//* PRQA S 3200 2 */ -+ xf_adsp_free_mem_pool( -+ tdm_playback->tdm_renderer->buf_pool); -+ -+ /* destroy TDM Renderer component */ -+ if (xf_adsp_tdm_renderer_destroy( -+ tdm_playback->tdm_renderer) != 0) -+ ret = -EINVAL; -+ -+ tdm_playback->tdm_renderer = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(tdm_playback->base.hrt_state) == TRUE) -+ hrtimer_cancel(&tdm_playback->base.hrtimer); -+ -+ /* free playback data */ -+ kfree(tdm_playback); -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Deinitialize TDM record function -+ * -+ * \param[out] tdm_record Pointer to TDM record data -+ * \retval -EINVAL Failed to deinitialize TDM record function -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_tdm_record_deinit(struct snd_adsp_tdm_record *tdm_record) -+{ -+ int ret = 0; -+ -+ /* perform de-initialization if TDM record has been created already */ -+ if (IS_VALID(tdm_record)) { -+ /* perform completion process */ -+ if (COMPONENT_IS_CREATED(tdm_record->state) == TRUE) { -+ /* send buffer with zero length to plugin for */ -+ /* completion process */ -+ /* PRQA S 3200 2 */ -+ xf_adsp_empty_this_buffer(tdm_record->base.handle_id, -+ NULL, 0); -+ -+ /* free buffer pool *//* PRQA S 3200 2 */ -+ xf_adsp_free_mem_pool( -+ tdm_record->tdm_capture->buf_pool); -+ -+ /* destroy TDM Capture component */ -+ if (xf_adsp_tdm_capture_destroy( -+ tdm_record->tdm_capture) != 0) -+ ret = -EINVAL; -+ -+ tdm_record->tdm_capture = NULL; -+ } -+ -+ /* canncel timer interrupt */ -+ if (COMPONENT_IS_CREATED(tdm_record->base.hrt_state) == TRUE) -+ hrtimer_cancel(&tdm_record->base.hrtimer); -+ -+ /* free record data */ -+ kfree(tdm_record); -+ } -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * callback functions of ADSP ALSA driver -+ * ***************************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Open a playback/TDM playback or record/TDM record stream -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_open(struct snd_pcm_substream *substream) -+{ -+ /* get ADSP soundcard and CPU DAI index */ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ /* register data for playback/record functions */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* perform playback initialization */ -+ if (snd_adsp_playback_init( -+ &adsp_card->playback[dai_idx], -+ adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][dai_idx], -+ substream) < 0) { -+ /* perform playback de-initialization when */ -+ /* the initialization fails */ -+ snd_adsp_playback_deinit( -+ adsp_card->playback[dai_idx]); -+ adsp_card->playback[dai_idx] = NULL; -+ return -EINVAL; -+ } -+ } else { -+ /* perform record initialization */ -+ if (snd_adsp_record_init(&adsp_card->record[dai_idx], -+ adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][dai_idx], -+ substream) < 0) { -+ /* perform record de-initialization when the */ -+ /* initialization fails */ -+ snd_adsp_record_deinit( -+ adsp_card->record[dai_idx]); -+ adsp_card->record[dai_idx] = NULL; -+ return -EINVAL; -+ } -+ } -+ -+ /* save the hardware parameters */ -+ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_hw); -+ -+ /* each period has a frame size */ -+ snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ FRAME_SIZE); -+ } else { -+ /* register data for TDM playback/record functions */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* perform TDM playback initialization */ -+ if (snd_adsp_tdm_playback_init( -+ &adsp_card->tdm_playback, substream) < 0) { -+ /* perform TDM playback de-initialization */ -+ /* when the initialization fails */ -+ snd_adsp_tdm_playback_deinit( -+ adsp_card->tdm_playback); -+ adsp_card->tdm_playback = NULL; -+ return -EINVAL; -+ } -+ } else { -+ /* perform TDM record initialization */ -+ if (snd_adsp_tdm_record_init(&adsp_card->tdm_record, -+ substream) < 0) { -+ /* perform TDM record de-initialization */ -+ /* when the initialization fails */ -+ snd_adsp_tdm_record_deinit( -+ adsp_card->tdm_record); -+ adsp_card->tdm_record = NULL; -+ return -EINVAL; -+ } -+ } -+ -+ /* save the hardware parameters */ -+ snd_soc_set_runtime_hwparams(substream, &snd_pcm_adsp_tdm_hw); -+ -+ /* each period has a frame size */ -+ snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, TDM_FRAME_SIZE); -+ } -+ -+ snd_pcm_hw_constraint_integer(substream->runtime, -+ SNDRV_PCM_HW_PARAM_PERIODS); -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Close a playback/TDM playback or record/TDM record stream -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_close(struct snd_pcm_substream *substream) -+{ -+ /* get ADSP soundcard and CPU DAI index */ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ int err = 0; -+ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ /* destroy Renderer/Capture or Equalizer (if used) */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (snd_adsp_playback_deinit( -+ adsp_card->playback[dai_idx]) < 0) -+ err = -EINVAL; -+ -+ adsp_card->playback[dai_idx] = NULL; -+ } else { -+ if (snd_adsp_record_deinit( -+ adsp_card->record[dai_idx]) < 0) -+ err = -EINVAL; -+ -+ adsp_card->record[dai_idx] = NULL; -+ } -+ } else { -+ /* destroy TDM Renderer/TDM Capture */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (snd_adsp_tdm_playback_deinit( -+ adsp_card->tdm_playback) < 0) -+ err = -EINVAL; -+ -+ adsp_card->tdm_playback = NULL; -+ } else { -+ if (snd_adsp_tdm_record_deinit( -+ adsp_card->tdm_record) < 0) -+ err = -EINVAL; -+ -+ adsp_card->tdm_record = NULL; -+ } -+ } -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ * \brief Allocate ALSA buffer and calculate expire time of hr timer -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -ENOMEM Cannot allocate ALSA buffer -+ *****************************************************************************/ -+static int snd_adsp_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ struct snd_adsp_base_info *base; -+ int err = 0; -+ -+ base = snd_adsp_get_base_from_substream(substream); -+ -+ /* set expire time of hrtimer, this value should be time for */ -+ /* transfer a frame */ -+ base->ktime = ns_to_ktime((1000000000 / params_rate(hw_params)) * -+ params_period_size(hw_params)); -+ -+ err = snd_pcm_lib_malloc_pages(substream, -+ params_buffer_bytes(hw_params)); -+ -+ /* reset DMA buffer area */ -+ memset(substream->runtime->dma_area, 0, substream->runtime->dma_bytes); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ * \brief Free the allocated ALSA buffer -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Cannot deallocate buffer -+ *****************************************************************************/ -+static int snd_adsp_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+/** ************************************************************************** -+ * \brief Prepare playback/TDM playback or record/TDM record function -+ * before transferring data -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ /* get ADSP soundcard and CPU DAI index */ -+ struct snd_adsp_card *adsp_card = -+ snd_adsp_get_drvdata_from_substream(substream); -+ int dai_idx = snd_adsp_get_dai_id_from_substream(substream); -+ int err = 0; -+ -+ if ((dai_idx == RDR_DAI_IDX0) || (dai_idx == RDR_DAI_IDX1) || -+ (dai_idx == RDR_DAI_IDX2) || (dai_idx == RDR_DAI_IDX3)) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ /* get playback prepared to execute */ -+ err = snd_adsp_playback_prepare( -+ adsp_card->playback[dai_idx], substream); -+ else -+ /* get record prepared to execute */ -+ err = snd_adsp_record_prepare( -+ adsp_card->record[dai_idx], substream); -+ } else { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ /* get TDM playback prepared to execute */ -+ err = snd_adsp_tdm_playback_prepare( -+ adsp_card->tdm_playback, substream); -+ else -+ /* get TDM record prepared to execute */ -+ err = snd_adsp_tdm_record_prepare( -+ adsp_card->tdm_record, substream); -+ } -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ * \brief Trigger playback/TDM playback or record/TDM record stream -+ * to go to next phase -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_trigger(struct snd_pcm_substream *substream, int idx) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ -+ switch (idx) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ /* start high-resolution timer */ -+ hrtimer_start(&base->hrtimer, base->ktime, -+ HRTIMER_MODE_REL); -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { -+ int buf_queue = 0; -+ -+ /* get current available buffer */ -+ spin_lock(&base->lock); -+ buf_queue = base->buf_queue; -+ spin_unlock(&base->lock); -+ -+ /* send all available buffer to plugin to */ -+ /* get data */ -+ for (; buf_queue > 0; buf_queue--) { -+ if (xf_adsp_fill_this_buffer( -+ base->handle_id, -+ base->buffer[base->buf_idx], -+ base->buf_bytes) != 0) -+ return -EINVAL; -+ -+ spin_lock(&base->lock); -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ base->buf_idx++; -+ if (base->buf_idx >= XF_BUF_POOL_SIZE) -+ base->buf_idx = 0; -+ } -+ } -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Return HW data position -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval position HW data position -+ *****************************************************************************/ -+static snd_pcm_uframes_t snd_adsp_pcm_pointer( -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ unsigned int hw_idx, hw_buffer_size; -+ snd_pcm_uframes_t pointer; -+ -+ /* convert hw index to correct as submitted bytes */ -+ spin_lock(&base->lock); -+ hw_idx = (base->hw_idx / base->buf_bytes) * base->period_bytes; -+ spin_unlock(&base->lock); -+ -+ hw_buffer_size = base->pcm_indirect.hw_buffer_size; -+ -+ if (hw_idx >= hw_buffer_size) { -+ spin_lock(&base->lock); -+ base->hw_idx -= (hw_buffer_size / base->period_bytes) * -+ base->buf_bytes; -+ spin_unlock(&base->lock); -+ } -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ pointer = snd_pcm_indirect_playback_pointer(substream, -+ &base->pcm_indirect, -+ hw_idx); -+ else -+ pointer = snd_pcm_indirect_capture_pointer(substream, -+ &base->pcm_indirect, -+ hw_idx); -+ -+ return pointer; -+} -+ -+/** ************************************************************************** -+ * \brief Call read/write process to transfer data -+ * -+ * \param[in] substream Pointer to substream object -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_pcm_ack(struct snd_pcm_substream *substream) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ -+ if (base->runtime_err == TRUE) -+ return -EINVAL; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ snd_pcm_indirect_playback_transfer(substream, -+ &base->pcm_indirect, -+ snd_adsp_pcm_transfer); -+ else -+ snd_pcm_indirect_capture_transfer(substream, -+ &base->pcm_indirect, -+ snd_adsp_pcm_transfer); -+ -+ return 0; -+} -+ -+/** *************************************************************************** -+ * \brief Copy data from source buffer to destination buffer -+ * -+ * \params[in] dst Destination buffer pointer -+ * \params[out] src Source buffer pointer -+ * \params[in] dst_size Destination buffer size in byte -+ * \params[in] src_size Source buffer size in byte -+ * \retval None -+ *****************************************************************************/ -+static inline void snd_adsp_copy_data(void *dst, void *src, int dst_size, -+ int src_size) -+{ -+ unsigned char *data_dst = dst; -+ unsigned char *data_src = src; -+ int i; -+ -+ if (dst_size == src_size) -+ /* src and dst buffers are same size, does not need to */ -+ /* convert */ -+ memcpy(data_dst, data_src, dst_size); -+ else if (dst_size < src_size) { -+ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_3LE)); -+ i += BYTES_PER_SAMPLE(S24_3LE)) { -+ *(u32 *)data_dst = *(u32 *)data_src; -+ -+ data_dst += BYTES_PER_SAMPLE(S24_3LE); -+ data_src += BYTES_PER_SAMPLE(S24_LE); -+ } -+ -+ SAMPLE_COPY(data_dst, data_src, S24_3LE, S24_LE); -+ } else { -+ unsigned int tmp; -+ -+ for (i = 0; i < (dst_size - BYTES_PER_SAMPLE(S24_LE)); -+ i += BYTES_PER_SAMPLE(S24_LE)) { -+ tmp = *(u32 *)data_src; -+ *(u32 *)data_dst = tmp & 0x0FFFFFF; -+ -+ data_dst += BYTES_PER_SAMPLE(S24_LE); -+ data_src += BYTES_PER_SAMPLE(S24_3LE); -+ } -+ -+ SAMPLE_COPY(data_dst, data_src, S24_LE, S24_3LE); -+ } -+} -+ -+/** ************************************************************************** -+ * \brief Transfer data process between ALSA buffer and ADSP buffer -+ * -+ * \param[in] substream Pointer to substream object -+ * \param[in] rec Pointer to indirect PCM data -+ * \param[in] bytes Number of byte need to be transferred -+ * \retval None -+ *****************************************************************************/ -+static void snd_adsp_pcm_transfer(struct snd_pcm_substream *substream, -+ struct snd_pcm_indirect *rec, size_t bytes) -+{ -+ struct snd_adsp_base_info *base = -+ snd_adsp_get_base_from_substream(substream); -+ int direct = substream->stream; -+ int trans_bytes = bytes; -+ int buf_bytes, period_bytes; -+ void *dma_buf, *data_buff; -+ -+ /* get the DMA buffer pointer */ -+ dma_buf = (void *)(substream->runtime->dma_area + rec->sw_data); -+ -+ /* get information from base */ -+ buf_bytes = base->buf_bytes; -+ period_bytes = base->period_bytes; -+ -+ /* make sure the available buffer and transfer size - TBD */ -+ while (trans_bytes > 0) { -+ spin_lock(&base->lock); -+ if ((base->buf_queue > 0) && (trans_bytes >= period_bytes)) { -+ base->buf_queue--; -+ spin_unlock(&base->lock); -+ -+ /* get the buffer pointer from stream */ -+ data_buff = base->buffer[base->buf_idx]; -+ -+ if (direct == SNDRV_PCM_STREAM_PLAYBACK) { -+ /* copy data from user *//* PRQA S 3200 2 */ -+ snd_adsp_copy_data(data_buff, dma_buf, -+ buf_bytes, period_bytes); -+ -+ /* send buffer to plugin */ -+ if (xf_adsp_empty_this_buffer(base->handle_id, -+ data_buff, -+ buf_bytes) < 0) -+ base->runtime_err = TRUE; -+ } else { -+ /* copy data to user *//* PRQA S 3200 2 */ -+ snd_adsp_copy_data(dma_buf, data_buff, -+ period_bytes, buf_bytes); -+ -+ /* send buffer to plugin */ -+ if (xf_adsp_fill_this_buffer(base->handle_id, -+ data_buff, -+ buf_bytes) < 0) -+ base->runtime_err = TRUE; -+ } -+ -+ base->buf_idx++; -+ if (base->buf_idx >= XF_BUF_POOL_SIZE) -+ base->buf_idx = 0; -+ } else { -+ spin_unlock(&base->lock); -+ break; -+ } -+ -+ trans_bytes -= period_bytes; -+ } -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Volume control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of volume control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_volume_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = -1; -+ uinfo->value.integer.max = 799; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get volume value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to volume value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_volume_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; -+ int handle_state, handle_id; -+ int volume, cmd_idx, direction; -+ unsigned int index; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* determine command index, direction, handle state, handle ID */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = -+ adsp_card->playback[index]->renderer->handle_id; -+ } -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->cap_state; -+ handle_id = -+ adsp_card->record[index]->capture->handle_id; -+ } -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) { -+ handle_state = adsp_card->tdm_playback->state; -+ handle_id = -+ adsp_card->tdm_playback->tdm_renderer->handle_id; -+ } -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) { -+ handle_state = adsp_card->tdm_record->state; -+ handle_id = -+ adsp_card->tdm_record->tdm_capture->handle_id; -+ } -+ } -+ } -+ -+ /* get the volume's value */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* get the volume's value from the plugin */ -+ if (xf_adsp_get_param(handle_id, cmd_idx, &volume) != 0) -+ return -EINVAL; -+ -+ /* check the value after getting it and adjust it */ -+ ucontrol->value.integer.value[0] = (volume == 0xFFFFFFFF) ? -+ (-1) : (volume * VOLUME_SCALE) >> 20; -+ } else { -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) -+ ucontrol->value.integer.value[0] = -+ (ctr_if->vol_rate[direction][index] -+ * VOLUME_SCALE) >> 20; -+ else -+ ucontrol->value.integer.value[0] = -+ (ctr_if->tdm_vol_rate[direction] -+ * VOLUME_SCALE) >> 20; -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set volume value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to volume value -+ * \retval 1 Volume change -+ * \retval 0 Volume does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_volume_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) /* PRQA S 3673 */ -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ struct snd_adsp_control *ctr_if = &adsp_card->ctr_if; -+ int volume; -+ int ret; -+ int handle_state, handle_id, cmd_idx, volume_get; -+ int direction; -+ unsigned int index; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state and handle ID */ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* get the value to set */ -+ if (ucontrol->value.integer.value[0] == -1) -+ volume = 0xFFFFFFFF; -+ else { -+ /* round up the value if needed */ -+ volume = (ucontrol->value.integer.value[0] * (1 << 20)) / -+ VOLUME_SCALE; -+ if ((ucontrol->value.integer.value[0] * (1 << 20)) > -+ (VOLUME_SCALE * volume)) -+ volume += 1; -+ } -+ -+ /* determine command index, direction, handle state, handle ID */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = -+ adsp_card->playback[index]->renderer->handle_id; -+ } -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->cap_state; -+ handle_id = -+ adsp_card->record[index]->capture->handle_id; -+ } -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) { -+ handle_state = adsp_card->tdm_playback->state; -+ handle_id = -+ adsp_card->tdm_playback->tdm_renderer->handle_id; -+ } -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) { -+ handle_state = adsp_card->tdm_record->state; -+ handle_id = -+ adsp_card->tdm_record->tdm_capture->handle_id; -+ } -+ } -+ } -+ -+ /* set volume to plugin */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* TDM does not support set volume in runtime state */ -+ if (kcontrol->id.name[0] == PREFIX_OF_TDM_CTR_NAME) -+ return -EINVAL; -+ -+ /* apply set volume value to ADSP from user setting */ -+ if (xf_adsp_set_param(handle_id, cmd_idx, volume) != 0) -+ return -EINVAL; -+ -+ /* get volume from ADSP after setting to confirm */ -+ if (xf_adsp_get_param(handle_id, cmd_idx, &volume_get) != 0) -+ return -EINVAL; -+ -+ /* check if the value has changed */ -+ ret = (volume_get == volume) ? 1 : 0; -+ } else { -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) -+ ctr_if->vol_rate[direction][index] = volume; -+ else -+ ctr_if->tdm_vol_rate[direction] = volume; -+ -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Sample Rate Converter control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of sample rate -+ * converter control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_sample_rate_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = -1; -+ uinfo->value.integer.max = 48000; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get sample rate value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to sample rate value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_sample_rate_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int *rate; -+ int handle_id, handle_state, cmd_idx, direction; -+ unsigned int index; -+ -+ rate = (int *)&(ucontrol->value.integer.value[0]); /* PRQA S 310 */ -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state and handle ID */ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* determine command, direction, handle state, handle ID */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = -+ adsp_card->playback[index]->renderer->handle_id; -+ } -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->cap_state; -+ handle_id = -+ adsp_card->record[index]->capture->handle_id; -+ } -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) { -+ handle_state = adsp_card->tdm_playback->state; -+ handle_id = -+ adsp_card->tdm_playback->tdm_renderer->handle_id; -+ } -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) { -+ handle_state = adsp_card->tdm_record->state; -+ handle_id = -+ adsp_card->tdm_record->tdm_capture->handle_id; -+ } -+ } -+ } -+ -+ /* get parameter from plugin */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ if (xf_adsp_get_param(handle_id, cmd_idx, rate) != 0) -+ return -EINVAL; -+ } else { -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) { -+ *rate = -+ adsp_card->ctr_if.sample_rate[direction][index]; -+ } else { -+ *rate = adsp_card->ctr_if.tdm_sample_rate[direction]; -+ } -+ } -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set sample rate value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to sample rate value -+ * \retval 1 Sample rate change -+ * \retval 0 Sample rate does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_sample_rate_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) /* PRQA S 3673 */ -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ unsigned int index; -+ int rate; -+ int handle_state, cmd_idx, direction; -+ int ret = 1; -+ -+ rate = (int)ucontrol->value.integer.value[0]; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* determine command, direction and handle state */ -+ if (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) { -+ cmd_idx = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->rdr_state; -+ } else if (kcontrol->id.name[0] == PREFIX_OF_CAPTURE_CTR_NAME) { -+ cmd_idx = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->record[index])) -+ handle_state = adsp_card->record[index]->cap_state; -+ } else { -+ if (kcontrol->id.name[3] == TDM_PLAYBACK) { -+ cmd_idx = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ direction = DIRECT_PLAYBACK; -+ -+ if (IS_VALID(adsp_card->tdm_playback)) -+ handle_state = adsp_card->tdm_playback->state; -+ } else { -+ cmd_idx = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ direction = DIRECT_CAPTURE; -+ -+ if (IS_VALID(adsp_card->tdm_record)) -+ handle_state = adsp_card->tdm_record->state; -+ } -+ } -+ -+ /* get the value to set */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ return -EINVAL; -+ -+ if (kcontrol->id.name[0] != PREFIX_OF_TDM_CTR_NAME) -+ adsp_card->ctr_if.sample_rate[direction][index] = rate; -+ else -+ adsp_card->ctr_if.tdm_sample_rate[direction] = rate; -+ -+ ret = 1; -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Equalizer control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of Equalizer control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = MAX_EQZ_PARAM_NUMBER; -+ uinfo->value.integer.min = -1; -+ uinfo->value.integer.max = 0x7fffffff; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get equalizer parameters value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer parameters value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_get(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int handle_state, direction; -+ int i, j, filter_index; -+ unsigned int index; -+ struct xf_adsp_equalizer *equalizer; -+ struct xf_adsp_equalizer_params *eqz_params; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determin direction of stream */ -+ direction = (kcontrol->id.name[0] == -+ PREFIX_OF_PLAYBACK_CTR_NAME) ? DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* set handle state as NULL state, handle ID, equalizer pointer */ -+ handle_state = XF_HANDLE_NULL; -+ equalizer = NULL; -+ -+ /* get component's state */ -+ if (direction == DIRECT_PLAYBACK) { -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->eqz_state; -+ equalizer = adsp_card->playback[index]->equalizer; -+ } -+ } else { -+ if (IS_VALID(adsp_card->record[index])) { -+ handle_state = adsp_card->record[index]->eqz_state; -+ equalizer = adsp_card->record[index]->equalizer; -+ } -+ } -+ -+ /* perform parameters' values getting */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* get equalizer's parameters */ -+ if (xf_adsp_equalizer_get_params(equalizer) != 0) -+ return -EINVAL; -+ -+ eqz_params = &equalizer->params; -+ } else -+ eqz_params = &adsp_card->ctr_if.eqz_params[direction][index]; -+ -+ /* get equalizer type: PARAMETRIC or GRAPHIC */ -+ ucontrol->value.integer.value[0] = eqz_params->eqz_type; -+ -+ /* get parameters' value from Equalizer plugin */ -+ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { -+ for (i = 0, filter_index = 1; -+ filter_index <= XA_REL_EQZ_FILTER_NUM; -+ i++, filter_index++) { -+ /* get filter index */ -+ ucontrol->value.integer.value[(i * 6) + 1] = -+ filter_index; -+ -+ /* get frequency centre */ -+ ucontrol->value.integer.value[(i * 6) + 2] = -+ eqz_params->p_coef.fc[i]; -+ -+ /* get bandwidth */ -+ ucontrol->value.integer.value[(i * 6) + 3] = -+ eqz_params->p_coef.band_width[i]; -+ -+ /* get filter type */ -+ ucontrol->value.integer.value[(i * 6) + 4] = -+ eqz_params->p_coef.type[i]; -+ -+ /* get gain base */ -+ ucontrol->value.integer.value[(i * 6) + 5] = -+ eqz_params->p_coef.gain_base[i]; -+ -+ /* get gain */ -+ ucontrol->value.integer.value[(i * 6) + 6] = -+ eqz_params->p_coef.gain[i]; -+ } -+ } else { -+ for (i = 0, filter_index = 1; -+ filter_index <= XA_REL_EQZ_GRAPHIC_BAND_NUM; -+ i++, filter_index++) { -+ /* get band index */ -+ ucontrol->value.integer.value[(i * 2) + 1] = -+ filter_index; -+ -+ /* get graphic gain */ -+ ucontrol->value.integer.value[(i * 2) + 2] = -+ eqz_params->g_coef.gain_g[i]; -+ } -+ -+ j = (i * 2) + 1; -+ -+ /* make the rest of values silent */ -+ while (j < MAX_EQZ_PARAM_NUMBER) { -+ ucontrol->value.integer.value[j] = -1; -+ j++; -+ } -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set equalizer parameters value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer parameters value -+ * \retval 1 Equalizer parameters change -+ * \retval 0 Equalizer parameters does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+/* PRQA S 3673 1*/ -+static int snd_adsp_control_eqz_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int handle_state, direction, filter_idx; -+ int i; -+ int index; -+ int ret = 0; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determine the direction */ -+ direction = (kcontrol->id.name[0] == -+ PREFIX_OF_PLAYBACK_CTR_NAME) ? DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* get the handle state */ -+ if (direction == DIRECT_PLAYBACK) { -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->eqz_state; -+ } else { -+ if (IS_VALID(adsp_card->record[index])) -+ handle_state = adsp_card->record[index]->eqz_state; -+ } -+ -+ /* perform equalizer's parameters setting */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ ret = -EINVAL; -+ else { -+ /* PRQA S 310 1*/ -+ struct xf_adsp_equalizer_params *eqz_params = -+ &adsp_card->ctr_if.eqz_params[direction][index]; -+ -+ i = 0; -+ /* PRQA S 3440 1*/ -+ eqz_params->eqz_type = ucontrol->value.integer.value[i]; -+ i++; -+ filter_idx = 0; -+ -+ if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { -+ while (i < MAX_EQZ_PARAM_NUMBER) { -+ /* get index filter */ -+ /* PRQA S 3440*/ -+ filter_idx = ucontrol->value.integer.value[i]; -+ i++; -+ -+ /* valid index filter is range */ -+ /* (1 to XA_REL_EQZ_FILTER_NUM) */ -+ if ((filter_idx >= 1) && -+ (filter_idx <= XA_REL_EQZ_FILTER_NUM)) { -+ /* PRQA S 3440 5*/ -+ eqz_params->p_coef.fc[filter_idx - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.band_width[ -+ filter_idx - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.type[filter_idx - 1] -+ = ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.gain_base[ -+ filter_idx - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ eqz_params->p_coef.gain[filter_idx - 1] -+ = ucontrol->value.integer.value[i]; -+ i++; -+ } -+ /* index filter = -1 means that user */ -+ /* does not set this filter */ -+ else if (filter_idx == -1 || filter_idx == 0) -+ i += 5; -+ else -+ return -EINVAL; -+ } -+ } else if (eqz_params->eqz_type == XA_REL_EQZ_TYPE_GRAPHIC) { -+ while (i < ((XA_REL_EQZ_GRAPHIC_BAND_NUM * 2) + 1)) { -+ /*get index filter */ -+ /* PRQA S 3440 */ -+ filter_idx = ucontrol->value.integer.value[i++]; -+ -+ if ((filter_idx >= 1) && (filter_idx <= -+ XA_REL_EQZ_GRAPHIC_BAND_NUM)) { -+ eqz_params->g_coef.gain_g[filter_idx -+ - 1] = -+ ucontrol->value.integer.value[i]; -+ i++; -+ } else if (filter_idx == -1 || -+ filter_idx == 0) -+ i += 1; -+ else -+ return -EINVAL; -+ } -+ } else -+ return -EINVAL; -+ -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Equalizer Switch control -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of Equalizer -+ * Switch control -+ * \retval 0 Success -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_switch_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 1; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get equalizer switch value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer switch value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_switch_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int direction; -+ unsigned int index; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determine the direction */ -+ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? -+ DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* get the Equalizer switch status */ -+ ucontrol->value.integer.value[0] = -+ adsp_card->ctr_if.eqz_switch[direction][index]; -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set equalizer switch value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to equalizer switch value -+ * \retval 1 Equalizer switch change -+ * \retval 0 Equalizer switch does not change -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static int snd_adsp_control_eqz_switch_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) /* PRQA S 3673 */ -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int eqz_switch; -+ int handle_state, direction; -+ unsigned int index; -+ int ret = 0; -+ -+ eqz_switch = ucontrol->value.integer.value[0]; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ /* determine the direction */ -+ direction = (kcontrol->id.name[0] == PREFIX_OF_PLAYBACK_CTR_NAME) ? -+ DIRECT_PLAYBACK : DIRECT_CAPTURE; -+ -+ /* set handle state as NULL state */ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* determine handle state */ -+ if (direction == DIRECT_PLAYBACK) { -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->rdr_state; -+ } else { -+ if (IS_VALID(adsp_card->record[index])) -+ handle_state = adsp_card->record[index]->cap_state; -+ } -+ -+ /* set the status of Equalizer */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ /* runtime setting is not supported */ -+ ret = -EINVAL; -+ else { -+ adsp_card->ctr_if.eqz_switch[direction][index] = eqz_switch; -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/** ************************************************************************** -+ * \brief Get info of Renderer output channel -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] uinfo Pointer to info structure of Renderer output channel -+ * \retval 0 Success -+ *****************************************************************************/ -+static -+int snd_adsp_control_rdr_out_channel_info(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = MONAURAL; -+ uinfo->value.integer.max = STEREO; -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Get Renderer output channel's value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to Renderer output channel value -+ * \retval 0 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static -+int snd_adsp_control_rdr_out_channel_get(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ int rdr_out_ch; -+ unsigned int index; -+ int handle_state, handle_id; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ handle_state = XF_HANDLE_NULL; -+ handle_id = -1; -+ -+ /* determine handle state and handle ID */ -+ if (IS_VALID(adsp_card->playback[index])) { -+ handle_state = adsp_card->playback[index]->rdr_state; -+ handle_id = adsp_card->playback[index]->renderer->handle_id; -+ } -+ -+ /* get Renderer output channel's value */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) { -+ /* get Renderer output channel's value from Renderer plugin */ -+ if (xf_adsp_get_param(handle_id -+ , XA_RDR_CONFIG_PARAM_OUT_CHANNELS -+ , &rdr_out_ch) != 0) { -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = rdr_out_ch; -+ } else { -+ ucontrol->value.integer.value[0] = -+ adsp_card->ctr_if.rdr_out_ch[index]; -+ } -+ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Set Renderer output channel's value -+ * -+ * \param[in] kcontrol Pointer to control instance -+ * \param[in] ucontrol Pointer to Renderer output channel value -+ * \retval 1 Success -+ * \retval -EINVAL Error -+ *****************************************************************************/ -+static -+int snd_adsp_control_rdr_out_channel_put(struct snd_kcontrol *kcontrol -+ , struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_adsp_card *adsp_card = snd_kcontrol_chip(kcontrol); -+ unsigned int index; -+ int handle_state; -+ int ret = 1; -+ -+ /* get the index */ -+ index = kcontrol->id.index; -+ -+ handle_state = XF_HANDLE_NULL; -+ -+ /* determine handle state and handle ID */ -+ if (IS_VALID(adsp_card->playback[index])) -+ handle_state = adsp_card->playback[index]->rdr_state; -+ -+ /* get Renderer output channel's value */ -+ if (COMPONENT_IS_READY(handle_state) == TRUE) -+ /* not support runtime setting */ -+ ret = -EINVAL; -+ else -+ adsp_card->ctr_if.rdr_out_ch[index] = -+ ucontrol->value.integer.value[0]; -+ -+ return ret; -+} -+ -+/** control interface for playback's volume rate */ -+/* PRQA S 3218 */ -+static -+struct snd_kcontrol_new snd_adsp_playback_volume_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ } -+}; -+ -+/** control interface for Capture's volume rate */ -+/* PRQA S 3218 1*/ -+static -+struct snd_kcontrol_new snd_adsp_capture_volume_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+ } -+}; -+ -+/** control interface for playback's output sample rate */ -+/* PRQA S 3218 1*/ -+static struct snd_kcontrol_new -+ snd_adsp_playback_sample_rate_out_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ } -+}; -+ -+/** control interface for Capture's input sample rate */ -+/* PRQA S 3218 */ -+static struct snd_kcontrol_new -+ snd_adsp_capture_sample_rate_in_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+ } -+}; -+ -+/** control interface for Equalizer parameters in playback */ -+/* PRQA S 3218 1*/ -+static struct snd_kcontrol_new -+ snd_adsp_playback_equalizer_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ } -+}; -+ -+/** control interface for Equalizer parameters in record */ -+/* PRQA S 3218 */ -+static struct snd_kcontrol_new -+ snd_adsp_capture_equalizer_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_EQZ_CTR_NAME, -+ .info = &snd_adsp_control_eqz_info, -+ .get = &snd_adsp_control_eqz_get, -+ .put = &snd_adsp_control_eqz_put -+ } -+}; -+ -+/** control interface for Equalizer usage in playback */ -+/* PRQA S 3218 */ -+static struct snd_kcontrol_new -+snd_adsp_playback_equalizer_switch_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ } -+}; -+ -+/** control interface for Equalizer usage in record */ -+/* PRQA S 3218 1*/ -+static struct snd_kcontrol_new -+ snd_adsp_capture_equalizer_switch_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX1, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX2, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX3, -+ .name = CAPTURE_EQZ_SWITCH_CTR_NAME, -+ .info = &snd_adsp_control_eqz_switch_info, -+ .get = &snd_adsp_control_eqz_switch_get, -+ .put = &snd_adsp_control_eqz_switch_put -+ } -+}; -+ -+/** control interface for playback's output channel */ -+static struct snd_kcontrol_new -+snd_adsp_playback_out_channel_control[MAX_DAI_IDX - 1] = { -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .index = RDR_DAI_IDX0, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .index = RDR_DAI_IDX1, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .index = RDR_DAI_IDX2, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ }, -+ { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .index = RDR_DAI_IDX3, -+ .name = PLAYBACK_OUT_CHANNEL_CTR_NAME, -+ .info = &snd_adsp_control_rdr_out_channel_info, -+ .get = &snd_adsp_control_rdr_out_channel_get, -+ .put = &snd_adsp_control_rdr_out_channel_put -+ } -+}; -+ -+/** control interface for TDM playback's volume rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_playback_volume_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_PLAYBACK_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+}; -+ -+/** control interface for TDM capture's volume rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_capture_volume_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_CAPTURE_VOLUME_CTR_NAME, -+ .info = &snd_adsp_control_volume_info, -+ .get = &snd_adsp_control_volume_get, -+ .put = &snd_adsp_control_volume_put -+}; -+ -+/** control interface for TDM playback's output sample rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_playback_sample_rate_out_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_PLAYBACK_OUT_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+}; -+ -+/** control interface for TDM capture's input sample rate */ -+static struct snd_kcontrol_new snd_adsp_tdm_capture_sample_rate_in_control = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* PRQA S 1053 5 */ -+ .name = TDM_CAPTURE_IN_RATE_CTR_NAME, -+ .info = &snd_adsp_control_sample_rate_info, -+ .get = &snd_adsp_control_sample_rate_get, -+ .put = &snd_adsp_control_sample_rate_put -+}; -+ -+/** PCM callback function of the sound card */ -+static struct snd_pcm_ops snd_adsp_pcm_ops = { -+ .open = &snd_adsp_pcm_open, /* PRQA S 1053 10 */ -+ .close = &snd_adsp_pcm_close, -+ .ioctl = &snd_pcm_lib_ioctl, -+ .hw_params = &snd_adsp_pcm_hw_params, -+ .hw_free = &snd_adsp_pcm_hw_free, -+ .prepare = &snd_adsp_pcm_prepare, -+ .trigger = &snd_adsp_pcm_trigger, -+ .pointer = &snd_adsp_pcm_pointer, -+ .ack = &snd_adsp_pcm_ack -+}; -+ -+/******************************************************************* -+ * Internal functions -+ * ****************************************************************/ -+ -+/** ************************************************************************** -+ * \brief Process information get from control structure -+ * -+ * \param[in] eqz_params Equalizer parameters object -+ * \param[in] eqz_ctr_params Equalizer parameters stored in control object -+ * \param[in] flag Indicate playback or capture stream -+ *****************************************************************************/ -+static void snd_adsp_get_eqz_params_from_control( -+ struct xf_adsp_equalizer_params *eqz_params, -+ struct xf_adsp_equalizer_params *eqz_ctr_params, bool flag) -+{ -+ int filter_idx; -+ -+ if (flag == true) { -+ if (eqz_ctr_params->eqz_type >= 0) -+ eqz_params->eqz_type = eqz_ctr_params->eqz_type; -+ -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; -+ filter_idx++) { -+ if (eqz_ctr_params->p_coef.fc[filter_idx] >= 0) -+ eqz_params->p_coef.fc[filter_idx] = -+ eqz_ctr_params->p_coef.fc[filter_idx]; -+ if (eqz_ctr_params->p_coef.band_width[filter_idx] >= 0) -+ eqz_params->p_coef.band_width[filter_idx] = -+ eqz_ctr_params->p_coef.band_width[filter_idx]; -+ if (eqz_ctr_params->p_coef.type[filter_idx] >= 0) -+ eqz_params->p_coef.type[filter_idx] = -+ eqz_ctr_params->p_coef.type[filter_idx]; -+ if (eqz_ctr_params->p_coef.gain_base[filter_idx] >= 0) -+ eqz_params->p_coef.gain_base[filter_idx] = -+ eqz_ctr_params->p_coef.gain_base[filter_idx]; -+ if (eqz_ctr_params->p_coef.gain[filter_idx] >= 0) -+ eqz_params->p_coef.gain[filter_idx] = -+ eqz_ctr_params->p_coef.gain[filter_idx]; -+ } -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; -+ filter_idx++) { -+ if (eqz_ctr_params->g_coef.gain_g[filter_idx] >= 0) -+ eqz_params->g_coef.gain_g[filter_idx] = -+ eqz_ctr_params->g_coef.gain_g[filter_idx]; -+ } -+ } else { -+ eqz_ctr_params->eqz_type = eqz_params->eqz_type; -+ -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_FILTER_NUM; -+ filter_idx++) { -+ eqz_ctr_params->p_coef.fc[filter_idx] = -+ eqz_params->p_coef.fc[filter_idx]; -+ eqz_ctr_params->p_coef.band_width[filter_idx] = -+ eqz_params->p_coef.band_width[filter_idx]; -+ eqz_ctr_params->p_coef.type[filter_idx] = -+ eqz_params->p_coef.type[filter_idx]; -+ eqz_ctr_params->p_coef.gain_base[filter_idx] = -+ eqz_params->p_coef.gain_base[filter_idx]; -+ eqz_ctr_params->p_coef.gain[filter_idx] = -+ eqz_params->p_coef.gain[filter_idx]; -+ } -+ for (filter_idx = 0; filter_idx < XA_REL_EQZ_GRAPHIC_BAND_NUM; -+ filter_idx++) -+ eqz_ctr_params->g_coef.gain_g[filter_idx] = -+ eqz_params->g_coef.gain_g[filter_idx]; -+ } -+} -+ -+/******************************************************************* -+ * ALSA ADSP Platform driver interface -+ * ****************************************************************/ -+ -+/** **************************************************************************** -+ * \brief Register control interface and preallocate ALSA buffer -+ * -+ * \param[in] runtime Pointer to runtime PCM data -+ * \retval 0 Success -+ * \retval -EINVAL Cannot register control interface -+ ******************************************************************************/ -+static int snd_adsp_pcm_new(struct snd_soc_pcm_runtime *runtime) -+{ -+ int i = 0, err = 0; -+ int id; -+ struct snd_card *card; -+ struct snd_adsp_card *adsp_card; -+ int alsa_buf_sz = 0; -+ -+ /* get sound card data */ -+ card = runtime->card->snd_card; -+ -+ /* get driver data */ -+ adsp_card = snd_soc_dai_get_drvdata(runtime->cpu_dai); -+ -+ /* get the ID of CPU DAI */ -+ id = runtime->cpu_dai->id; -+ -+ /* register control interfaces */ -+ if (id == RDR_DAI_IDX0 || id == RDR_DAI_IDX1 -+ || id == RDR_DAI_IDX2 || id == RDR_DAI_IDX3) { -+ struct snd_kcontrol *kctl[RDR_CONTROL_NUM]; -+ void *rdr_ctr[RDR_CONTROL_NUM] = { -+ &snd_adsp_playback_volume_control[id], /* PRQA S 1031 */ -+ &snd_adsp_capture_volume_control[id], -+ &snd_adsp_playback_sample_rate_out_control[id], -+ &snd_adsp_capture_sample_rate_in_control[id], -+ &snd_adsp_playback_equalizer_control[id], -+ &snd_adsp_capture_equalizer_control[id], -+ &snd_adsp_playback_equalizer_switch_control[id], -+ &snd_adsp_capture_equalizer_switch_control[id], -+ &snd_adsp_playback_out_channel_control[id] -+ }; -+ -+ /* add basic control instance */ -+ for (i = 0; i < RDR_CONTROL_NUM; i++) { -+ kctl[i] = snd_ctl_new1(rdr_ctr[i], adsp_card); -+ err = snd_ctl_add(card, kctl[i]); -+ if (err < 0) -+ return -EINVAL; -+ } -+ -+ /* assign ALSA buffer size */ -+ alsa_buf_sz = MAX_BUFFER_BYTES; -+ -+ /* enable MIX feature from the 2nd playback/record stream */ -+ if (adsp_card->ctr_if.mix_usage == MIX_UNUSED) -+ adsp_card->ctr_if.mix_usage = FIRST_RUN; -+ else if (adsp_card->ctr_if.mix_usage == FIRST_RUN) -+ adsp_card->ctr_if.mix_usage = SECOND_RUN; -+ -+ } else { -+ struct snd_kcontrol *kctl[TDM_CONTROL_NUM]; -+ void *tdm_ctr[TDM_CONTROL_NUM] = { -+ &snd_adsp_tdm_playback_volume_control, -+ &snd_adsp_tdm_playback_sample_rate_out_control, -+ &snd_adsp_tdm_capture_volume_control, -+ &snd_adsp_tdm_capture_sample_rate_in_control -+ }; -+ -+ /* add basic control instances */ -+ for (i = 0; i < TDM_CONTROL_NUM; i++) { -+ kctl[i] = snd_ctl_new1(tdm_ctr[i], adsp_card); -+ err = snd_ctl_add(card, kctl[i]); -+ if (err < 0) -+ return -EINVAL; -+ } -+ -+ /* assign ALSA buffer size */ -+ alsa_buf_sz = TDM_MAX_BUFFER_BYTES; -+ } -+ -+ return snd_pcm_lib_preallocate_pages_for_all(runtime->pcm, -+ SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data(GFP_KERNEL), -+ alsa_buf_sz, alsa_buf_sz); -+} -+ -+/* **************************************************************************** -+ * ALSA ADSP DAI register -+ * ***************************************************************************/ -+ -+/** callback function of platform driver */ -+static struct snd_soc_platform_driver snd_adsp_platform = { -+ .pcm_new = &snd_adsp_pcm_new, /* PRQA S 1053 *//* PRQA S 0674 */ -+ .ops = &snd_adsp_pcm_ops, -+}; -+ -+/** component information of driver */ -+static const struct snd_soc_component_driver snd_adsp_component = { -+ .name = "snd_adsp", /* PRQA S 1053 */ -+}; -+ -+/** DAI information of ADSP ALSA driver */ -+static struct snd_soc_dai_driver snd_adsp_dai[MAX_DAI_IDX] = { -+ { -+ /* PRQA S 1053 */ -+ .id = RDR_DAI_IDX0, -+ .name = "adsp-dai.0", -+ .playback.stream_name = "Playback0", -+ .capture.stream_name = "Capture0", -+ }, -+ { -+ .id = RDR_DAI_IDX1, -+ .name = "adsp-dai.1", -+ .playback.stream_name = "Playback1", -+ .capture.stream_name = "Capture1", -+ }, -+ { -+ .id = RDR_DAI_IDX2, -+ .name = "adsp-dai.2", -+ .playback.stream_name = "Playback2", -+ .capture.stream_name = "Capture2", -+ }, -+ { -+ .id = RDR_DAI_IDX3, -+ .name = "adsp-dai.3", -+ .playback.stream_name = "Playback3", -+ .capture.stream_name = "Capture3", -+ }, -+ { -+ .id = TDM_DAI_IDX, -+ .name = "adsp-tdm-dai", -+ .playback.stream_name = "TDM Playback", -+ .capture.stream_name = "TDM Capture", -+ } -+}; -+ -+/** *************************************************************************** -+ * \brief Register platform driver and ADSP ALSA sound card -+ * -+ * \param[in] pdev Pointer to platform driver data -+ * \retval 0 Success -+ * \retval -ENOMEM Cannot allocate driver's data -+ * \retval -EINVAL Cannot register platform driver or sound card -+ ****************************************************************************/ -+static int snd_adsp_probe(struct platform_device *pdev) -+{ -+ struct snd_adsp_card *adsp_card; -+ int i; -+ -+ /* allocate a card data structure */ -+ adsp_card = kmalloc(sizeof(*adsp_card), GFP_KERNEL); -+ if (!adsp_card) -+ return -ENOMEM; -+ -+ /* init parameters */ -+ memset(adsp_card, 0, sizeof(*adsp_card)); /* PRQA S 3200 */ -+ /* PRQA S 3200 1*/ -+ memset(&adsp_card->ctr_if, -1, sizeof(struct snd_adsp_control)); -+ -+ /* disable Equalizer for all streams */ -+ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { -+ adsp_card->ctr_if.eqz_switch[DIRECT_CAPTURE][i] = 0; -+ adsp_card->ctr_if.eqz_switch[DIRECT_PLAYBACK][i] = 0; -+ } -+ -+ /* disable MIX function for all */ -+ adsp_card->ctr_if.mix_usage = MIX_UNUSED; -+ -+ /* save driver data */ -+ dev_set_drvdata(&pdev->dev, adsp_card); -+ -+ /* register platform device */ -+ if (snd_soc_register_platform(&pdev->dev, &snd_adsp_platform) < 0) { -+ //snd_printk("[ADSP] Cannot register platform driver\n"); -+ snd_soc_unregister_platform(&pdev->dev); -+ return -EINVAL; -+ } -+ -+ /* fill format information of sound DAI driver for Rdr/Cap function */ -+ for (i = 0; i < (MAX_DAI_IDX - 1); i++) { -+ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].playback.channels_min = MIN_CHANNEL; -+ snd_adsp_dai[i].playback.channels_max = MAX_CHANNEL; -+ -+ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].capture.channels_min = MIN_CHANNEL; -+ snd_adsp_dai[i].capture.channels_max = MAX_CHANNEL; -+ } -+ -+ /* fill format information of sound DAI driver for TDM function */ -+ snd_adsp_dai[i].playback.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].playback.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].playback.channels_min = TDM_MIN_CHANNEL; -+ snd_adsp_dai[i].playback.channels_max = TDM_MAX_CHANNEL; -+ -+ snd_adsp_dai[i].capture.rates = SND_ADSP_SAMPLE_RATES; -+ snd_adsp_dai[i].capture.formats = SND_ADSP_PCM_WIDTHS; -+ snd_adsp_dai[i].capture.channels_min = TDM_MIN_CHANNEL; -+ snd_adsp_dai[i].capture.channels_max = TDM_MAX_CHANNEL; -+ -+ /* register CPU dai */ -+ if (snd_soc_register_component(&pdev->dev, &snd_adsp_component -+ , snd_adsp_dai -+ , ARRAY_SIZE(snd_adsp_dai)) < 0) { -+ //snd_printk("[ADSP] Cannot register component\n"); -+ snd_soc_unregister_platform(&pdev->dev); -+ return -EINVAL; -+ } -+ -+ dev_info(&pdev->dev, "probed\n"); -+ -+ /* success */ -+ return 0; -+} -+ -+/** ************************************************************************** -+ * \brief Unregister platform driver and ADSP ALSA sound card -+ * -+ * \param[in] pdev Pointer platform driver data -+ * \retval 0 Success -+ * \retval -EINVAL Invalid driver's data -+ *****************************************************************************/ -+static int snd_adsp_remove(struct platform_device *pdev) -+{ -+ /* get ADSP sound card data */ -+ struct snd_adsp_card *adsp_card = -+ (struct snd_adsp_card *)dev_get_drvdata(&pdev->dev); -+ -+ if (!adsp_card) { -+ //snd_printk("Invalid snd_adsp_card data\n"); -+ return -ENODEV; -+ } -+ -+ /* release the ADSP sound card */ -+ kfree(adsp_card); -+ -+ /* unregister platform driver */ -+ snd_soc_unregister_component(&pdev->dev); -+ snd_soc_unregister_platform(&pdev->dev); -+ -+ /* success */ -+ return 0; -+} -+ -+/** ADSP ALSA driver information */ -+static const struct of_device_id snd_adsp_id[] = { -+ { .compatible = "renesas,rcar_adsp_sound_gen3", }, /* PRQA S 1053 */ -+}; -+MODULE_DEVICE_TABLE(of, snd_adsp_id); -+ -+/** platform driver of ADSP ALSA sound card */ -+static struct platform_driver snd_adsp_driver = { -+ .driver = { /* PRQA S 1053 */ -+ .name = "rcar_adsp_sound", -+ .of_match_table = snd_adsp_id, -+ }, -+ .probe = snd_adsp_probe, -+ .remove = snd_adsp_remove, -+}; -+module_platform_driver(snd_adsp_driver); /* PRQA S 0651 */ -+ -+MODULE_AUTHOR("Renesas AudioDSP"); -+MODULE_DESCRIPTION("Platform driver for ADSP"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:ADSP-PCM-AUDIO"); -diff --git a/sound/soc/adsp/xf-adsp-base.c b/sound/soc/adsp/xf-adsp-base.c -new file mode 100644 -index 0000000..d797bf5 ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-base.c -@@ -0,0 +1,2239 @@ -+/** *************************************************************************** -+ *\file xf-adsp-base.c -+ *\brief Source file for ADSP Base Control layer -+ *\addtogroup ADSP Driver -+ ****************************************************************************** -+ *\date Oct. 21, 2017 -+ *\author Renesas Electronics Corporation -+ ****************************************************************************** -+ *\par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#include -+#include -+#include -+ -+#include "xf-adsp-base.h" -+ -+#define XF_AUX_POOL_SIZE (16) /**< size of auxiliary pool*/ -+#define XF_AUX_POOL_MSG_LENGTH (256) /**< size of auxiliary buffer */ -+ -+#define XF_PROXY_ALIGN (64) /**< proxy alignment */ -+ -+/** \def XF_ALIGNED(size) -+ * Get properly aligned buffer length -+ */ -+#define XF_ALIGNED(size)\ -+((((size) + XF_PROXY_ALIGN) - 1) & ~(XF_PROXY_ALIGN - 1)) /* PRQA S 3453 */ -+ -+#ifndef offset_of -+/** \def offset_of(type, member) -+ * Return the offset of member in type structuer in byte -+ */ -+#define offset_of(type, member) \ -+ ((int)(long int)&(((const type *)(0))->member)) /* PRQA S 3453 */ -+#endif -+ -+/************************************************* -+ * Variable and and function declaration -+ * **********************************************/ -+ -+/** ADSP base control data */ -+static struct xf_adsp_base *base; -+ -+/* function declaration */ -+static int xf_adsp_base_register_handle(void *private_data, -+ struct xf_callback_func *cb -+ , int comp_id); -+static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id); -+static int xf_adsp_base_free_handle(int handle_id); -+static void xf_adsp_base_init_handle(void); -+static int xf_adsp_base_get_valid_handle(void); -+static int xf_send_and_receive(struct xf_message *msg); -+static int xf_response_thread(void *data); -+static void xf_buffer_put(struct xf_buffer *buffer); -+static u32 xf_buffer_length(struct xf_buffer *b); -+static struct xf_buffer *xf_buffer_get(struct xf_pool *pool); -+static void *xf_buffer_data(struct xf_buffer *b); -+static int xf_adsp_unregister(int comp_id); -+static int xf_adsp_register(char *name, int *comp_id); -+ -+/************************************************* -+ * Helper function to process pool data -+ * **********************************************/ -+ -+/** *********************************************************** -+ * \brief get buffer from given pool -+ * -+ * \param[in] pool Data pool address -+ * \retval b Pointer to buffer address in pool -+ **************************************************************/ -+static struct xf_buffer *xf_buffer_get(struct xf_pool *pool) -+{ -+ struct xf_buffer *b; -+ -+ b = pool->free; -+ if (b) { -+ pool->free = b->link.next; -+ b->link.pool = pool; -+ } -+ return b; -+} -+ -+/*********************************************************** -+ *\brief return buffer back to pool -+ * -+ *\param[in] buffer Pointer to the buffer data -+ ************************************************************/ -+static void xf_buffer_put(struct xf_buffer *buffer) -+{ -+ struct xf_pool *pool = buffer->link.pool; -+ -+ buffer->link.next = pool->free; -+ pool->free = buffer; -+} -+ -+/*********************************************************** -+ *\brief get the address of the given buffer data -+ * -+ *\param[in] b Pointer to the buffer data -+ *\retval address Address of buffer data -+ ************************************************************/ -+static void *xf_buffer_data(struct xf_buffer *b) -+{ -+ return b->address; -+} -+ -+/************************************************************ -+ *\brief get the length of the given buffer data -+ * -+ *\param[in] b Pointer to the buffer data -+ *\retval length Size of buffer data -+ ************************************************************/ -+static u32 xf_buffer_length(struct xf_buffer *b) /* PRQA S 3673 */ -+{ -+ return b->link.pool->length; -+} -+ -+/************************************************************ -+ *\brief set data to the given command message -+ * -+ *\param[out] m Pointer to the command message -+ *\param[in] id Message ID -+ *\param[in] opcode Message opcode -+ *\param[in] length Message length -+ *\param[in] buf Pointer to the buffer data -+ *\param[in] next Pointer to the next message -+ *\retval m Pointer to the command message -+ ************************************************************/ -+static inline struct xf_message *xf_create_msg( -+ struct xf_message *m, u32 id, u32 opcode, -+ u32 length, void *buf, struct xf_message *next) -+{ -+ if (m) { -+ m->id = id; -+ m->opcode = opcode; -+ m->length = length; -+ m->buffer = buf; -+ m->next = next; -+ } -+ -+ return m; -+} -+ -+/***************************************************************** -+ *\brief synchronous send and wait for response message from proxy -+ * -+ *\param[in] msg Pointer to the command message -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ ****************************************************************/ -+static int xf_send_and_receive(struct xf_message *msg) -+{ -+ int err; -+ int opcode = msg->opcode; -+ -+ /* reset the base flag */ -+ spin_lock(&base->lock); -+ base->base_flag = FALSE; -+ spin_unlock(&base->lock); -+ -+ err = base->cmd.send(base->client, (void *)msg); -+ if (err != 0) -+ return err; -+ -+ /* sleep and wait for the response wake up event */ -+ if (wait_event_interruptible(base->base_wait, -+ base->base_flag || base->err_flag)) { -+ return -EINVAL; -+ } -+ -+ if (base->err_flag != 0) { -+ spin_lock(&base->lock); -+ base->err_flag = FALSE; -+ spin_unlock(&base->lock); -+ return -EINVAL; -+ } -+ -+ /* save the response message */ -+ /* PRQA S 3200 */ -+ memcpy(msg, &base->base_msg, sizeof(struct xf_message)); -+ -+ /* check if the reponsed message is right */ -+ if (msg->opcode != opcode) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+/************************************************************* -+ *\brief send a message to proxy -+ * -+ *\param[in] msg Pointer to the command message -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+static inline int xf_send(struct xf_message *msg) -+{ -+ return base->cmd.send(base->client, (void *)msg); -+} -+ -+/** *********************************************************** -+ *\brief receive message from proxy -+ * -+ *\param[in] msg Pointer to store the response message -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+static inline int xf_receive(struct xf_message *msg) -+{ -+ /* do not wait here */ -+ return base->cmd.recv(base->client, (void *)msg); -+} -+ -+/** *********************************************************** -+ *\brief thread for receive response data -+ **************************************************************/ -+static int xf_response_thread(void *data) -+{ -+ struct xf_message msg; -+ struct xf_handle *handle; -+ int id; -+ -+ /* set polling to wait the response message */ -+ spin_lock(&base->lock); -+ base->wait_flag = FALSE; -+ spin_unlock(&base->lock); -+ -+ while (!kthread_should_stop()) { -+ if (base->cmd.poll(base->client, &base->wait_flag) != 0) -+ continue; -+ -+ if (xf_receive(&msg) != 0) -+ continue; -+ /* get the handle id */ -+ id = XF_AP_CLIENT(msg.id); -+ -+ /* check the destination of the response message */ -+ if (id == 0) { -+ /* message is from base control */ -+ /* PRQA S 3200 1*/ -+ memcpy(&base->base_msg -+ , &msg, sizeof(struct xf_message)); -+ spin_lock(&base->lock); -+ base->base_flag = TRUE; -+ spin_unlock(&base->lock); -+ wake_up(&base->base_wait); -+ continue; -+ } -+ -+ /* get handle data */ -+ handle = xf_adsp_base_get_handle(id); -+ -+ if (handle == 0) -+ continue; -+ -+ switch (msg.opcode) { -+ case XF_EMPTY_THIS_BUFFER: /* PRQA S 0594 */ -+ handle->cb->empty_buf_done(handle->private_data, -+ msg.opcode, -+ msg.length, -+ msg.buffer); -+ break; -+ case XF_FILL_THIS_BUFFER: /* PRQA S 0594 */ -+ handle->cb->fill_buf_done(handle->private_data, -+ msg.opcode, -+ msg.length, -+ msg.buffer); -+ break; -+ case XF_SET_PARAM: /* PRQA S 0594 4 */ -+ case XF_GET_PARAM: -+ case XF_ROUTE: -+ case XF_UNROUTE: -+ /* message is from base control */ -+ memcpy(&base->base_msg, &msg, -+ sizeof(struct xf_message)); /* PRQA S 3200 */ -+ spin_lock(&base->lock); -+ base->base_flag = TRUE; -+ spin_unlock(&base->lock); -+ wake_up(&base->base_wait); -+ break; -+ default: -+ /* error has occurred */ -+ handle->cb->event_handler(handle->private_data); -+ xf_adsp_base_free_handle(id); /* PRQA S 3200 */ -+ spin_lock(&base->lock); -+ base->err_flag = TRUE; -+ spin_unlock(&base->lock); -+ wake_up(&base->base_wait); -+ break; -+ } -+ } -+ -+ pr_info("ADSP base thread was exited\n"); -+ -+ do_exit(0); -+ return 0; -+} -+ -+/************************************************************* -+ * \brief register component to ADSP -+ * -+ * \param[in] name Name string of component -+ * \param[out] comp_id Store the registered component ID -+ * \retval 0 Success -+ * \retval -EINVAL Failed -+ **************************************************************/ -+static int xf_adsp_register(char *name, int *comp_id) /* PRQA S 3673 */ -+{ -+ struct xf_message msg; -+ struct xf_buffer *b = xf_buffer_get(base->aux_pool); -+ int err = 0; -+ -+ msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); -+ msg.opcode = XF_REGISTER; -+ msg.length = strlen(name) + 1; -+ msg.buffer = xf_buffer_data(b); -+ -+ /* copy identify name of ADSP component */ -+ if (msg.length <= xf_buffer_length(b)) -+ strncpy(msg.buffer, name, msg.length); /* PRQA S 3200 */ -+ else -+ strncpy(msg.buffer, name, xf_buffer_length(b));/* PRQA S 3200 */ -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the registered component ID */ -+ *comp_id = XF_MSG_SRC(msg.id); -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ * \brief unregister component from ADSP -+ * \param[in] comp_id Registered component ID -+ * \retval 0 Success -+ * \retval -EINVAL Failed -+ **************************************************************/ -+static int xf_adsp_unregister(int comp_id) -+{ -+ struct xf_message msg; -+ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), comp_id), -+ XF_UNREGISTER, 0, NULL, NULL); /* PRQA S 3200 */ -+ -+ return xf_send_and_receive(&msg); -+} -+ -+/*************************************************************** -+ * APIs for ADSP component helper -+ * ************************************************************/ -+/** *********************************************************** -+ * \brief allocate memory pool from shared memory -+ * \param[in] pool_size Number of buffer need to allocate -+ * \param[in] buf_length Size of each buffer in bytes -+ * \retval pool Pointer to allocated pool -+ * \retval -EINVAL Invalid base data -+ * \retval -ENOMEM Out of memory resource -+ **************************************************************/ -+struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length) -+{ -+ void *data; -+ u32 number; -+ struct xf_buffer *b; -+ struct xf_message msg; -+ struct xf_pool *pool; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return ERR_PTR(-EINVAL); /* PRQA S 0306 */ -+ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), -+ XF_ALLOC, -+ buf_length * pool_size, NULL, NULL); /* PRQA S 3200 */ -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ -+ -+ pool = kmalloc(offset_of(struct xf_pool, buffer) + -+ (pool_size * sizeof(struct xf_buffer)), GFP_KERNEL);/* PRQA S 0306 */ -+ if (!pool) -+ return ERR_PTR(-ENOMEM); /* PRQA S 0306 */ -+ -+ pool->length = buf_length; -+ pool->number = pool_size; -+ pool->p = msg.buffer; -+ -+ number = pool_size; -+ for (pool->free = b = &pool->buffer[0], data = pool->p; -+ number > 0; number--, b++) { /* PRQA S 2462,3418,0489 */ -+ /* set address of the buffer */ -+ b->address = data; -+ -+ /* fill buffer into free list */ -+ if (number == 1) -+ b->link.next = NULL; -+ else -+ b->link.next = b + 1; /* PRQA S 0489 */ -+ -+ /* advance data pointer in contigous buffer */ -+ data += buf_length; /* PRQA S 0550 */ -+ } -+ -+ return pool; -+} -+ -+/** *********************************************************** -+ *\brief return memory to shared memory -+ *\param[in] pool Data pool address -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or pool data -+ **************************************************************/ -+int xf_adsp_free_mem_pool(struct xf_pool *pool) -+{ -+ struct xf_message msg; -+ -+ /* check the sane ADSP base pool data*/ -+ if (!base || !pool) -+ return -EINVAL; -+ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)), -+ XF_FREE, pool->number * pool->length, -+ pool->p, NULL); /* PRQA S 3200 */ -+ -+ xf_send_and_receive(&msg); /* PRQA S 3200 */ -+ -+ kfree(pool); -+ -+ return 0; -+} -+ -+/** *********************************************************** -+ *\brief get buffer from given pool -+ * -+ *\param[in] pool Data pool address -+ *\param[in] index Buffer index -+ *\retval b Pointer to buffer address in pool -+ *\retval -EINVAL Invalid pool or index -+ **************************************************************/ -+char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index) -+{ -+ struct xf_buffer *buf[XF_BUF_POOL_SIZE] = {0}; -+ char *data; -+ int i; -+ -+ /* check the sane pool data*/ -+ if (!pool) -+ return ERR_PTR(-EINVAL); /* PRQA S 306 */ -+ -+ /* check the index is valid */ -+ if (index > (pool->number - 1)) -+ return ERR_PTR(-EINVAL); /* PRQA S 306 */ -+ -+ /* get buffer from pool */ -+ for (i = 0; i <= index; i++) -+ buf[i] = xf_buffer_get(pool); -+ -+ /* get data from buffer */ -+ data = xf_buffer_data(buf[index]); -+ -+ /* return buffer to pool */ -+ for (i = index; i >= 0; i--) -+ xf_buffer_put(buf[i]); -+ -+ return data; -+} -+ -+/** *********************************************************** -+ *\brief send empty this buffer command to ADSP framework -+ * -+ *\param[in] handle_id ID of the registered handle -+ *\param[in] buffer Pointer to data buffer -+ *\param[in] length Size of buffer in bytes -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length) -+{ -+ struct xf_message msg; -+ struct xf_handle *handle; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ /* submit message to port 0 of component */ -+ /* PRQA S 3200 2 */ -+ xf_create_msg( -+ &msg, __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), -+ __XF_PORT_SPEC2(handle->comp_id, 0)), -+ XF_EMPTY_THIS_BUFFER, length, buffer, NULL); -+ -+ xf_send(&msg); /* PRQA S 3200 */ -+ -+ return 0; -+} -+ -+/** *********************************************************** -+ *\brief send fill this buffer command to ADSP framework -+ * -+ *\param[in] handle_id ID of the registered handle -+ *\param[in] buffer Pointer to data buffer -+ *\param[in] length Size of buffer in bytes -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length) -+{ -+ struct xf_message msg; -+ struct xf_handle *handle; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ /* submit message to port 1 of component */ -+ /* PRQA S 3200 2 */ -+ xf_create_msg( -+ &msg, __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id), -+ __XF_PORT_SPEC2(handle->comp_id, 1)), -+ XF_FILL_THIS_BUFFER, length, buffer, NULL); -+ -+ xf_send(&msg); /* PRQA S 3200 */ -+ -+ return 0; -+} -+ -+/** *********************************************************** -+ *\brief route data between two registered ADSP plugins -+ * -+ *\param[in] src_handle_id Handle ID of source plugin -+ *\param[in] dst_handle_id Handle ID of sink plugin -+ *\param[in] buf_cnt Number of buffer in tunnel -+ *\param[in] buf_size Size of each buffer in tunnel -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_route(int src_handle_id, -+ int dst_handle_id, -+ int buf_cnt, int buf_size) -+{ -+ struct xf_route_port_msg *route_msg; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ struct xf_handle *dst_handle, *src_handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ /* get handle data */ -+ dst_handle = xf_adsp_base_get_handle(dst_handle_id); -+ src_handle = xf_adsp_base_get_handle(src_handle_id); -+ -+ if (!dst_handle || !src_handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ route_msg = xf_buffer_data(b); -+ -+ /* route information */ -+ route_msg->dst = __XF_PORT_SPEC2(dst_handle->comp_id, 0); -+ route_msg->alloc_align = 4; -+ route_msg->alloc_number = buf_cnt; -+ route_msg->alloc_size = buf_size; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_CLIENT(0, src_handle_id) -+ , __XF_PORT_SPEC2(src_handle->comp_id, 1)), -+ XF_ROUTE, sizeof(*route_msg), route_msg, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief set a single parameter -+ * -+ *\param[in] handle_id ID of registered handle -+ *\param[in] index Sub-command index of parameter -+ *\param[in] value the setting value -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_set_param(int handle_id, int index, int value) -+{ -+ struct xf_message msg; -+ struct xf_buffer *b; -+ struct xf_set_param_msg *msg_params; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ msg_params->item[0].id = index; -+ msg_params->item[0].value = value; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(1) -+ , msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get a single parameter -+ * -+ *\param[in] handle_id ID of registered handle -+ *\param[in] index Sub-command index of parameter -+ *\param[out] value Store the getting value -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_get_param(int handle_id, int index, int *value) -+{ -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base and value data */ -+ if (!base || !value) -+ return -EINVAL; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ msg_params->c.id[0] = index; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)), -+ XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(1), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ *value = msg_params->r.value[0]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/*************************************************** -+ * APIs for ADSP base control -+ * ************************************************/ -+ -+/** *********************************************************** -+ *\brief initialize ADSP base's instance -+ * -+ *\retval 0 Success -+ *\retval -EINVAL ADSP base's instance has been initialized -+ *\retval -ENOMEM Cannot allocate memory for ADSP base -+ *\retval -EBUSY Cannot register client to proxy -+ **************************************************************/ -+int xf_adsp_base_create(xf_adsp_base_cmd_t *cmd) -+{ -+ int err = 0; -+ -+ if (base != 0) -+ return -EINVAL; -+ -+ if (!cmd || !cmd->recv || !cmd->send || !cmd->poll -+ || !cmd->client_register || !cmd->client_unregister) -+ return -EINVAL; -+ -+ base = kmalloc(sizeof(*base), GFP_KERNEL); -+ if (!base) -+ return -ENOMEM; -+ -+ memset(base, 0, sizeof(struct xf_adsp_base)); /* PRQA S 3200 */ -+ -+ /* store the proxy command */ -+ memcpy(&base->cmd, cmd, sizeof(xf_adsp_base_cmd_t)); -+ -+ /* create client to connect from proxy driver */ -+ err = base->cmd.client_register(&base->client); -+ if (err != 0) -+ goto err3; /* PRQA S 2001 */ -+ -+ /* initialize waiting queue */ -+ init_waitqueue_head(&base->base_wait); -+ -+ /* initialize handle */ -+ xf_adsp_base_init_handle(); -+ -+ /* create thread to get the responsed message from proxy */ -+ base->rsp_thread = kthread_run(&xf_response_thread -+ , (void *)base, "adsp base"); -+ if (base->rsp_thread != 0) { -+ pr_info("ADSP base thread has been started.\n"); -+ } else { -+ pr_info("Failed in create base thread\n"); -+ err = -ENOMEM; -+ goto err2; /* PRQA S 2001 */ -+ } -+ -+ /* allocate auxiliary pool for component usage */ -+ base->aux_pool = -+ xf_adsp_allocate_mem_pool(XF_AUX_POOL_SIZE -+ , XF_ALIGNED(XF_AUX_POOL_MSG_LENGTH)); -+ if (IS_ERR(base->aux_pool)) { /* PRQA S 306 */ -+ err = -ENOMEM; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ pr_info("ADSP base was created\n"); -+ return 0; -+ -+err1: -+ /* cancel the waitting queue */ -+ spin_lock(&base->lock); -+ base->wait_flag = TRUE; -+ spin_unlock(&base->lock); -+ -+ /* stop thread inadvance */ -+ kthread_stop(base->rsp_thread); -+ -+err2: -+ base->cmd.client_unregister(base->client); -+ -+err3: -+ kfree(base); -+ base = NULL; -+ -+ return err; -+} -+EXPORT_SYMBOL(xf_adsp_base_create); /* PRQA S 0651 */ -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP base's instance -+ * -+ *\retval 0 Success -+ *\retval -EINVAL Invalid ADSP base's instance -+ **************************************************************/ -+int xf_adsp_base_destroy(void) -+{ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ /* free auxiliary pool to shared memory */ -+ xf_adsp_free_mem_pool(base->aux_pool); /* PRQA S 3200 */ -+ -+ /* cancel wait the response message, go to stop process */ -+ spin_lock(&base->lock); -+ base->wait_flag = TRUE; -+ spin_unlock(&base->lock); -+ -+ /* stop response thread */ -+ kthread_stop(base->rsp_thread); -+ -+ /* unregister client */ -+ base->cmd.client_unregister(base->client); -+ -+ kfree(base); -+ base = NULL; -+ -+ pr_info("ADSP base was destroyed\n"); -+ return 0; -+} -+EXPORT_SYMBOL(xf_adsp_base_destroy); /* PRQA S 0651 */ -+ -+/** *********************************************************** -+ * \brief initialize handle instance -+ **************************************************************/ -+static inline void xf_adsp_base_init_handle(void) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_HANDLE; i++) -+ base->handle[i] = NULL; -+} -+ -+/** *********************************************************** -+ *\brief get the next available handle ID for register -+ * -+ *\retval -1 Unavailable handle ID -+ *\retval 0 to 255 Available handle ID -+ **************************************************************/ -+static inline int xf_adsp_base_get_valid_handle(void) -+{ -+ int id = -1; -+ int i; -+ -+ for (i = 0; i < MAX_HANDLE; i++) { -+ /* get the id of the first available handler */ -+ if (base->handle[i] == NULL) { -+ id = i; -+ break; -+ } -+ } -+ -+ return id; -+} -+ -+/** *********************************************************** -+ *\brief register a handle instance for component usage -+ * -+ *\param[in] private_data Private data of this component -+ *\param[in] cb Callback function -+ *\param[in] comp_id ID of register component -+ *\retval id ID of registered handle -+ *\retval -EINVAL Cannot get the handle instance -+ *\retval -ENOMEM Cannot allocate handle memory -+ **************************************************************/ -+static int xf_adsp_base_register_handle(void *private_data -+ , struct xf_callback_func *cb -+ , int comp_id) -+{ -+ struct xf_handle *handle; -+ int id; -+ -+ /* get the next handle id */ -+ id = xf_adsp_base_get_valid_handle(); -+ -+ /* check available handle in base */ -+ if (id < 0) -+ return -EINVAL; -+ -+ /* allocate handle data */ -+ handle = kmalloc(sizeof(*handle), GFP_KERNEL); -+ if (!handle) -+ return -ENOMEM; -+ -+ /* save handle data */ -+ handle->private_data = private_data; -+ handle->cb = cb; -+ handle->comp_id = comp_id; -+ -+ /* save the hanle data */ -+ base->handle[id] = handle; -+ -+ /* return the id numbering in base handle */ -+ return (id + 1); -+} -+ -+/** *********************************************************** -+ *\brief get handle instance from handle ID -+ * -+ *\param[in] handle_id ID of registered handle -+ *\retval handle Pointer to handle instance -+ **************************************************************/ -+static inline struct xf_handle *xf_adsp_base_get_handle(int handle_id) -+{ -+ return base->handle[handle_id - 1]; -+} -+ -+/** *********************************************************** -+ *\brief free the registered handle instance -+ * -+ *\param[in] handle_id ID of registered handle -+ *\retval 0 Success -+ *\retval -EINVAL Invalid handle ID -+ **************************************************************/ -+static int xf_adsp_base_free_handle(int handle_id) -+{ -+ if (handle_id < 1 || handle_id > MAX_HANDLE) -+ return -EINVAL; -+ -+ kfree(base->handle[handle_id - 1]); -+ base->handle[handle_id - 1] = NULL; -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for Renderer component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP Renderer parameters -+ * -+ *\param[in] renderer Pointer to Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_renderer_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !renderer) -+ return -EINVAL; -+ -+ params = &renderer->params; -+ -+ /* get Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_CHANNELS; -+ msg_params->item[i++].value = params->channel; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; -+ msg_params->item[i++].value = params->out_channel; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_MIX_CONTROL; -+ msg_params->item[i++].value = params->mix_ctrl; -+ -+ msg_params->item[i].id = XA_RDR_CONFIG_PARAM_STATE; -+ msg_params->item[i++].value = params->state; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP Renderer parameters -+ * -+ *\param[in] renderer Pointer to Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 */ -+int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer) -+{ -+ struct xf_adsp_renderer_params *rdr_params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !renderer) -+ return -EINVAL; -+ -+ rdr_params = &renderer->params; -+ -+ /* get Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 13 1*/ -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_CHANNELS; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_OUT_CHANNELS; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_MIX_CONTROL; -+ msg_params->c.id[i++] = XA_RDR_CONFIG_PARAM_STATE; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg, __XF_MSG_ID(__XF_AP_CLIENT(0, renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ rdr_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ -+ rdr_params->channel = msg_params->r.value[i++]; -+ rdr_params->pcm_width = msg_params->r.value[i++]; -+ rdr_params->frame_size = msg_params->r.value[i++]; -+ rdr_params->dev1 = msg_params->r.value[i++]; -+ rdr_params->dev2 = msg_params->r.value[i++]; -+ rdr_params->dma1 = msg_params->r.value[i++]; -+ rdr_params->dma2 = msg_params->r.value[i++]; -+ rdr_params->out_rate = msg_params->r.value[i++]; -+ rdr_params->vol_rate = msg_params->r.value[i++]; -+ rdr_params->out_channel = msg_params->r.value[i++]; -+ rdr_params->mix_ctrl = msg_params->r.value[i++]; -+ rdr_params->state = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create Renderer component -+ * -+ *\param[in,out] renderer Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Renderer instance -+ *****************************************************************************/ -+int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_renderer *rdr; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ rdr = kmalloc(sizeof(*rdr), GFP_KERNEL); -+ if (!rdr) -+ return -ENOMEM; -+ -+ memset(rdr, 0, sizeof(struct xf_adsp_renderer)); /* PRQA S 3200 */ -+ -+ /* register renderer component */ -+ err = xf_adsp_register("renderer", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register Renderer to ADSP base control */ -+ rdr->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (rdr->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from Renderer plugin */ -+ err = xf_adsp_renderer_get_params(rdr); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save renderer compoent data */ -+ *renderer = rdr; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(rdr); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP Renderer component -+ * -+ *\param[in] renderer Pointer to Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Renderer data -+ **************************************************************/ -+/* PRQA S 3673 */ -+int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !renderer) -+ return -EINVAL; -+ -+ handle_id = renderer->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(renderer); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for Capture component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP Capture parameters -+ * -+ *\param[in] capture Pointer to Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_capture_set_params(struct xf_adsp_capture *capture) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_capture_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !capture) -+ return -EINVAL; -+ -+ params = &capture->params; -+ -+ /* get Capture's handle data */ -+ handle = xf_adsp_base_get_handle(capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_CHANNELS; -+ msg_params->item[i++].value = params->channel; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ msg_params->item[i].id = XA_CAP_CONFIG_PARAM_STATE; -+ msg_params->item[i++].value = params->state; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP Capture parameters -+ * -+ *\param[in] capture Pointer to Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 */ -+int xf_adsp_capture_get_params(struct xf_adsp_capture *capture) -+{ -+ struct xf_adsp_capture_params *cap_params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !capture) -+ return -EINVAL; -+ -+ cap_params = &capture->params; -+ -+ /* get Capture's handle data */ -+ handle = xf_adsp_base_get_handle(capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 11 1*/ -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_CHANNELS; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->c.id[i++] = XA_CAP_CONFIG_PARAM_STATE; -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ cap_params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 11 */ -+ cap_params->channel = msg_params->r.value[i++]; -+ cap_params->pcm_width = msg_params->r.value[i++]; -+ cap_params->frame_size = msg_params->r.value[i++]; -+ cap_params->dev1 = msg_params->r.value[i++]; -+ cap_params->dev2 = msg_params->r.value[i++]; -+ cap_params->dma1 = msg_params->r.value[i++]; -+ cap_params->dma2 = msg_params->r.value[i++]; -+ cap_params->out_rate = msg_params->r.value[i++]; -+ cap_params->vol_rate = msg_params->r.value[i++]; -+ cap_params->state = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create Capture component -+ * -+ *\param[in,out] capture Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Capture instance -+ *****************************************************************************/ -+int xf_adsp_capture_create(struct xf_adsp_capture **capture -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_capture *cap; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ cap = kmalloc(sizeof(*cap), GFP_KERNEL); -+ if (!cap) -+ return -ENOMEM; -+ -+ memset(cap, 0, sizeof(struct xf_adsp_capture)); /* PRQA S 3200 */ -+ -+ /* register capture component */ -+ err = xf_adsp_register("capture", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register capture to ADSP base control */ -+ cap->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (cap->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from capture plugin */ -+ err = xf_adsp_capture_get_params(cap); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save capture compoent data */ -+ *capture = cap; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(cap); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP Capture component -+ * -+ *\param[in] capture Pointer to Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Capture data -+ **************************************************************/ -+int xf_adsp_capture_destroy(struct xf_adsp_capture *capture) /* PRQA S 3673 */ -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !capture) -+ return -EINVAL; -+ -+ handle_id = capture->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(capture); -+ //pr_info("ADSP Capture[%d] was destroyed\n", handle_id); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for Equalizer component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP Equalizer parameters -+ * -+ *\param[in] equalizer Pointer to Equalizer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_equalizer_params *params; -+ struct xf_buffer *b; -+ int i, n; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !equalizer) -+ return -EINVAL; -+ -+ params = &equalizer->params; -+ -+ /* get Equalizer's handle data */ -+ handle = xf_adsp_base_get_handle(equalizer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_COEF_FS; -+ msg_params->item[i++].value = params->rate; -+ -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_CH; -+ msg_params->item[i++].value = params->channel; -+ -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; -+ msg_params->item[i++].value = params->eqz_type; -+ -+ if (params->eqz_type == XA_REL_EQZ_TYPE_PARAMETRIC) { -+ struct xf_equalizer_parametric_coef *coef = ¶ms->p_coef; -+ -+ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; -+ msg_params->item[i++].value = coef->type[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; -+ msg_params->item[i++].value = coef->fc[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; -+ msg_params->item[i++].value = -+ coef->band_width[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; -+ msg_params->item[i++].value = coef->gain[n]; -+ -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; -+ msg_params->item[i++].value = coef->gain_base[n]; -+ } -+ } else { -+ struct xf_equalizer_graphic_coef *coef = ¶ms->g_coef; -+ -+ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { -+ msg_params->item[i].id = -+ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n; -+ msg_params->item[i++].value = coef->gain_g[n]; -+ } -+ } -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP Equalizer parameters -+ * -+ *\param[in] equalizer Pointer to Equalizer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 1*/ -+int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer) -+{ -+ struct xf_adsp_equalizer_params *eqz_params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i, n; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !equalizer) -+ return -EINVAL; -+ -+ eqz_params = &equalizer->params; -+ -+ /* get Equalizer's handle data */ -+ handle = xf_adsp_base_get_handle(equalizer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_COEF_FS; /* PRQA S 3440 4 */ -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_CH; -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_EQZ_CONFIG_PARAM_EQZ_TYPE; -+ -+ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE + n; /* PRQA S 3440 5 */ -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC + n; -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW + n; -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA + n; -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA + n; -+ } -+ -+ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) -+ msg_params->c.id[i++] = -+ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA + n;/* PRQA S 3440 */ -+ -+ /* PRQA S 3200 2 */ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, equalizer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ eqz_params->rate = msg_params->r.value[i++]; /* PRQA S 3440 4 */ -+ eqz_params->channel = msg_params->r.value[i++]; -+ eqz_params->pcm_width = msg_params->r.value[i++]; -+ eqz_params->eqz_type = msg_params->r.value[i++]; -+ -+ for (n = 0; n < XA_REL_EQZ_FILTER_NUM; n++) { -+ eqz_params->p_coef.type[n] = -+ msg_params->r.value[i++]; /* PRQA S 3440 5 */ -+ eqz_params->p_coef.fc[n] = msg_params->r.value[i++]; -+ eqz_params->p_coef.band_width[n] = msg_params->r.value[i++]; -+ eqz_params->p_coef.gain[n] = msg_params->r.value[i++]; -+ eqz_params->p_coef.gain_base[n] = msg_params->r.value[i++]; -+ } -+ -+ for (n = 0; n < XA_REL_EQZ_GRAPHIC_BAND_NUM; n++) { -+ eqz_params->g_coef.gain_g[n] = -+ msg_params->r.value[i++]; /* PRQA S 3440 */ -+ } -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create Equalizer component -+ * -+ *\param[in,out] equalizer Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Equalier instance -+ *****************************************************************************/ -+int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_equalizer *eqz; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ eqz = kmalloc(sizeof(*eqz), GFP_KERNEL); -+ if (!eqz) -+ return -ENOMEM; -+ -+ memset(eqz, 0, sizeof(struct xf_adsp_equalizer)); /* PRQA S 3200 */ -+ -+ /* register equalizer component */ -+ err = xf_adsp_register("equalizer", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register equalizer to ADSP base control */ -+ eqz->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (eqz->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from equalizer plugin */ -+ err = xf_adsp_equalizer_get_params(eqz); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save equalizer compoent data */ -+ *equalizer = eqz; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(eqz); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP Equalizer component -+ * -+ *\param[in] equalizer Pointer to Equalizer component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Equalizer data -+ **************************************************************/ -+/* PRQA S 3673 */ -+int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base and Equalizer data */ -+ if (!base || !equalizer) -+ return -EINVAL; -+ -+ handle_id = equalizer->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(equalizer); -+ //pr_info("ADSP Equalizer[%d] was destroyed\n", handle_id); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for TDM Renderer component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP TDM Renderer parameters -+ * -+ *\param[in] tdm_renderer Pointer to TDM Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_tdm_renderer_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_renderer) -+ return -EINVAL; -+ -+ params = &tdm_renderer->params; -+ -+ /* get TDM Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->item[i++].value = params->ch_mode; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP TDM Renderer parameters -+ * -+ *\param[in] tdm_renderer Pointer to TDM Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 1*/ -+int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer) -+{ -+ struct xf_adsp_tdm_renderer_params *params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_renderer) -+ return -EINVAL; -+ -+ params = &tdm_renderer->params; -+ -+ /* get TDM Renderer's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_renderer->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 13 1*/ -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT1; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUTPUT2; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_renderer->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ -+ params->ch_mode = msg_params->r.value[i++]; -+ params->pcm_width = msg_params->r.value[i++]; -+ params->frame_size = msg_params->r.value[i++]; -+ params->dev1 = msg_params->r.value[i++]; -+ params->dev2 = msg_params->r.value[i++]; -+ params->dma1 = msg_params->r.value[i++]; -+ params->dma2 = msg_params->r.value[i++]; -+ params->out_rate = msg_params->r.value[i++]; -+ params->vol_rate = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create TDM Renderer component -+ * -+ *\param[in,out] tdm_renderer Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Renderer instance -+ *****************************************************************************/ -+int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer -+ , struct xf_callback_func *cb -+ , void *private_data) -+{ -+ struct xf_adsp_tdm_renderer *tdm_rdr; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ tdm_rdr = kmalloc(sizeof(*tdm_rdr), GFP_KERNEL); -+ if (!tdm_rdr) -+ return -ENOMEM; -+ /* PRQA S 3200 */ -+ memset(tdm_rdr, 0, sizeof(struct xf_adsp_tdm_renderer)); -+ -+ /* register TDM Renderer component */ -+ err = xf_adsp_register("tdm-renderer", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register TDM Renderer to ADSP base control */ -+ tdm_rdr->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (tdm_rdr->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from plugin */ -+ err = xf_adsp_tdm_renderer_get_params(tdm_rdr); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save compoent data */ -+ *tdm_renderer = tdm_rdr; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(tdm_rdr); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP TDM Renderer component -+ * -+ *\param[in] tdm_renderer Pointer to TDM Renderer component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Renderer data -+ **************************************************************/ -+/* PRQA S 3673 1*/ -+int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_renderer) -+ return -EINVAL; -+ -+ handle_id = tdm_renderer->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(tdm_renderer); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * APIs for TDM Capture component -+ * ********************************************************************/ -+ -+/** *********************************************************** -+ *\brief set ADSP TDM Capture parameters -+ * -+ *\param[in] tdm_capture Pointer to TDM Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture) -+{ -+ struct xf_message msg; -+ struct xf_set_param_msg *msg_params; -+ struct xf_adsp_tdm_capture_params *params; -+ struct xf_buffer *b; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_capture) -+ return -EINVAL; -+ -+ params = &tdm_capture->params; -+ -+ /* get TDM Capture's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->item[i++].value = params->in_rate; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->item[i++].value = params->ch_mode; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->item[i++].value = params->pcm_width; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->item[i++].value = params->frame_size; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->item[i++].value = params->dev1; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->item[i++].value = params->dev2; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->item[i++].value = params->dma1; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->item[i++].value = params->dma2; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->item[i++].value = params->out_rate; -+ -+ msg_params->item[i].id = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ msg_params->item[i++].value = params->vol_rate; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_SET_PARAM, XF_SET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief get ADSP TDM Capture parameters -+ * -+ *\param[in] tdm_capture Pointer to TDM Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Failed -+ **************************************************************/ -+/* PRQA S 1505 1*/ -+int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture) -+{ -+ struct xf_adsp_tdm_capture_params *params; -+ struct xf_message msg; -+ struct xf_buffer *b; -+ union xf_get_param_msg *msg_params; -+ int i; -+ struct xf_handle *handle; -+ int err = 0; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_capture) -+ return -EINVAL; -+ -+ params = &tdm_capture->params; -+ -+ /* get TDM Capture's handle data */ -+ handle = xf_adsp_base_get_handle(tdm_capture->handle_id); -+ if (!handle) -+ return -EINVAL; -+ -+ b = xf_buffer_get(base->aux_pool); -+ msg_params = xf_buffer_data(b); -+ -+ i = 0; -+ /* PRQA S 3440 13 1*/ -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT1; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_INPUT2; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE; -+ msg_params->c.id[i++] = XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE; -+ -+ /* PRQA S 3200 2*/ -+ xf_create_msg(&msg -+ , __XF_MSG_ID(__XF_AP_CLIENT(0, tdm_capture->handle_id) -+ , __XF_PORT_SPEC2(handle->comp_id, 0)) -+ , XF_GET_PARAM, XF_GET_PARAM_CMD_LEN(i), msg_params, NULL); -+ -+ err = xf_send_and_receive(&msg); -+ if (err != 0) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* save the received parameters */ -+ i = 0; -+ params->in_rate = msg_params->r.value[i++]; /* PRQA S 3440 13 */ -+ params->ch_mode = msg_params->r.value[i++]; -+ params->pcm_width = msg_params->r.value[i++]; -+ params->frame_size = msg_params->r.value[i++]; -+ params->dev1 = msg_params->r.value[i++]; -+ params->dev2 = msg_params->r.value[i++]; -+ params->dma1 = msg_params->r.value[i++]; -+ params->dma2 = msg_params->r.value[i++]; -+ params->out_rate = msg_params->r.value[i++]; -+ params->vol_rate = msg_params->r.value[i++]; -+ -+exit: -+ /* return msg to pool */ -+ xf_buffer_put(b); -+ -+ return err; -+} -+ -+/** ************************************************************************** -+ *\brief create TDM Capture component -+ * -+ *\param[in,out] tdm_capture Pointer to the registered component -+ *\param[in] cb Callback function -+ *\param[in] private_data Private data -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base instance or register fail -+ *\retval -ENOMEM Cannot allocate Renderer instance -+ *****************************************************************************/ -+int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture -+ , struct xf_callback_func *cb, void *private_data) -+{ -+ struct xf_adsp_tdm_capture *tdm_cap; -+ int err; -+ int comp_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base) -+ return -EINVAL; -+ -+ tdm_cap = kmalloc(sizeof(*tdm_cap), GFP_KERNEL); -+ if (!tdm_cap) -+ return -ENOMEM; -+ -+ /* PRQA S 3200 */ -+ memset(tdm_cap, 0, sizeof(struct xf_adsp_tdm_capture)); -+ -+ /* register TDM Capture component */ -+ err = xf_adsp_register("tdm-capture", &comp_id); -+ if (err != 0) -+ goto err2; /* PRQA S 2001 */ -+ -+ /* register TDM Capture to ADSP base control */ -+ tdm_cap->handle_id = xf_adsp_base_register_handle(private_data -+ , cb, comp_id); -+ if (tdm_cap->handle_id <= 0) { -+ err = -EINVAL; -+ goto err1; /* PRQA S 2001 */ -+ } -+ -+ /* get the default parameter from plugin */ -+ err = xf_adsp_tdm_capture_get_params(tdm_cap); -+ if (err != 0) -+ goto err1; /* PRQA S 2001 */ -+ -+ /* save compoent data */ -+ *tdm_capture = tdm_cap; -+ -+ return 0; -+ -+err1: -+ xf_adsp_unregister(comp_id); /* PRQA S 3200 */ -+ -+err2: -+ kfree(tdm_cap); -+ -+ return err; -+} -+ -+/** *********************************************************** -+ *\brief deinitialize ADSP TDM Capture component -+ * -+ *\param[in] tdm_capture Pointer to TDM Capture component -+ *\retval 0 Success -+ *\retval -EINVAL Invalid base or Renderer data -+ **************************************************************/ -+/* PRQA S 3673 */ -+int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture) -+{ -+ struct xf_handle *handle; -+ int handle_id; -+ -+ /* check the sane ADSP base data */ -+ if (!base || !tdm_capture) -+ return -EINVAL; -+ -+ handle_id = tdm_capture->handle_id; -+ -+ handle = xf_adsp_base_get_handle(handle_id); -+ if (!handle) -+ goto exit; /* PRQA S 2001 */ -+ -+ /* unregister component */ -+ xf_adsp_unregister(handle->comp_id); /* PRQA S 3200 */ -+ -+ /* free handle data from base control */ -+ xf_adsp_base_free_handle(handle_id); /* PRQA S 3200 */ -+ -+exit: -+ kfree(tdm_capture); -+ -+ return 0; -+} -diff --git a/sound/soc/adsp/xf-adsp-base.h b/sound/soc/adsp/xf-adsp-base.h -new file mode 100644 -index 0000000..818ebdd ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-base.h -@@ -0,0 +1,276 @@ -+/** ************************************************************************* -+ *\file xf-adsp-base.h -+ *\brief Header file for ADSP Base Control layer -+ *\addtogroup ADSP Driver -+ **************************************************************************** -+ *\date Oct. 21, 2017 -+ *\author Renesas Electronics Corporation -+ **************************************************************************** -+ *\par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#ifndef __XF_ADSP_BASE_H -+#define __XF_ADSP_BASE_H -+ -+#include "xf-adsp-config.h" -+#include -+ -+#define XF_BUF_POOL_SIZE (4) /**< number of buffer in a data pool */ -+ -+/**< maximum number of DSP component can be registered */ -+#define MAX_HANDLE (256) -+ -+/* define boolean */ -+#define TRUE (1) -+#define FALSE (0) -+ -+/** \struct xf_callback_func -+ * \brief callback function for ADSP's response message -+ */ -+struct xf_callback_func { -+ /** callback for empty buffer done message */ -+ int (*empty_buf_done)(void *data, int opcode, int length, char *buffer); -+ -+ /** callback for fill buffer done message */ -+ int (*fill_buf_done)(void *data, int opcode, int length, char *buffer); -+ -+ /** callback for event handler */ -+ int (*event_handler)(void *data); -+}; -+ -+/** \struct xf_adsp_renderer_params -+ * \brief parameter structure for Renderer component -+ */ -+struct xf_adsp_renderer_params { -+ int channel; /**< channel number */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+ int out_channel; /**< output channels */ -+ int mix_ctrl; /**< mix control flag */ -+ int state; /**< operation state */ -+}; -+ -+/** \struct xf_adsp_renderer -+ * \brief Renderer component structure -+ */ -+struct xf_adsp_renderer { -+ struct xf_adsp_renderer_params params; /**< parameter structure*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle*/ -+}; -+ -+/** \struct xf_adsp_capture_params -+ *\brief parameter structure of Capture component -+ */ -+struct xf_adsp_capture_params { -+ int channel; /**< channel number */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+ int state; /**< operation state */ -+}; -+ -+/** \struct xf_adsp_capture -+ * \brief Capture component structure -+ */ -+struct xf_adsp_capture { -+ struct xf_adsp_capture_params params; /**< parameter structuer*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle*/ -+}; -+ -+/** \struct xf_equalizer_parametric_coef -+ *\brief Parametric Equalizer type's parameters -+ */ -+struct xf_equalizer_parametric_coef { -+ int type[XA_REL_EQZ_FILTER_NUM]; /**< Filter type*/ -+ int fc[XA_REL_EQZ_FILTER_NUM]; /**< Filter center frequency*/ -+ int gain[XA_REL_EQZ_FILTER_NUM]; /**< Filter gain*/ -+ int band_width[XA_REL_EQZ_FILTER_NUM]; /**< Filter band width */ -+ int gain_base[XA_REL_EQZ_FILTER_NUM]; /**< Filter base gain */ -+}; -+ -+/** \struct xf_equalizer_graphic_coef -+ * \brief Graphic Equalizer type's parameters -+ */ -+struct xf_equalizer_graphic_coef { -+ int gain_g[XA_REL_EQZ_GRAPHIC_BAND_NUM];/**< Graphic equalizer gain */ -+}; -+ -+/** \struct xf_adsp_equalizer_params -+ *\brief Equalizer parameters -+ */ -+struct xf_adsp_equalizer_params { -+ int channel; /**< channel number */ -+ int pcm_width; /**< PCM width */ -+ int rate; /**< sampling rate */ -+ int eqz_type; /**< Equalizer type */ -+ /**< Parametric parameters */ -+ struct xf_equalizer_parametric_coef p_coef; -+ struct xf_equalizer_graphic_coef g_coef; /**< Graphic parameters */ -+}; -+ -+/** \struct xf_adsp_equalizer -+ * \brief Equalizer component's structure -+ */ -+struct xf_adsp_equalizer { -+ struct xf_adsp_equalizer_params params;/**< Equalizer parameters */ -+ struct xf_pool *buf_pool; /**< buffer pool for transfer data */ -+ int handle_id; /**< ID of registered handle */ -+}; -+ -+/** \struct xf_adsp_tdm_renderer_params -+ * \brief parameter structure for TDM Renderer component -+ */ -+struct xf_adsp_tdm_renderer_params { -+ int ch_mode; /**< channel mode */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+}; -+ -+/** \struct xf_adsp_tdm_renderer -+ * \brief TDM Renderer component structure -+ */ -+struct xf_adsp_tdm_renderer { -+ struct xf_adsp_tdm_renderer_params params; /**< parameter structure*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle */ -+}; -+ -+/** \struct xf_adsp_tdm_capture_params -+ * \brief parameter structure for TDM Capture component -+ */ -+struct xf_adsp_tdm_capture_params { -+ int ch_mode; /**< channel mode */ -+ int pcm_width; /**< PCM width */ -+ int frame_size; /**< frame size */ -+ int in_rate; /**< input sampling rate */ -+ int out_rate; /**< output sampling rate */ -+ int vol_rate; /**< volume rate */ -+ int dev1; /**< 1st device index */ -+ int dev2; /**< 2nd device index */ -+ int dma1; /**< 1st DMA index */ -+ int dma2; /**< 2nd DMA index */ -+}; -+ -+/** \struct xf_adsp_tdm_capture -+ * \brief TDM Capture component structure -+ */ -+struct xf_adsp_tdm_capture { -+ struct xf_adsp_tdm_capture_params params; /**< parameter structure*/ -+ struct xf_pool *buf_pool; /**< buffer pool for data transfer */ -+ int handle_id; /**< ID of registered handle*/ -+}; -+ -+/** \struct xf_handle -+ * \brief Handle struct for each ADSP component -+ */ -+struct xf_handle { -+ int comp_id;/**< ADSP component ID */ -+ struct xf_callback_func *cb;/**< callback functions */ -+ void *private_data; /**< private data for callback functions*/ -+}; -+ -+/** \struct xf_adsp_base -+ * \brief Base component structure -+ */ -+struct xf_adsp_base { -+ xf_adsp_base_cmd_t cmd; /**< proxy commands */ -+ void *client;/**< client data which registered to proxy */ -+ struct xf_pool *aux_pool; /**< auxiliary buffer pool data */ -+ struct xf_handle *handle[MAX_HANDLE]; /**< handler data */ -+ struct task_struct *rsp_thread;/**< thread for response message*/ -+ wait_queue_head_t base_wait; /**< ADSP base's waiting queue */ -+ struct xf_message base_msg; /**< ADSP base's response message */ -+ int base_flag; /**< flag to control its waiting queue */ -+ int err_flag; /**< flag to indicate a error from plugins */ -+ int wait_flag; /**< flag to control the polling waiting*/ -+ spinlock_t lock; /**< spinlock data */ -+}; -+ -+struct xf_pool *xf_adsp_allocate_mem_pool(int pool_size, int buf_length); -+int xf_adsp_free_mem_pool(struct xf_pool *pool); -+char *xf_adsp_get_data_from_pool(struct xf_pool *pool, int index); -+ -+int xf_adsp_empty_this_buffer(int handle_id, char *buffer, int length); -+int xf_adsp_fill_this_buffer(int handle_id, char *buffer, int length); -+ -+int xf_adsp_route(int src_handle_id, int dst_handle_id -+ , int buf_cnt, int buf_size); -+ -+int xf_adsp_set_param(int handle_id, int index, int value); -+int xf_adsp_get_param(int handle_id, int index, int *value); -+ -+int xf_adsp_renderer_create(struct xf_adsp_renderer **renderer -+ , struct xf_callback_func *cb, void *private_data); -+int xf_adsp_renderer_destroy(struct xf_adsp_renderer *renderer); -+int xf_adsp_renderer_set_params(struct xf_adsp_renderer *renderer); -+int xf_adsp_renderer_get_params(struct xf_adsp_renderer *renderer); -+ -+int xf_adsp_capture_create(struct xf_adsp_capture **capture -+ , struct xf_callback_func *cb, void *private_data); -+int xf_adsp_capture_destroy(struct xf_adsp_capture *capture); -+int xf_adsp_capture_set_params(struct xf_adsp_capture *capture); -+int xf_adsp_capture_get_params(struct xf_adsp_capture *capture); -+ -+int xf_adsp_equalizer_create(struct xf_adsp_equalizer **equalizer -+ , struct xf_callback_func *cb, void *private_data); -+int xf_adsp_equalizer_destroy(struct xf_adsp_equalizer *equalizer); -+int xf_adsp_equalizer_set_params(struct xf_adsp_equalizer *equalizer); -+int xf_adsp_equalizer_get_params(struct xf_adsp_equalizer *equalizer); -+ -+int xf_adsp_tdm_renderer_create(struct xf_adsp_tdm_renderer **tdm_renderer -+ , struct xf_callback_func *cb -+ , void *private_data); -+int xf_adsp_tdm_renderer_destroy(struct xf_adsp_tdm_renderer *tdm_renderer); -+int xf_adsp_tdm_renderer_set_params(struct xf_adsp_tdm_renderer *tdm_renderer); -+int xf_adsp_tdm_renderer_get_params(struct xf_adsp_tdm_renderer *tdm_renderer); -+ -+int xf_adsp_tdm_capture_create(struct xf_adsp_tdm_capture **tdm_capture -+ , struct xf_callback_func *cb -+ , void *private_data); -+int xf_adsp_tdm_capture_destroy(struct xf_adsp_tdm_capture *tdm_capture); -+int xf_adsp_tdm_capture_set_params(struct xf_adsp_tdm_capture *tdm_capture); -+int xf_adsp_tdm_capture_get_params(struct xf_adsp_tdm_capture *tdm_capture); -+ -+#endif -diff --git a/sound/soc/adsp/xf-adsp-config.h b/sound/soc/adsp/xf-adsp-config.h -new file mode 100644 -index 0000000..7fc93ab ---- /dev/null -+++ b/sound/soc/adsp/xf-adsp-config.h -@@ -0,0 +1,604 @@ -+/** **************************************************************************** -+ *\file xf-adsp-config.h -+ *\brief Header file for ADSP configuration -+ *\addtogroup ADSP Driver -+ ******************************************************************************* -+ *\date Oct. 21, 2017 -+ *\author Renesas Electronics Corporation -+ ******************************************************************************* -+ *\par Copyright -+ * -+ * Copyright(c) 2016 Renesas Electoronics Corporation -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ ******************************************************************************/ -+ -+#ifndef __XF_ADSP_CONFIG_H -+#define __XF_ADSP_CONFIG_H -+ -+/* Equalizer definition */ -+#define XA_REL_EQZ_FILTER_NUM (9) /**< number of filter */ -+#define XA_REL_EQZ_GRAPHIC_BAND_NUM (5) /**< number of graphic band */ -+ -+struct xf_buffer { -+ void *address; -+ union { /* PRQA S 750 3 */ -+ struct xf_buffer *next; -+ struct xf_pool *pool; -+ } link; -+}; -+ -+struct xf_pool { -+ /* length of individual buffer in a pool */ -+ u32 length; -+ -+ /* number of buffer in a pool */ -+ u32 number; -+ -+ /* pointer to pool memory */ -+ void *p; -+ -+ /* pointer to first free buffer in a pool */ -+ struct xf_buffer *free; -+ -+ /* individual buffer */ -+ struct xf_buffer buffer[0]; /* PRQA S 1037 */ -+}; -+ -+struct xf_message { -+ /* pointer to the next item in the list */ -+ struct xf_message *next; -+ -+ /* shmem session_id */ -+ u32 id; -+ -+ /* operation code */ -+ u32 opcode; -+ -+ /* length of attached message buffer */ -+ u32 length; -+ -+ /* message buffer */ -+ void *buffer; -+}; -+ -+/******************************************************************************* -+ * XF_GET_PARAM message -+ ******************************************************************************/ -+ -+/* ...message body (command/response) */ -+union xf_get_param_msg { /* PRQA S 750 18 */ -+ /* ...command structure */ -+ struct { -+ /* ...array of parameters requested */ -+ u32 id[0]; /* PRQA S 1037 */ -+ -+ } __attribute__((__packed__)) c; -+ -+ /* ...response structure */ -+ struct { -+ /* ...array of parameters values */ -+ u32 value[0];/* PRQA S 1037 */ -+ -+ } __attribute__((__packed__)) r; -+ -+}; -+ -+/* ...length of the XF_GET_PARAM command/response */ -+/* PRQA S 3453 2 */ -+#define XF_GET_PARAM_CMD_LEN(params) (sizeof(u32) * (params)) -+#define XF_GET_PARAM_RSP_LEN(params) (sizeof(u32) * (params)) -+ -+/******************************************************************************* -+ * XF_SET_PARAM message -+ ******************************************************************************/ -+ -+/* ...component initialization parameter */ -+struct xf_set_param_item { -+ /* ...index of parameter passed to SET_CONFIG_PARAM call */ -+ u32 id; -+ -+ /* ...value of parameter */ -+ u32 value; -+ -+} __attribute__ ((__packed__)); -+ -+/* ...message body (no response message? - tbd) */ -+struct xf_set_param_msg { -+ /* ...command message */ -+ struct xf_set_param_item item[0]; /* PRQA S 1037 */ -+ -+} __attribute__ ((__packed__)); -+ -+/* ...length of the command message */ -+/* PRQA S 3453 */ -+#define XF_SET_PARAM_CMD_LEN(params) \ -+ (sizeof(struct xf_set_param_item) * (params)) -+ -+/******************************************************************************* -+ * XF_ROUTE definition -+ ******************************************************************************/ -+ -+/* ...port routing command */ -+struct xf_route_port_msg { -+ /* ...source port specification */ -+ u32 src; -+ -+ /* ...destination port specification */ -+ u32 dst; -+ -+ /* ...number of buffers to allocate */ -+ u32 alloc_number; -+ -+ /* ...length of buffer to allocate */ -+ u32 alloc_size; -+ -+ /* ...alignment restriction for a buffer */ -+ u32 alloc_align; -+ -+} __attribute__((__packed__)); -+ -+/******************************************************************************* -+ * XF_UNROUTE definition -+ ******************************************************************************/ -+ -+/* ...port unrouting command */ -+struct xf_unroute_port_msg { -+ /* ...source port specification */ -+ u32 src; -+ -+ /* ...destination port specification */ -+ u32 dst; -+ -+} __attribute__((__packed__)); -+ -+/* ...Capture states */ -+enum xa_capture_state { -+ XA_CAP_STATE_RUN = 0, -+ XA_CAP_STATE_IDLE = 1, -+ XA_CAP_STATE_PAUSE = 2 -+}; -+ -+/* ...Renderer states */ -+enum xa_renderer_state { -+ XA_RDR_STATE_RUN = 0, -+ XA_RDR_STATE_IDLE = 1, -+ XA_RDR_STATE_PAUSE = 2 -+}; -+ -+/******************************************************************************* -+ * Message routing composition - move somewhere else - tbd -+ ******************************************************************************/ -+ -+/* ...adjust IPC client of message going from user-space */ -+#define XF_MSG_AP_FROM_USER(id, client) \ -+ (((id) & ~(0xF << 2)) | ((client) << 2)) -+ -+/* ...wipe out IPC client from message going to user-space */ -+#define XF_MSG_AP_TO_USER(id) \ -+ ((id) & ~(0xF << 18)) -+ -+/* ...port specification (12 bits) */ -+#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8)) -+#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8)) -+#define XF_PORT_CORE(spec) ((spec) & 0x3) -+#define XF_PORT_CLIENT(spec) (((spec) >> 2) & 0x3F) -+#define XF_PORT_ID(spec) (((spec) >> 8) & 0xF) -+ -+/* ...message id contains source and destination ports specification */ -+#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) -+#define XF_MSG_SRC(id) (((id) >> 0) & 0xFFFF) -+#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3) -+#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F) -+#define XF_MSG_SRC_PORT(id) (((id) >> 8) & 0xF) -+#define XF_MSG_SRC_PROXY(id) (((id) >> 15) & 0x1) -+#define XF_MSG_DST(id) (((id) >> 16) & 0xFFFF) -+#define XF_MSG_DST_CORE(id) (((id) >> 16) & 0x3) -+#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F) -+#define XF_MSG_DST_PORT(id) (((id) >> 24) & 0xF) -+#define XF_MSG_DST_PROXY(id) (((id) >> 31) & 0x1) -+ -+/* ...special treatment of AP-proxy destination field */ -+#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) -+#define XF_AP_CLIENT(id) (((id) >> 22) & 0x1FF) -+#define __XF_AP_PROXY(core) ((core) | 0x8000) -+#define __XF_DSP_PROXY(core) ((core) | 0x8000) -+#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 0x8000) -+ -+/******************************************************************************* -+ * Opcode composition -+ ******************************************************************************/ -+ -+/* ...opcode composition with command/response data tags */ -+#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) -+ -+/* ...accessors */ -+#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31)) -+#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30)) -+#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F)) -+ -+/******************************************************************************* -+ * Opcode types -+ ******************************************************************************/ -+ -+/* ...unregister client */ -+#define XF_UNREGISTER __XF_OPCODE(0, 0, 0) -+ -+/* ...register client at proxy */ -+#define XF_REGISTER __XF_OPCODE(1, 0, 1) -+ -+/* ...port routing command */ -+#define XF_ROUTE __XF_OPCODE(1, 0, 2) -+ -+/* ...port unrouting command */ -+#define XF_UNROUTE __XF_OPCODE(1, 0, 3) -+ -+/* ...shared buffer allocation */ -+#define XF_ALLOC __XF_OPCODE(0, 0, 4) -+ -+/* ...shared buffer freeing */ -+#define XF_FREE __XF_OPCODE(0, 0, 5) -+ -+/* ...set component parameters */ -+#define XF_SET_PARAM __XF_OPCODE(1, 0, 6) -+ -+/* ...get component parameters */ -+#define XF_GET_PARAM __XF_OPCODE(1, 1, 7) -+ -+/* ...input buffer reception */ -+#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8) -+ -+/* ...output buffer reception */ -+#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9) -+ -+/* ...flush specific port */ -+#define XF_FLUSH __XF_OPCODE(0, 0, 10) -+ -+/* ...start component operation */ -+#define XF_START __XF_OPCODE(0, 0, 11) -+ -+/* ...stop component operation */ -+#define XF_STOP __XF_OPCODE(0, 0, 12) -+ -+/* ...pause component operation */ -+#define XF_PAUSE __XF_OPCODE(0, 0, 13) -+ -+/* ...resume component operation */ -+#define XF_RESUME __XF_OPCODE(0, 0, 14) -+ -+/* ...total amount of supported decoder commands */ -+#define __XF_OP_NUM (15) -+ -+/************************************************* -+ * Renderer - specific configuration parameters -+ * **********************************************/ -+ -+enum xa_config_param_renderer { -+ XA_RDR_CONFIG_PARAM_STATE = 0, -+ XA_RDR_CONFIG_PARAM_PCM_WIDTH = 1, -+ XA_RDR_CONFIG_PARAM_CHANNELS = 2, -+ XA_RDR_CONFIG_PARAM_SAMPLE_RATE = 3, -+ XA_RDR_CONFIG_PARAM_FRAME_SIZE = 4, -+ XA_RDR_CONFIG_PARAM_OUTPUT1 = 5, -+ XA_RDR_CONFIG_PARAM_DMACHANNEL1 = 6, -+ XA_RDR_CONFIG_PARAM_OUTPUT2 = 7, -+ XA_RDR_CONFIG_PARAM_DMACHANNEL2 = 8, -+ XA_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 9, -+ XA_RDR_CONFIG_PARAM_VOLUME_RATE = 10, -+ XA_RDR_CONFIG_PARAM_OUT_CHANNELS = 11, -+ XA_RDR_CONFIG_PARAM_MIX_CONTROL = 12, -+ XA_RDR_CONFIG_PARAM_NUM = 13 -+}; -+ -+/************************************************* -+ * Capture - specific configuration parameters -+ * **********************************************/ -+ -+enum xa_config_param_capture { -+ XA_CAP_CONFIG_PARAM_CB = 0, -+ XA_CAP_CONFIG_PARAM_STATE = 1, -+ XA_CAP_CONFIG_PARAM_PCM_WIDTH = 2, -+ XA_CAP_CONFIG_PARAM_CHANNELS = 3, -+ XA_CAP_CONFIG_PARAM_SAMPLE_RATE = 4, -+ XA_CAP_CONFIG_PARAM_FRAME_SIZE = 5, -+ XA_CAP_CONFIG_PARAM_INPUT1 = 6, -+ XA_CAP_CONFIG_PARAM_DMACHANNEL1 = 7, -+ XA_CAP_CONFIG_PARAM_INPUT2 = 8, -+ XA_CAP_CONFIG_PARAM_DMACHANNEL2 = 9, -+ XA_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 10, -+ XA_CAP_CONFIG_PARAM_VOLUME_RATE = 11, -+ XA_CAP_CONFIG_PARAM_NUM = 12 -+}; -+ -+/************************************************* -+ * Equalizer - specific configuration parameters -+ * **********************************************/ -+ -+enum xa_rel_eqz_filter_type { -+ XA_REL_EQZ_TYPE_THROUGH = 0, -+ XA_REL_EQZ_TYPE_PEAK = 1, -+ XA_REL_EQZ_TYPE_BASS = 2, -+ XA_REL_EQZ_TYPE_TREBLE = 3 -+}; -+ -+enum xa_rel_eqz_type { -+ XA_REL_EQZ_TYPE_PARAMETRIC = 0, -+ XA_REL_EQZ_TYPE_GRAPHIC = 1 -+}; -+ -+/*****************************************************************************/ -+/* Additional subcommand indices */ -+/*****************************************************************************/ -+ -+enum xa_add_cmd_type_generic { -+ /* XA_API_CMD_SET_CONFIG_PARAM indices */ -+ XA_EQZ_CONFIG_PARAM_COEF_FS = 0x0000, -+ XA_EQZ_CONFIG_PARAM_PCM_WIDTH = 0x0001, -+ XA_EQZ_CONFIG_PARAM_CH = 0x0002, -+ XA_EQZ_CONFIG_PARAM_EQZ_TYPE = 0x0003, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_FC = 0x0010, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_FC = 0x0011, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_FC = 0x0012, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_FC = 0x0013, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_FC = 0x0014, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_FC = 0x0015, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_FC = 0x0016, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_FC = 0x0017, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_FC = 0x0018, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_TYPE = 0x0020, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_TYPE = 0x0021, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_TYPE = 0x0022, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_TYPE = 0x0023, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_TYPE = 0x0024, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_TYPE = 0x0025, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_TYPE = 0x0026, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_TYPE = 0x0027, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_TYPE = 0x0028, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BW = 0x0030, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BW = 0x0031, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BW = 0x0032, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BW = 0x0033, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BW = 0x0034, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BW = 0x0035, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BW = 0x0036, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BW = 0x0037, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BW = 0x0038, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_GA = 0x0040, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_GA = 0x0041, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_GA = 0x0042, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_GA = 0x0043, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_GA = 0x0044, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_GA = 0x0045, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_GA = 0x0046, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_GA = 0x0047, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_GA = 0x0048, -+ -+ XA_EQZ_CONFIG_PARAM_FILTER_0_COEF_BA = 0x0050, -+ XA_EQZ_CONFIG_PARAM_FILTER_1_COEF_BA = 0x0051, -+ XA_EQZ_CONFIG_PARAM_FILTER_2_COEF_BA = 0x0052, -+ XA_EQZ_CONFIG_PARAM_FILTER_3_COEF_BA = 0x0053, -+ XA_EQZ_CONFIG_PARAM_FILTER_4_COEF_BA = 0x0054, -+ XA_EQZ_CONFIG_PARAM_FILTER_5_COEF_BA = 0x0055, -+ XA_EQZ_CONFIG_PARAM_FILTER_6_COEF_BA = 0x0056, -+ XA_EQZ_CONFIG_PARAM_FILTER_7_COEF_BA = 0x0057, -+ XA_EQZ_CONFIG_PARAM_FILTER_8_COEF_BA = 0x0058, -+ -+ XA_EQZ_CONFIG_PARAM_BAND_0_GCOEF_GA = 0x0060, -+ XA_EQZ_CONFIG_PARAM_BAND_1_GCOEF_GA = 0x0061, -+ XA_EQZ_CONFIG_PARAM_BAND_2_GCOEF_GA = 0x0062, -+ XA_EQZ_CONFIG_PARAM_BAND_3_GCOEF_GA = 0x0063, -+ XA_EQZ_CONFIG_PARAM_BAND_4_GCOEF_GA = 0x0064 -+}; -+ -+/* ...tdm-renderer-specific configuration parameters */ -+enum xa_config_param_tdm_renderer { -+ XA_TDM_RDR_CONFIG_PARAM_PCM_WIDTH = 0, -+ XA_TDM_RDR_CONFIG_PARAM_CHANNEL_MODE = 1, -+ XA_TDM_RDR_CONFIG_PARAM_IN_SAMPLE_RATE = 2, -+ XA_TDM_RDR_CONFIG_PARAM_FRAME_SIZE = 3, -+ XA_TDM_RDR_CONFIG_PARAM_OUTPUT1 = 4, -+ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL1 = 5, -+ XA_TDM_RDR_CONFIG_PARAM_OUTPUT2 = 6, -+ XA_TDM_RDR_CONFIG_PARAM_DMACHANNEL2 = 7, -+ XA_TDM_RDR_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, -+ XA_TDM_RDR_CONFIG_PARAM_VOLUME_RATE = 9 -+}; -+ -+enum xa_rel_tdm_renderer_channel_mode { -+ XA_TDM_RDR_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ -+ XA_TDM_RDR_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ -+ /**< 1 six-channels plus 1 two-channels TDM data */ -+ XA_TDM_RDR_CHANNEL_MODE_6_2 = 2, -+ XA_TDM_RDR_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ -+ XA_TDM_RDR_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ -+}; -+ -+/* ...TDM Capture-specific configuration parameters */ -+enum xa_config_param_tdm_capture { -+ XA_TDM_CAP_CONFIG_PARAM_PCM_WIDTH = 0, -+ XA_TDM_CAP_CONFIG_PARAM_CHANNEL_MODE = 1, -+ XA_TDM_CAP_CONFIG_PARAM_IN_SAMPLE_RATE = 2, -+ XA_TDM_CAP_CONFIG_PARAM_FRAME_SIZE = 3, -+ XA_TDM_CAP_CONFIG_PARAM_INPUT1 = 4, -+ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL1 = 5, -+ XA_TDM_CAP_CONFIG_PARAM_INPUT2 = 6, -+ XA_TDM_CAP_CONFIG_PARAM_DMACHANNEL2 = 7, -+ XA_TDM_CAP_CONFIG_PARAM_OUT_SAMPLE_RATE = 8, -+ XA_TDM_CAP_CONFIG_PARAM_VOLUME_RATE = 9 -+}; -+ -+enum xa_rel_tdm_capture_channel_mode { -+ XA_TDM_CAP_CHANNEL_MODE_2X4 = 0, /**< 4 stereo TDM data */ -+ XA_TDM_CAP_CHANNEL_MODE_1X8 = 1, /**< 1 eight-channel TDM data*/ -+ /**< 1 six-channels plus 1 two-channels TDM data */ -+ XA_TDM_CAP_CHANNEL_MODE_6_2 = 2, -+ XA_TDM_CAP_CHANNEL_MODE_2X3 = 3, /**< 3 stereo TDM data */ -+ XA_TDM_CAP_CHANNEL_MODE_1X6 = 4 /**< 1 six-channel TDM data */ -+}; -+ -+/*****************************************************************************/ -+/* HW supported */ -+/*****************************************************************************/ -+/* ...SSI modules supported by HW */ -+enum ssi_module { -+ SSI00 = 0, -+ SSI01 = 1, -+ SSI02 = 2, -+ SSI03 = 3, -+ SSI04 = 4, -+ SSI05 = 5, -+ SSI06 = 6, -+ SSI07 = 7, -+ SSI10 = 10, -+ SSI11 = 11, -+ SSI12 = 12, -+ SSI13 = 13, -+ SSI14 = 14, -+ SSI15 = 15, -+ SSI16 = 16, -+ SSI17 = 17, -+ SSI20 = 20, -+ SSI21 = 21, -+ SSI22 = 22, -+ SSI23 = 23, -+ SSI24 = 24, -+ SSI25 = 25, -+ SSI26 = 26, -+ SSI27 = 27, -+ SSI30 = 30, -+ SSI31 = 31, -+ SSI32 = 32, -+ SSI33 = 33, -+ SSI34 = 34, -+ SSI35 = 35, -+ SSI36 = 36, -+ SSI37 = 37, -+ SSI40 = 40, -+ SSI41 = 41, -+ SSI42 = 42, -+ SSI43 = 43, -+ SSI44 = 44, -+ SSI45 = 45, -+ SSI46 = 46, -+ SSI47 = 47, -+ SSI5 = 50, -+ SSI6 = 60, -+ SSI7 = 70, -+ SSI8 = 80, -+ SSI90 = 90, -+ SSI91 = 91, -+ SSI92 = 92, -+ SSI93 = 93, -+ SSI94 = 94, -+ SSI95 = 95, -+ SSI96 = 96, -+ SSI97 = 97 -+}; -+ -+/* ...SRC modules supported by HW */ -+enum src_module { -+ SRC0 = 110, /* SRC0 */ -+ SRC1 = 111, /* SRC1 */ -+ SRC2 = 112, /* SRC2 */ -+ SRC3 = 113, /* SRC3 */ -+ SRC4 = 114, /* SRC4 */ -+ SRC5 = 115, /* SRC5 */ -+ SRC6 = 116, /* SRC6 */ -+ SRC7 = 117, /* SRC7 */ -+ SRC8 = 118, /* SRC8 */ -+ SRC9 = 119, /* SRC9 */ -+ SRCMAX = 120 /* Maximum number of SRC modules */ -+}; -+ -+/* ...PDMA supported by HW */ -+enum { -+ PDMA_CH00 = 0, -+ PDMA_CH01 = 1, -+ PDMA_CH02 = 2, -+ PDMA_CH03 = 3, -+ PDMA_CH04 = 4, -+ PDMA_CH05 = 5, -+ PDMA_CH06 = 6, -+ PDMA_CH07 = 7, -+ PDMA_CH08 = 8, -+ PDMA_CH09 = 9, -+ PDMA_CH10 = 10, -+ PDMA_CH11 = 11, -+ PDMA_CH12 = 12, -+ PDMA_CH13 = 13, -+ PDMA_CH14 = 14, -+ PDMA_CH15 = 15, -+ PDMA_CH16 = 16, -+ PDMA_CH17 = 17, -+ PDMA_CH18 = 18, -+ PDMA_CH19 = 19, -+ PDMA_CH20 = 20, -+ PDMA_CH21 = 21, -+ PDMA_CH22 = 22, -+ PDMA_CH23 = 23, -+ PDMA_CH24 = 24, -+ PDMA_CH25 = 25, -+ PDMA_CH26 = 26, -+ PDMA_CH27 = 27, -+ PDMA_CH28 = 28, -+ PDMA_CHMAX = 29 -+}; -+ -+/* ...DMAC supported by HW */ -+enum { -+ ADMAC_CH00 = PDMA_CHMAX + 0, -+ ADMAC_CH01 = PDMA_CHMAX + 1, -+ ADMAC_CH02 = PDMA_CHMAX + 2, -+ ADMAC_CH03 = PDMA_CHMAX + 3, -+ ADMAC_CH04 = PDMA_CHMAX + 4, -+ ADMAC_CH05 = PDMA_CHMAX + 5, -+ ADMAC_CH06 = PDMA_CHMAX + 6, -+ ADMAC_CH07 = PDMA_CHMAX + 7, -+ ADMAC_CH08 = PDMA_CHMAX + 8, -+ ADMAC_CH09 = PDMA_CHMAX + 9, -+ ADMAC_CH10 = PDMA_CHMAX + 10, -+ ADMAC_CH11 = PDMA_CHMAX + 11, -+ ADMAC_CH12 = PDMA_CHMAX + 12, -+ ADMAC_CH13 = PDMA_CHMAX + 13, -+ ADMAC_CH14 = PDMA_CHMAX + 14, -+ ADMAC_CH15 = PDMA_CHMAX + 15, -+ ADMAC_CH16 = PDMA_CHMAX + 16, -+ ADMAC_CH17 = PDMA_CHMAX + 17, -+ ADMAC_CH18 = PDMA_CHMAX + 18, -+ ADMAC_CH19 = PDMA_CHMAX + 19, -+ ADMAC_CH20 = PDMA_CHMAX + 20, -+ ADMAC_CH21 = PDMA_CHMAX + 21, -+ ADMAC_CH22 = PDMA_CHMAX + 22, -+ ADMAC_CH23 = PDMA_CHMAX + 23, -+ ADMAC_CH24 = PDMA_CHMAX + 24, -+ ADMAC_CH25 = PDMA_CHMAX + 25, -+ ADMAC_CH26 = PDMA_CHMAX + 26, -+ ADMAC_CH27 = PDMA_CHMAX + 27, -+ ADMAC_CH28 = PDMA_CHMAX + 28, -+ ADMAC_CH29 = PDMA_CHMAX + 29, -+ ADMAC_CH30 = PDMA_CHMAX + 30, -+ ADMAC_CH31 = PDMA_CHMAX + 31, -+ ADMAC_CHMAX = PDMA_CHMAX + 32 -+}; -+ -+#endif --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch deleted file mode 100644 index d068e6d..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch +++ /dev/null @@ -1,32 +0,0 @@ -From bcf876462ac57204cf9054ba6cc5d0703b9beb5e Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:48 +0900 -Subject: [PATCH 3/6] arm64: dts: r8a7795-salvator-x: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts -index 6156bcc521b2..1f1920270aa4 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts -@@ -117,12 +117,6 @@ - status = "okay"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1 /* HDMI0 */ -- &rsnd_port2>; /* HDMI1 */ --}; -- - &hdmi0 { - status = "okay"; - --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch new file mode 100644 index 0000000..6d95d65 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch @@ -0,0 +1,185 @@ +From 825517f3f8ebe551d297db16e4582c0eae646f05 Mon Sep 17 00:00:00 2001 +From: tienphitran +Date: Wed, 31 Oct 2018 16:12:36 +0700 +Subject: [PATCH 4/6] ADSP: integrate ADSP sound for H3, M3, M3N board + +Signed-off-by: tienphitran +[takeshi.kihara.df: fix W=1 dtc warning] +Signed-off-by: Takeshi Kihara +--- + arch/arm64/boot/dts/renesas/r8a7795.dtsi | 5 ++ + arch/arm64/boot/dts/renesas/r8a7796.dtsi | 5 ++ + arch/arm64/boot/dts/renesas/r8a77965.dtsi | 5 ++ + .../boot/dts/renesas/salvator-common.dtsi | 84 +++++++++++++++++-- + 4 files changed, 94 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi +index 1896e5250dff..8dfda0fda91c 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi +@@ -793,6 +793,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi +index c00d1da64198..726c0d07fe59 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi +@@ -798,6 +798,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi +index 454a67b132f4..799b005ade92 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi +@@ -227,6 +227,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +index 922b9cc4797c..2c1d49c4bcaa 100644 +--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi ++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi +@@ -153,11 +153,27 @@ + }; + + sound_card: sound { +- compatible = "audio-graph-card"; ++ compatible = "audio-graph-scu-card"; + + label = "rcar-sound"; + +- dais = <&rsnd_port0>; ++ prefix = "ak4613"; ++ routing = "ak4613 Playback", "Playback0", ++ "ak4613 Playback", "Playback1", ++ "ak4613 Playback", "Playback2", ++ "ak4613 Playback", "Playback3", ++ "Capture0", "ak4613 Capture", ++ "Capture1", "ak4613 Capture", ++ "Capture2", "ak4613 Capture", ++ "Capture3", "ak4613 Capture", ++ "ak4613 Playback", "DAI0 Playback", ++ "DAI0 Capture", "ak4613 Capture"; ++ ++ dais = <&adsp_port0 ++ &adsp_port1 ++ &adsp_port2 ++ &adsp_port3 ++ &rsnd_port0>; + }; + + vbus0_usb2: regulator-vbus0-usb2 { +@@ -419,8 +435,27 @@ + asahi-kasei,out5-single-end; + asahi-kasei,out6-single-end; + +- port { +- ak4613_endpoint: endpoint { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ak4613_endpoint0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&adsp_endpoint0>; ++ }; ++ ak4613_endpoint1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&adsp_endpoint1>; ++ }; ++ ak4613_endpoint2: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&adsp_endpoint2>; ++ }; ++ ak4613_endpoint3: endpoint@3 { ++ reg = <3>; ++ remote-endpoint = <&adsp_endpoint3>; ++ }; ++ ak4613_endpoint4: endpoint@4 { ++ reg = <4>; + remote-endpoint = <&rsnd_endpoint0>; + }; + }; +@@ -731,6 +766,45 @@ + status = "okay"; + }; + ++&rcar_adsp_sound { ++ status = "okay"; ++ /* Multiple DAI */ ++ #sound-dai-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adsp_port0: port@0 { ++ reg = <0>; ++ adsp_endpoint0: endpoint { ++ remote-endpoint = <&ak4613_endpoint0>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port1: port@1 { ++ reg = <1>; ++ adsp_endpoint1: endpoint { ++ remote-endpoint = <&ak4613_endpoint1>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port2: port@2 { ++ reg = <2>; ++ adsp_endpoint2: endpoint { ++ remote-endpoint = <&ak4613_endpoint2>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port3: port@3 { ++ reg = <3>; ++ adsp_endpoint3: endpoint { ++ remote-endpoint = <&ak4613_endpoint3>; ++ dai-format = "left_j"; ++ }; ++ }; ++ }; ++}; ++ + &rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; +@@ -769,7 +843,7 @@ + rsnd_port0: port@0 { + reg = <0>; + rsnd_endpoint0: endpoint { +- remote-endpoint = <&ak4613_endpoint>; ++ remote-endpoint = <&ak4613_endpoint4>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-Update-device-tree-for-ADSP-sound-driver.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-Update-device-tree-for-ADSP-sound-driver.patch deleted file mode 100644 index 2586dac..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-Update-device-tree-for-ADSP-sound-driver.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 81528aacc64df60f2471873deca3f1092d47b6ae Mon Sep 17 00:00:00 2001 -From: tienphitran -Date: Mon, 15 Oct 2018 17:56:29 +0700 -Subject: [PATCH 4/4] Update device tree for ADSP sound driver - -Signed-off-by: tienphitran - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi -index 1c8e713..1331a09 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi -@@ -2161,6 +2161,11 @@ - status = "disabled"; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi -index f25b476..ed332e7 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi -@@ -2067,6 +2067,11 @@ - status = "disabled"; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi -index d86bf9e..05861b4 100644 ---- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi -@@ -1478,6 +1478,11 @@ - }; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts -index 10a3403..b96ae07 100644 ---- a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts -+++ b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts -@@ -356,11 +356,26 @@ - }; - - sound_card: sound { -- compatible = "audio-graph-card"; -+ compatible = "audio-graph-scu-card"; - - label = "rcar-sound"; -- -- dais = <&rsnd_port0>; -+ prefix = "ak4613"; -+ routing = "ak4613 Playback", "DAI0 Playback", -+ "DAI0 Capture", "ak4613 Capture", -+ "ak4613 Playback", "Playback0", -+ "ak4613 Playback", "Playback1", -+ "ak4613 Playback", "Playback2", -+ "ak4613 Playback", "Playback3", -+ "Capture0", "ak4613 Capture", -+ "Capture1", "ak4613 Capture", -+ "Capture2", "ak4613 Capture", -+ "Capture3", "ak4613 Capture"; -+ -+ dais = <&adsp_port0 -+ &adsp_port1 -+ &adsp_port2 -+ &adsp_port3 -+ &rsnd_port0>; - }; - }; - -@@ -567,7 +582,19 @@ - asahi-kasei,out6-single-end; - - port { -- ak4613_endpoint: endpoint { -+ ak4613_endpoint0: endpoint@0 { -+ remote-endpoint = <&adsp_endpoint0>; -+ }; -+ ak4613_endpoint1: endpoint@1 { -+ remote-endpoint = <&adsp_endpoint1>; -+ }; -+ ak4613_endpoint2: endpoint@2 { -+ remote-endpoint = <&adsp_endpoint2>; -+ }; -+ ak4613_endpoint3: endpoint@3 { -+ remote-endpoint = <&adsp_endpoint3>; -+ }; -+ ak4613_endpoint4: endpoint@4 { - remote-endpoint = <&rsnd_endpoint0>; - }; - }; -@@ -766,6 +793,39 @@ - shared-pin; - }; - -+&rcar_adsp_sound { -+ status = "okay"; -+ /* Multiple DAI */ -+ #sound-dai-cells = <1>; -+ -+ ports { -+ adsp_port0: port@0 { -+ adsp_endpoint0: endpoint@0 { -+ remote-endpoint = <&ak4613_endpoint0>; -+ dai-format = "left_j"; -+ }; -+ }; -+ adsp_port1: port@1 { -+ adsp_endpoint1: endpoint@1 { -+ remote-endpoint = <&ak4613_endpoint1>; -+ dai-format = "left_j"; -+ }; -+ }; -+ adsp_port2: port@2 { -+ adsp_endpoint2: endpoint@2 { -+ remote-endpoint = <&ak4613_endpoint2>; -+ dai-format = "left_j"; -+ }; -+ }; -+ adsp_port3: port@3 { -+ adsp_endpoint3: endpoint@3 { -+ remote-endpoint = <&ak4613_endpoint3>; -+ dai-format = "left_j"; -+ }; -+ }; -+ }; -+}; -+ - &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; - pinctrl-names = "default"; -@@ -801,7 +861,7 @@ - ports { - rsnd_port0: port@0 { - rsnd_endpoint0: endpoint { -- remote-endpoint = <&ak4613_endpoint>; -+ remote-endpoint = <&ak4613_endpoint4>; - - dai-format = "left_j"; - bitclock-master = <&rsnd_endpoint0>; -diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi -index 242de2c..870bd4e 100644 ---- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi -+++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi -@@ -1276,6 +1276,11 @@ - }; - }; - -+ rcar_adsp_sound: adsp_sound@0 { -+ compatible = "renesas,rcar_adsp_sound_gen3"; -+ status = "disabled"; -+ }; -+ - rcar_sound: sound@ec500000 { - /* - * #sound-dai-cells is required -diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -index 6cda028..89fbcf6 100644 ---- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi -+++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi -@@ -125,12 +125,43 @@ - regulator-boot-on; - regulator-always-on; - }; -+ - rsnd_ak4613: sound { -- compatible = "simple-audio-card"; -+ compatible = "simple-scu-audio-card"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&sndcpu>; - simple-audio-card,frame-master = <&sndcpu>; -- sndcpu: simple-audio-card,cpu { -+ -+ simple-audio-card,name = "audio-card"; -+ simple-audio-card,prefix = "ak4613"; -+ simple-audio-card,routing = "ak4613 Playback", "Playback0", -+ "ak4613 Playback", "Playback1", -+ "ak4613 Playback", "Playback2", -+ "ak4613 Playback", "Playback3", -+ "Capture0", "ak4613 Capture", -+ "Capture1", "ak4613 Capture", -+ "Capture2", "ak4613 Capture", -+ "Capture3", "ak4613 Capture", -+ "ak4613 Playback", "DAI0 Playback", -+ "DAI0 Capture", "ak4613 Capture"; -+ -+ sndcpu: simple-audio-card,cpu@0 { -+ sound-dai = <&rcar_adsp_sound 0>; -+ }; -+ -+ simple-audio-card,cpu@1 { -+ sound-dai = <&rcar_adsp_sound 1>; -+ }; -+ -+ simple-audio-card,cpu@2 { -+ sound-dai = <&rcar_adsp_sound 2>; -+ }; -+ -+ simple-audio-card,cpu@3 { -+ sound-dai = <&rcar_adsp_sound 3>; -+ }; -+ -+ simple-audio-card,cpu@4 { - sound-dai = <&rcar_sound>; - }; - -@@ -139,7 +170,6 @@ - }; - }; - -- - vbus0_usb2: regulator-vbus0-usb2 { - compatible = "regulator-fixed"; - -@@ -763,6 +793,12 @@ - status = "okay"; - }; - -+&rcar_adsp_sound { -+ status = "okay"; -+ /* Multiple DAI */ -+ #sound-dai-cells = <1>; -+}; -+ - &rcar_sound { - pinctrl-0 = <&sound_pins &sound_clk_pins>; - pinctrl-names = "default"; --- -2.7.4 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch deleted file mode 100644 index b740cfe..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 47fe276f805a83ef155bd9c16aea9fb16a3a931d Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:48:54 +0900 -Subject: [PATCH 4/6] arm64: dts: r8a7795-salvator-xs: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts -index b37b1de9d51a..286a8ffbdce5 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts -@@ -127,12 +127,6 @@ - status = "okay"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1 /* HDMI0 */ -- &rsnd_port2>; /* HDMI1 */ --}; -- - &hdmi0 { - status = "okay"; - --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch new file mode 100644 index 0000000..34b32d8 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-ADSP-integrate-ADSP-sound-for-E3-board.patch @@ -0,0 +1,272 @@ +From 455f26d0de1cf6eaeb0aa5b58725e3e34d8d34bd Mon Sep 17 00:00:00 2001 +From: Nguyen Dang +Date: Tue, 6 Nov 2018 11:36:15 +0700 +Subject: [PATCH 5/6] ADSP: integrate ADSP sound for E3 board + +Signed-off-by: Nguyen Dang +[takeshi.kihara.df: fix W=1 dtc warning] +[takeshi.kihara.df: support for dt file separation by E3 ES1.0 SoC] +Signed-off-by: Takeshi Kihara +--- + .../arm64/boot/dts/renesas/r8a77990-ebisu.dts | 84 +++++++++++++++++-- + .../boot/dts/renesas/r8a77990-es10-ebisu.dts | 84 +++++++++++++++++-- + arch/arm64/boot/dts/renesas/r8a77990.dtsi | 5 ++ + 3 files changed, 163 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts +index 26081a6e1866..20fdb4085d87 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77990-ebisu.dts +@@ -221,11 +221,27 @@ + }; + + sound_card: sound { +- compatible = "audio-graph-card"; ++ compatible = "audio-graph-scu-card"; + + label = "rcar-sound"; + +- dais = <&rsnd_port0>; ++ prefix = "ak4613"; ++ routing = "ak4613 Playback", "DAI0 Playback", ++ "DAI0 Capture", "ak4613 Capture", ++ "ak4613 Playback", "Playback0", ++ "ak4613 Playback", "Playback1", ++ "ak4613 Playback", "Playback2", ++ "ak4613 Playback", "Playback3", ++ "Capture0", "ak4613 Capture", ++ "Capture1", "ak4613 Capture", ++ "Capture2", "ak4613 Capture", ++ "Capture3", "ak4613 Capture"; ++ ++ dais = <&adsp_port0 ++ &adsp_port1 ++ &adsp_port2 ++ &adsp_port3 ++ &rsnd_port0>; + }; + + vbus0_usb2: regulator-vbus0-usb2 { +@@ -501,8 +517,27 @@ + asahi-kasei,out5-single-end; + asahi-kasei,out6-single-end; + +- port { +- ak4613_endpoint: endpoint { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ak4613_endpoint0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&adsp_endpoint0>; ++ }; ++ ak4613_endpoint1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&adsp_endpoint1>; ++ }; ++ ak4613_endpoint2: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&adsp_endpoint2>; ++ }; ++ ak4613_endpoint3: endpoint@3 { ++ reg = <3>; ++ remote-endpoint = <&adsp_endpoint3>; ++ }; ++ ak4613_endpoint4: endpoint@4 { ++ reg = <4>; + remote-endpoint = <&rsnd_endpoint0>; + }; + }; +@@ -702,6 +737,45 @@ + status = "okay"; + }; + ++&rcar_adsp_sound { ++ status = "okay"; ++ /* Multiple DAI */ ++ #sound-dai-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adsp_port0: port@0 { ++ reg = <0>; ++ adsp_endpoint0: endpoint { ++ remote-endpoint = <&ak4613_endpoint0>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port1: port@1 { ++ reg = <1>; ++ adsp_endpoint1: endpoint { ++ remote-endpoint = <&ak4613_endpoint1>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port2: port@2 { ++ reg = <2>; ++ adsp_endpoint2: endpoint { ++ remote-endpoint = <&ak4613_endpoint2>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port3: port@3 { ++ reg = <3>; ++ adsp_endpoint3: endpoint { ++ remote-endpoint = <&ak4613_endpoint3>; ++ dai-format = "left_j"; ++ }; ++ }; ++ }; ++}; ++ + &rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; +@@ -737,7 +811,7 @@ + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { +- remote-endpoint = <&ak4613_endpoint>; ++ remote-endpoint = <&ak4613_endpoint4>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; +diff --git a/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts b/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts +index 087d5533f3db..61e18309c4a4 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts ++++ b/arch/arm64/boot/dts/renesas/r8a77990-es10-ebisu.dts +@@ -221,11 +221,27 @@ + }; + + sound_card: sound { +- compatible = "audio-graph-card"; ++ compatible = "audio-graph-scu-card"; + + label = "rcar-sound"; + +- dais = <&rsnd_port0>; ++ prefix = "ak4613"; ++ routing = "ak4613 Playback", "DAI0 Playback", ++ "DAI0 Capture", "ak4613 Capture", ++ "ak4613 Playback", "Playback0", ++ "ak4613 Playback", "Playback1", ++ "ak4613 Playback", "Playback2", ++ "ak4613 Playback", "Playback3", ++ "Capture0", "ak4613 Capture", ++ "Capture1", "ak4613 Capture", ++ "Capture2", "ak4613 Capture", ++ "Capture3", "ak4613 Capture"; ++ ++ dais = <&adsp_port0 ++ &adsp_port1 ++ &adsp_port2 ++ &adsp_port3 ++ &rsnd_port0>; + }; + + vbus0_usb2: regulator-vbus0-usb2 { +@@ -501,8 +517,27 @@ + asahi-kasei,out5-single-end; + asahi-kasei,out6-single-end; + +- port { +- ak4613_endpoint: endpoint { ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ak4613_endpoint0: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&adsp_endpoint0>; ++ }; ++ ak4613_endpoint1: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&adsp_endpoint1>; ++ }; ++ ak4613_endpoint2: endpoint@2 { ++ reg = <2>; ++ remote-endpoint = <&adsp_endpoint2>; ++ }; ++ ak4613_endpoint3: endpoint@3 { ++ reg = <3>; ++ remote-endpoint = <&adsp_endpoint3>; ++ }; ++ ak4613_endpoint4: endpoint@4 { ++ reg = <4>; + remote-endpoint = <&rsnd_endpoint0>; + }; + }; +@@ -702,6 +737,45 @@ + status = "okay"; + }; + ++&rcar_adsp_sound { ++ status = "okay"; ++ /* Multiple DAI */ ++ #sound-dai-cells = <1>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adsp_port0: port@0 { ++ reg = <0>; ++ adsp_endpoint0: endpoint { ++ remote-endpoint = <&ak4613_endpoint0>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port1: port@1 { ++ reg = <1>; ++ adsp_endpoint1: endpoint { ++ remote-endpoint = <&ak4613_endpoint1>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port2: port@2 { ++ reg = <2>; ++ adsp_endpoint2: endpoint { ++ remote-endpoint = <&ak4613_endpoint2>; ++ dai-format = "left_j"; ++ }; ++ }; ++ adsp_port3: port@3 { ++ reg = <3>; ++ adsp_endpoint3: endpoint { ++ remote-endpoint = <&ak4613_endpoint3>; ++ dai-format = "left_j"; ++ }; ++ }; ++ }; ++}; ++ + &rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; +@@ -737,7 +811,7 @@ + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { +- remote-endpoint = <&ak4613_endpoint>; ++ remote-endpoint = <&ak4613_endpoint4>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; +diff --git a/arch/arm64/boot/dts/renesas/r8a77990.dtsi b/arch/arm64/boot/dts/renesas/r8a77990.dtsi +index bd4d71e2b93e..845399adcbdb 100644 +--- a/arch/arm64/boot/dts/renesas/r8a77990.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a77990.dtsi +@@ -181,6 +181,11 @@ + method = "smc"; + }; + ++ rcar_adsp_sound: adsp_sound { ++ compatible = "renesas,rcar_adsp_sound_gen3"; ++ status = "disabled"; ++ }; ++ + /* External SCIF clock - to be overridden by boards that provide it */ + scif_clk: scif { + compatible = "fixed-clock"; +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch deleted file mode 100644 index 825e48f..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 7f000c3d136f9c2fb2087a1a1715a29e51140fc9 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:49:00 +0900 -Subject: [PATCH 5/6] arm64: dts: r8a7795-es1-salvator-x: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts -index 212e1f6ac5af..8e56c7b9d4bf 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-salvator-x.dts -@@ -117,11 +117,6 @@ - status = "okay"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1 /* HDMI0 */ -- &rsnd_port2>; /* HDMI1 */ --}; - - &hdmi0 { - status = "okay"; --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch new file mode 100644 index 0000000..f1a9f30 --- /dev/null +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-ADSP-remove-HDMI-support-from-rcar-sound.patch @@ -0,0 +1,82 @@ +From 9ad46b0976a91a5de41ab62c3d0fe923857a8dda Mon Sep 17 00:00:00 2001 +From: Nguyen Dang +Date: Tue, 6 Nov 2018 11:46:25 +0700 +Subject: [PATCH 6/6] ADSP: remove HDMI support from rcar-sound + +Signed-off-by: Nguyen Dang +--- + arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts | 6 ------ + arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts | 6 ------ + arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts | 5 ----- + arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts | 5 ----- + 4 files changed, 22 deletions(-) + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts +index 6928afbd8e06..b268afd7df85 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-x.dts +@@ -104,12 +104,6 @@ + status = "okay"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1 /* HDMI0 */ +- &rsnd_port2>; /* HDMI1 */ +-}; +- + &hdmi0 { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts +index 498f78875dbd..b6ec3036e9fd 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7795-salvator-xs.dts +@@ -114,12 +114,6 @@ + status = "okay"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1 /* HDMI0 */ +- &rsnd_port2>; /* HDMI1 */ +-}; +- + &hdmi0 { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts +index 02a938b416d0..2dba6e8e627a 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts +@@ -88,11 +88,6 @@ + "dclkin.0", "dclkin.1", "dclkin.2"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1>; /* HDMI0 */ +-}; +- + &hdmi0 { + status = "okay"; + +diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts +index bd66be180d6d..708bd634b5af 100644 +--- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts ++++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-xs.dts +@@ -88,11 +88,6 @@ + "dclkin.0", "dclkin.1", "dclkin.2"; + }; + +-&sound_card { +- dais = <&rsnd_port0 /* ak4613 */ +- &rsnd_port1>; /* HDMI0 */ +-}; +- + &hdmi0 { + status = "okay"; + +-- +2.19.1 + diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch deleted file mode 100644 index c312fea..0000000 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 867b08a686424cb771dbf83814b44e64e72cebe2 Mon Sep 17 00:00:00 2001 -From: Takeshi Kihara -Date: Fri, 19 Oct 2018 11:49:09 +0900 -Subject: [PATCH 6/6] arm64: dts: r8a7796-salvator-x: Remove-Sound-Card - -This Patch Removes Sound-Card - -Signed-off-by: Takeshi Kihara ---- - arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts -index 8e4f264ff8a3..9343244e8032 100644 ---- a/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts -+++ b/arch/arm64/boot/dts/renesas/r8a7796-salvator-x.dts -@@ -91,11 +91,6 @@ - "dclkin.0", "dclkin.1", "dclkin.2"; - }; - --&sound_card { -- dais = <&rsnd_port0 /* ak4613 */ -- &rsnd_port1>; /* HDMI0 */ --}; -- - &lvds0 { - ports { - port@1 { --- -2.19.0 - diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/defconfig b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/defconfig index a7df2be..dd59bb8 100644 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/defconfig +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/defconfig @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm64 4.14.70 Kernel Configuration +# Linux/arm64 4.14.75 Kernel Configuration # CONFIG_ARM64=y CONFIG_64BIT=y @@ -1308,7 +1308,6 @@ CONFIG_OF=y # CONFIG_OF_UNITTEST is not set CONFIG_OF_FLATTREE=y CONFIG_OF_EARLY_FLATTREE=y -CONFIG_OF_DYNAMIC=y CONFIG_OF_ADDRESS=y CONFIG_OF_ADDRESS_PCI=y CONFIG_OF_IRQ=y @@ -1317,8 +1316,7 @@ CONFIG_OF_MDIO=y CONFIG_OF_PCI=y CONFIG_OF_PCI_IRQ=y CONFIG_OF_RESERVED_MEM=y -CONFIG_OF_RESOLVE=y -CONFIG_OF_OVERLAY=y +# CONFIG_OF_OVERLAY is not set CONFIG_OF_NUMA=y # CONFIG_PARPORT is not set CONFIG_PNP=y @@ -5044,10 +5042,11 @@ CONFIG_TEGRA_IOMMU_SMMU=y # CONFIG_EXYNOS_IOMMU is not set CONFIG_IPMMU_VMSA=y CONFIG_IPMMU_VMSA_CTX_NUM=8 +CONFIG_IPMMU_VMSA_WHITELIST=y CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU_V3=y # CONFIG_MTK_IOMMU is not set -CONFIG_QCOM_IOMMU=y +# CONFIG_QCOM_IOMMU is not set # # Remoteproc drivers diff --git a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_4.14.bb b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_4.14.bb index 56edb1f..addda0a 100644 --- a/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_4.14.bb +++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas_4.14.bb @@ -9,13 +9,14 @@ require include/adsp-control.inc FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/:" COMPATIBLE_MACHINE = "salvator-x|h3ulcb|m3ulcb|ebisu" -RENESAS_BSP_URL = "git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas-bsp.git" -BRANCH = "v4.14.70-ltsi-rc1/rcar-3.8.0" -SRCREV = "52f8a317698424fe3a4ba7f88d2b87fc6bf6591d" +RENESAS_BSP_URL = " \ + git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas-bsp.git" +BRANCH = "v4.14.75-ltsi/rcar-3.9.2" +SRCREV = "a5266d298124874c2c06b8b13d073f6ecc2ee355" SRC_URI = "${RENESAS_BSP_URL};protocol=git;nocheckout=1;branch=${BRANCH}" -LINUX_VERSION ?= "4.14.70" +LINUX_VERSION ?= "4.14.75" PV = "${LINUX_VERSION}+git${SRCPV}" PR = "r1" @@ -40,22 +41,14 @@ SRC_URI_append = " \ ${@base_conditional("USE_CAS", "1", " file://capacity_aware_migration_strategy.cfg", "",d)} \ " -# Device tree patches -SRC_URI_append = " \ - file://0001-arm64-dts-salvator-common-Rcar-Sound.patch \ - file://0002-arm64-dts-r8a7796-salvator-xs-Remove-Sound-Card.patch \ - file://0003-arm64-dts-r8a7795-salvator-x-Remove-Sound-Card.patch \ - file://0004-arm64-dts-r8a7795-salvator-xs-Remove-Sound-Card.patch \ - file://0005-arm64-dts-r8a7795-es1-salvator-x-Remove-Sound-Card.patch \ - file://0006-arm64-dts-r8a7796-salvator-x-Remove-Sound-Card.patch \ -" - # Add ADSP ALSA driver SUPPORT_ADSP_ASOC = " \ - file://0001-Add-build-for-ADSP-sound-driver.patch \ - file://0002-Add-document-file-for-ADSP-sound-driver.patch \ - file://0003-Add-ADSP-sound-driver-source.patch \ - file://0004-Update-device-tree-for-ADSP-sound-driver.patch \ + file://0001-ADSP-add-document-for-compatible-string-renesas-rcar.patch \ + file://0002-ADSP-add-ADSP-sound-driver-source.patch \ + file://0003-ADSP-add-build-for-ADSP-sound-driver.patch \ + file://0004-ADSP-integrate-ADSP-sound-for-H3-M3-M3N-board.patch \ + file://0005-ADSP-integrate-ADSP-sound-for-E3-board.patch \ + file://0006-ADSP-remove-HDMI-support-from-rcar-sound.patch \ file://adsp.cfg \ " -- cgit 1.2.3-korg