aboutsummaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3/recipes-kernel/linux
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3/recipes-kernel/linux')
-rw-r--r--meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-Add-build-for-ADSP-sound-driver.patch31
-rw-r--r--meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-Add-document-file-for-ADSP-sound-driver.patch27
-rw-r--r--meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch7172
-rw-r--r--meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-Update-device-tree-for-ADSP-sound-driver.patch249
-rw-r--r--meta-rcar-gen3/recipes-kernel/linux/linux-renesas/adsp.cfg3
-rw-r--r--meta-rcar-gen3/recipes-kernel/linux/linux-renesas_4.14.bb14
6 files changed, 7496 insertions, 0 deletions
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
new file mode 100644
index 0000000..508600d
--- /dev/null
+++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-Add-build-for-ADSP-sound-driver.patch
@@ -0,0 +1,31 @@
+From 4e7d2e7b5737d9a7ffbd59ad260e6b86b2e48691 Mon Sep 17 00:00:00 2001
+From: tienphitran <tien.tran.uw@renesas.com>
+Date: Mon, 15 Oct 2018 17:57:56 +0700
+Subject: [PATCH 1/4] Add build for ADSP sound driver
+
+Signed-off-by: tienphitran <tien.tran.uw@renesas.com>
+
+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/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
new file mode 100644
index 0000000..f4305ad
--- /dev/null
+++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0002-Add-document-file-for-ADSP-sound-driver.patch
@@ -0,0 +1,27 @@
+From 35f2052da7ebf049daaf85ff8c8eb8d31617c80f Mon Sep 17 00:00:00 2001
+From: tienphitran <tien.tran.uw@renesas.com>
+Date: Mon, 15 Oct 2018 17:59:33 +0700
+Subject: [PATCH 2/4] Add document file for ADSP sound driver
+
+Signed-off-by: tienphitran <tien.tran.uw@renesas.com>
+
+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/0003-Add-ADSP-sound-driver-source.patch b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch
new file mode 100644
index 0000000..d25c2b1
--- /dev/null
+++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0003-Add-ADSP-sound-driver-source.patch
@@ -0,0 +1,7172 @@
+From 1705856b55d8f93a22843a9577eadac4212342e7 Mon Sep 17 00:00:00 2001
+From: tienphitran <tien.tran.uw@renesas.com>
+Date: Mon, 15 Oct 2018 18:00:42 +0700
+Subject: [PATCH 3/4] Add ADSP sound driver source
+
+Signed-off-by: tienphitran <tien.tran.uw@renesas.com>
+
+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 <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/sched/signal.h>
++#include <linux/delay.h>
++#include <sound/core.h>
++#include <sound/control.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/pcm-indirect.h>
++#include <linux/time.h>
++
++#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 <linux/slab.h>
++#include <linux/kthread.h>
++#include <linux/wait.h>
++
++#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 = &params->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 = &params->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 <adsp_drv/xf-adsp-drv-ext.h>
++
++#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/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
new file mode 100644
index 0000000..2586dac
--- /dev/null
+++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0004-Update-device-tree-for-ADSP-sound-driver.patch
@@ -0,0 +1,249 @@
+From 81528aacc64df60f2471873deca3f1092d47b6ae Mon Sep 17 00:00:00 2001
+From: tienphitran <tien.tran.uw@renesas.com>
+Date: Mon, 15 Oct 2018 17:56:29 +0700
+Subject: [PATCH 4/4] Update device tree for ADSP sound driver
+
+Signed-off-by: tienphitran <tien.tran.uw@renesas.com>
+
+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/adsp.cfg b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/adsp.cfg
new file mode 100644
index 0000000..f19e8d2
--- /dev/null
+++ b/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/adsp.cfg
@@ -0,0 +1,3 @@
+CONFIG_SND_SOC_ADSP=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+
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 208607a..56edb1f 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
@@ -4,6 +4,7 @@ require include/avb-control.inc
require include/iccom-control.inc
require recipes-kernel/linux/linux-yocto.inc
require include/cas-control.inc
+require include/adsp-control.inc
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}/:"
COMPATIBLE_MACHINE = "salvator-x|h3ulcb|m3ulcb|ebisu"
@@ -49,6 +50,19 @@ SRC_URI_append = " \
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://adsp.cfg \
+"
+
+SRC_URI_append = " \
+ ${@base_conditional("USE_ADSP", "1", "${SUPPORT_ADSP_ASOC}", "", d)} \
+"
+
# Install USB3.0 firmware to rootfs
USB3_FIRMWARE_V2 = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/r8a779x_usb3_v2.dlmem;md5sum=645db7e9056029efa15f158e51cc8a11"
USB3_FIRMWARE_V3 = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/r8a779x_usb3_v3.dlmem;md5sum=687d5d42f38f9850f8d5a6071dca3109"